use super::buffer_descriptor::BufferDescriptor;
use super::metal_vertex_buffer::{MetalCommandBuffer, MetalDevice, MetalVertexBuffer};
use crate::far::StencilTable;
use opensubdiv_petite_sys as sys;
use crate::Error;
use std::marker::PhantomData;
use std::ptr::NonNull;
type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug)]
pub struct MetalComputeEncoder<'a> {
ptr: NonNull<std::ffi::c_void>,
_marker: PhantomData<&'a std::ffi::c_void>,
}
impl<'a> MetalComputeEncoder<'a> {
pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Option<MetalComputeEncoder<'a>> {
NonNull::new(ptr).map(|ptr| MetalComputeEncoder {
ptr,
_marker: PhantomData,
})
}
pub(crate) fn as_ptr(&self) -> *mut std::ffi::c_void {
self.ptr.as_ptr()
}
}
pub fn evaluate_stencils(
src_buffer: &MetalVertexBuffer,
src_desc: BufferDescriptor,
dst_buffer: &mut MetalVertexBuffer,
dst_desc: BufferDescriptor,
stencil_table: &MetalStencilTable,
command_buffer: &MetalCommandBuffer,
compute_encoder: &MetalComputeEncoder,
) -> Result<()> {
unsafe {
if sys::osd::MTLComputeEvaluator_EvalStencils(
src_buffer.0,
src_desc.0,
dst_buffer.0,
dst_desc.0,
stencil_table.ptr,
command_buffer.as_ptr() as *const _,
compute_encoder.as_ptr() as *const _,
) {
Ok(())
} else {
Err(Error::EvalStencilsFailed)
}
}
}
pub struct MetalStencilTable<'a> {
pub(crate) ptr: sys::osd::MetalStencilTablePtr,
st: std::marker::PhantomData<&'a StencilTable>,
}
impl<'a> MetalStencilTable<'a> {
pub fn new(st: &'a StencilTable, device: &MetalDevice) -> Result<MetalStencilTable<'a>> {
let ptr = unsafe { sys::osd::MTLStencilTable_Create(st.0, device.as_ptr() as *const _) };
if ptr.is_null() {
return Err(Error::GpuBackend(
"Could not create MetalStencilTable".to_string(),
));
}
Ok(MetalStencilTable {
ptr,
st: std::marker::PhantomData,
})
}
}
impl Drop for MetalStencilTable<'_> {
fn drop(&mut self) {
unsafe {
sys::osd::MTLStencilTable_destroy(self.ptr);
}
}
}