use crate::Error;
use j2k_metal_support::{MetalImageLayout, ResidentMetalImage, SubmittedMetalImages};
use metal::{BlitCommandEncoderRef, Buffer, CommandBuffer, ComputeCommandEncoderRef, DeviceRef};
pub(crate) fn support_error(
context: &'static str,
source: j2k_metal_support::MetalSupportError,
) -> Error {
Error::Encode {
message: format!("{context}: {source}"),
}
}
pub(crate) fn device_tile_image(
tile: &wsi_rs::output::metal::MetalDeviceTile,
) -> Result<&ResidentMetalImage, Error> {
tile.validated_resident_image()
.map_err(|source| Error::Unsupported {
reason: format!("Metal device tile is not a validated resident image: {source}"),
})
}
pub(crate) 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,
);
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn copy_resident_rows(
encoder: &BlitCommandEncoderRef,
image: &ResidentMetalImage,
source_offset: u64,
source_pitch: u64,
destination: &Buffer,
destination_offset: u64,
destination_pitch: u64,
row_bytes: u64,
height: u64,
) {
let source = unsafe { image.raw_buffer() };
for row in 0..height {
encoder.copy_from_buffer(
source,
source_offset + row * source_pitch,
destination,
destination_offset + row * destination_pitch,
row_bytes,
);
}
}
pub(crate) fn submit_images(
device: &DeviceRef,
command_buffer: CommandBuffer,
outputs: Vec<(Buffer, MetalImageLayout)>,
inputs: Vec<ResidentMetalImage>,
) -> Result<SubmittedMetalImages, Error> {
unsafe { SubmittedMetalImages::from_uncommitted(device, command_buffer, outputs, inputs) }
.map_err(|source| support_error("Metal image submission", source))
}
#[cfg(test)]
pub(crate) fn test_tile_from_shared_bytes(
device: &DeviceRef,
bytes: &[u8],
width: u32,
height: u32,
format: j2k_core::PixelFormat,
) -> wsi_rs::output::metal::MetalDeviceTile {
let pitch_bytes = width as usize * format.bytes_per_pixel();
let buffer = j2k_metal_support::checked_shared_buffer_with_slice(device, bytes)
.expect("test Metal upload");
test_tile_from_completed_buffer(
buffer,
0,
width,
height,
pitch_bytes,
wsi_rs::PixelFormat::try_from(format).expect("supported test Metal pixel format"),
)
}
#[cfg(test)]
pub(crate) fn test_tile_from_completed_buffer(
buffer: Buffer,
byte_offset: usize,
width: u32,
height: u32,
pitch_bytes: usize,
format: wsi_rs::PixelFormat,
) -> wsi_rs::output::metal::MetalDeviceTile {
unsafe {
wsi_rs::output::metal::MetalDeviceTile::from_completed_buffer(
buffer,
byte_offset,
width,
height,
pitch_bytes,
format,
)
}
.expect("test resident Metal tile")
}
#[cfg(test)]
pub(crate) fn test_tile_bytes(tile: &wsi_rs::output::metal::MetalDeviceTile) -> Vec<u8> {
let image = device_tile_image(tile).expect("test resident Metal tile");
unsafe {
j2k_metal_support::checked_buffer_read_vec::<u8>(
image.raw_buffer(),
image.byte_offset(),
image.byte_len(),
)
}
.expect("test resident Metal readback")
}
#[cfg(test)]
pub(crate) fn test_u64_buffer_values(buffer: &Buffer, len: usize) -> Vec<u64> {
unsafe { j2k_metal_support::checked_buffer_read_vec::<u64>(buffer, 0, len) }
.expect("test Metal u64 readback")
}