use crate::{Error, Result};
use opensubdiv_petite_sys as sys;
use std::convert::TryInto;
use std::marker::PhantomData;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct OpenClContext<'a> {
ptr: NonNull<std::ffi::c_void>,
_marker: PhantomData<&'a std::ffi::c_void>,
}
impl<'a> OpenClContext<'a> {
pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Option<OpenClContext<'a>> {
NonNull::new(ptr).map(|ptr| OpenClContext {
ptr,
_marker: PhantomData,
})
}
pub(crate) fn as_ptr(&self) -> *mut std::ffi::c_void {
self.ptr.as_ptr()
}
}
#[derive(Debug)]
pub struct OpenClCommandQueue<'a> {
ptr: NonNull<std::ffi::c_void>,
_marker: PhantomData<&'a std::ffi::c_void>,
}
impl<'a> OpenClCommandQueue<'a> {
pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Option<OpenClCommandQueue<'a>> {
NonNull::new(ptr).map(|ptr| OpenClCommandQueue {
ptr,
_marker: PhantomData,
})
}
pub(crate) fn as_ptr(&self) -> *mut std::ffi::c_void {
self.ptr.as_ptr()
}
}
pub struct OpenClVertexBuffer(pub(crate) sys::osd::OpenCLVertexBufferPtr);
impl Drop for OpenClVertexBuffer {
#[inline]
fn drop(&mut self) {
unsafe { sys::osd::CLVertexBuffer_destroy(self.0) }
}
}
impl OpenClVertexBuffer {
#[inline]
pub fn new(
element_count: usize,
vertex_count: usize,
context: Option<&OpenClContext>,
) -> Result<OpenClVertexBuffer> {
let ptr = unsafe {
sys::osd::CLVertexBuffer_Create(
element_count
.try_into()
.map_err(|_| Error::InvalidBufferSize {
expected: element_count,
actual: i32::MAX as usize,
})?,
vertex_count
.try_into()
.map_err(|_| Error::InvalidBufferSize {
expected: vertex_count,
actual: i32::MAX as usize,
})?,
context.map_or(std::ptr::null(), |ctx| ctx.as_ptr() as *const _),
)
};
if ptr.is_null() {
return Err(Error::GpuBackend(
"CLVertexBuffer_Create returned null".to_string(),
));
}
Ok(OpenClVertexBuffer(ptr))
}
#[inline]
pub fn element_count(&self) -> usize {
unsafe { sys::osd::CLVertexBuffer_GetNumElements(self.0) as _ }
}
#[inline]
pub fn vertex_count(&self) -> usize {
unsafe { sys::osd::CLVertexBuffer_GetNumVertices(self.0) as _ }
}
#[inline]
pub fn bind_cl_buffer(&self, command_queue: &OpenClCommandQueue) -> *const std::ffi::c_void {
unsafe { sys::osd::CLVertexBuffer_BindCLBuffer(self.0, command_queue.as_ptr() as *const _) }
}
#[inline]
pub fn update_data(
&mut self,
src: &[f32],
start_vertex: usize,
vertex_count: usize,
command_queue: &OpenClCommandQueue,
) -> Result<()> {
let element_count = self.element_count();
if start_vertex * element_count > src.len() {
return Err(Error::InvalidBufferSize {
expected: start_vertex * element_count,
actual: src.len(),
});
}
if vertex_count * element_count > src.len() {
return Err(Error::InvalidBufferSize {
expected: vertex_count * element_count,
actual: src.len(),
});
}
unsafe {
sys::osd::CLVertexBuffer_UpdateData(
self.0,
src.as_ptr(),
start_vertex
.try_into()
.map_err(|_| Error::InvalidBufferSize {
expected: start_vertex,
actual: i32::MAX as usize,
})?,
vertex_count
.try_into()
.map_err(|_| Error::InvalidBufferSize {
expected: vertex_count,
actual: i32::MAX as usize,
})?,
command_queue.as_ptr() as *const _,
);
}
Ok(())
}
}