use super::{MetalDeviceStorage, MetalDeviceTile};
use crate::{error::WsiError, PixelFormat};
use j2k_metal_support::{MetalImageLayout, ResidentMetalImage, SubmittedMetalImages};
use metal::{Buffer, CommandBuffer, ComputeCommandEncoderRef, DeviceRef};
pub(super) fn support_error(
context: &'static str,
source: j2k_metal_support::MetalSupportError,
) -> WsiError {
WsiError::Codec {
codec: context,
source: Box::new(source),
}
}
pub(super) fn bind_resident_compute_input(
encoder: &ComputeCommandEncoderRef,
index: u64,
image: &ResidentMetalImage,
) {
encoder.set_buffer(
index,
Some(unsafe { image.raw_buffer() }),
image.byte_offset() as u64,
);
}
pub(super) fn submit_ycbcr_images(
device: &DeviceRef,
command_buffer: CommandBuffer,
outputs: Vec<(Buffer, MetalImageLayout)>,
inputs: Vec<ResidentMetalImage>,
) -> Result<SubmittedMetalImages, WsiError> {
unsafe { SubmittedMetalImages::from_uncommitted(device, command_buffer, outputs, inputs) }
.map_err(|source| support_error("metal-ycbcr", source))
}
#[cfg(test)]
pub(super) fn resident_test_image(
device: &DeviceRef,
bytes: &[u8],
dimensions: (u32, u32),
pitch_bytes: usize,
) -> ResidentMetalImage {
let buffer = j2k_metal_support::checked_shared_buffer_with_slice(device, bytes)
.expect("test Metal upload");
let layout = MetalImageLayout::new(0, dimensions, pitch_bytes, j2k_core::PixelFormat::Rgb8)
.expect("test resident layout");
unsafe { ResidentMetalImage::from_completed_buffer(buffer, layout) }
.expect("test resident image")
}
#[cfg(test)]
pub(super) fn resident_bytes(image: &ResidentMetalImage) -> Vec<u8> {
unsafe {
j2k_metal_support::checked_buffer_read_vec::<u8>(
image.raw_buffer(),
image.byte_offset(),
image.byte_len(),
)
}
.expect("resident test readback")
}
#[cfg(test)]
pub(super) fn u64_buffer_values(buffer: &Buffer, len: usize) -> Vec<u64> {
unsafe { j2k_metal_support::checked_buffer_read_vec::<u64>(buffer, 0, len) }
.expect("test u64 Metal readback")
}
impl MetalDeviceTile {
pub unsafe fn from_completed_buffer(
buffer: Buffer,
byte_offset: usize,
width: u32,
height: u32,
pitch_bytes: usize,
format: PixelFormat,
) -> Result<Self, WsiError> {
let j2k_format = j2k_core::PixelFormat::from(format);
let layout = MetalImageLayout::new(byte_offset, (width, height), pitch_bytes, j2k_format)
.map_err(|source| support_error("metal-tile-layout", source))?;
let image = unsafe { ResidentMetalImage::from_completed_buffer(buffer, layout) }
.map_err(|source| support_error("metal-tile-adoption", source))?;
Self::from_resident(image)
}
#[deprecated(note = "use from_completed_buffer or the safe from_resident constructor")]
pub unsafe fn from_buffer(
buffer: Buffer,
byte_offset: usize,
width: u32,
height: u32,
pitch_bytes: usize,
format: PixelFormat,
) -> Result<Self, WsiError> {
unsafe {
Self::from_completed_buffer(buffer, byte_offset, width, height, pitch_bytes, format)
}
}
#[allow(deprecated)]
pub unsafe fn raw_buffer(&self) -> (&Buffer, usize) {
match &self.storage {
MetalDeviceStorage::Resident { image } => {
(unsafe { image.raw_buffer() }, image.byte_offset())
}
MetalDeviceStorage::Buffer {
buffer,
byte_offset,
} => (buffer, *byte_offset),
}
}
}