use crate::metal::RafxDeviceContextMetal;
use crate::{RafxBufferDef, RafxMemoryUsage, RafxResourceType, RafxResult};
#[derive(Debug)]
pub struct RafxBufferMetal {
device_context: RafxDeviceContextMetal,
buffer_def: RafxBufferDef,
buffer: metal_rs::Buffer,
}
unsafe impl Send for RafxBufferMetal {}
unsafe impl Sync for RafxBufferMetal {}
impl RafxBufferMetal {
pub fn buffer_def(&self) -> &RafxBufferDef {
&self.buffer_def
}
pub fn set_debug_name(
&self,
name: impl AsRef<str>,
) {
if self.device_context.device_info().debug_names_enabled {
self.metal_buffer().set_label(name.as_ref())
}
}
pub fn metal_buffer(&self) -> &metal_rs::BufferRef {
self.buffer.as_ref()
}
pub fn map_buffer(&self) -> RafxResult<*mut u8> {
if self.buffer_def.memory_usage == RafxMemoryUsage::GpuOnly {
return Err("Cannot map GPU-only buffer")?;
}
Ok(self.buffer.contents() as *mut u8)
}
pub fn unmap_buffer(&self) -> RafxResult<()> {
Ok(())
}
pub fn mapped_memory(&self) -> Option<*mut u8> {
Some(self.buffer.contents() as *mut u8)
}
pub fn copy_to_host_visible_buffer<T: Copy>(
&self,
data: &[T],
) -> RafxResult<()> {
self.copy_to_host_visible_buffer_with_offset(data, 0)
}
pub fn copy_to_host_visible_buffer_with_offset<T: Copy>(
&self,
data: &[T],
buffer_byte_offset: u64,
) -> RafxResult<()> {
let data_size_in_bytes = rafx_base::memory::slice_size_in_bytes(data) as u64;
assert!(buffer_byte_offset + data_size_in_bytes <= self.buffer_def.size);
let src = data.as_ptr() as *const u8;
let required_alignment = std::mem::align_of::<T>();
unsafe {
let dst = self.map_buffer()?.add(buffer_byte_offset as usize);
assert_eq!(((dst as usize) % required_alignment), 0);
std::ptr::copy_nonoverlapping(src, dst, data_size_in_bytes as usize);
}
self.unmap_buffer()?;
Ok(())
}
pub fn new(
device_context: &RafxDeviceContextMetal,
buffer_def: &RafxBufferDef,
) -> RafxResult<Self> {
buffer_def.verify();
let mut allocation_size = buffer_def.size;
if buffer_def
.resource_type
.intersects(RafxResourceType::UNIFORM_BUFFER)
{
allocation_size = rafx_base::memory::round_size_up_to_alignment_u64(
buffer_def.size,
device_context
.device_info()
.min_uniform_buffer_offset_alignment as u64,
)
}
assert_ne!(0, allocation_size);
let buffer = device_context.device().new_buffer(
allocation_size,
buffer_def.memory_usage.mtl_resource_options(),
);
Ok(RafxBufferMetal {
device_context: device_context.clone(),
buffer_def: buffer_def.clone(),
buffer,
})
}
}