From 524ff72fd3e0ecfc08ac55cf372b889abdbe43d6 Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Wed, 27 Feb 2019 08:27:30 -0800 Subject: [PATCH] Typed mapping of buffers Add a sprinkling of generics to remove the need for unsafe code to typecast slices resulting from mapping buffers. --- examples/hello_compute_rust/main.rs | 5 ++- gfx-examples/src/cube.rs | 20 +++++------ wgpu-rs/src/lib.rs | 52 ++++++++++++++++++----------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/examples/hello_compute_rust/main.rs b/examples/hello_compute_rust/main.rs index 4cad28a37d..7761828e38 100644 --- a/examples/hello_compute_rust/main.rs +++ b/examples/hello_compute_rust/main.rs @@ -96,10 +96,9 @@ fn main() { encoder.copy_buffer_to_buffer(&storage_buffer, 0, &staging_buffer, 0, size); - staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u8]>| { + staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u32]>| { if let wgpu::BufferMapAsyncResult::Success(data) = result { - let results = unsafe { ::std::slice::from_raw_parts(data.as_ptr() as *const u32, data.len() / std::mem::size_of::()) }; - println!("Times: {:?}", results); + println!("Times: {:?}", data); } staging_buffer.unmap(); diff --git a/gfx-examples/src/cube.rs b/gfx-examples/src/cube.rs index 2e675da697..cb52b0a83e 100644 --- a/gfx-examples/src/cube.rs +++ b/gfx-examples/src/cube.rs @@ -1,7 +1,7 @@ mod framework; -#[derive(Clone)] +#[derive(Clone, Copy)] struct Vertex { pos: [f32; 4], tex_coord: [f32; 2], @@ -123,9 +123,9 @@ impl framework::Example for Example { }); //vertex_buf.set_sub_data(0, framework::cast_slice(&vertex_data)); - vertex_buf.map_write_async(0, vertex_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| { + vertex_buf.map_write_async(0, vertex_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [Vertex]>| { if let wgpu::BufferMapAsyncResult::Success(data) = result { - unsafe { std::ptr::copy_nonoverlapping(vertex_data.as_ptr() as *const u8, data.as_mut_ptr(), vertex_buffer_length) }; + data.copy_from_slice(&vertex_data); } vertex_buf.unmap(); @@ -136,9 +136,9 @@ impl framework::Example for Example { usage: wgpu::BufferUsageFlags::INDEX | wgpu::BufferUsageFlags::TRANSFER_DST | wgpu::BufferUsageFlags::MAP_WRITE, }); // index_buf.set_sub_data(0, framework::cast_slice(&index_data)); - index_buf.map_write_async(0, index_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| { + index_buf.map_write_async(0, index_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [u16]>| { if let wgpu::BufferMapAsyncResult::Success(data) = result { - unsafe { std::ptr::copy_nonoverlapping(index_data.as_ptr() as *const u8, data.as_mut_ptr(), index_buffer_length) }; + data.copy_from_slice(&index_data); } index_buf.unmap(); @@ -191,7 +191,7 @@ impl framework::Example for Example { // temp_buf.set_sub_data(0, &texels); temp_buf.map_write_async(0, texels.len() as u32, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| { if let wgpu::BufferMapAsyncResult::Success(data) = result { - unsafe { std::ptr::copy_nonoverlapping(texels.as_ptr() as *const u8, data.as_mut_ptr(), texels.len()) }; + data.copy_from_slice(&texels); } temp_buf.unmap(); @@ -237,9 +237,9 @@ impl framework::Example for Example { let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); // uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..])); - uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| { + uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [f32]>| { if let wgpu::BufferMapAsyncResult::Success(data) = result { - unsafe { std::ptr::copy_nonoverlapping(mx_ref.as_ptr() as *const u8, data.as_mut_ptr(), 64) }; + data.copy_from_slice(mx_ref); } uniform_buf.unmap(); @@ -343,9 +343,9 @@ impl framework::Example for Example { let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); // self.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..])); - self.uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| { + self.uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [f32]>| { if let wgpu::BufferMapAsyncResult::Success(data) = result { - unsafe { std::ptr::copy_nonoverlapping(mx_ref.as_ptr() as *const u8, data.as_mut_ptr(), 64) }; + data.copy_from_slice(mx_ref); } self.uniform_buf.unmap(); diff --git a/wgpu-rs/src/lib.rs b/wgpu-rs/src/lib.rs index 3cac17352f..b01e99312d 100644 --- a/wgpu-rs/src/lib.rs +++ b/wgpu-rs/src/lib.rs @@ -465,14 +465,18 @@ pub enum BufferMapAsyncResult { Error, } -struct BufferMapReadAsyncUserData)> { +struct BufferMapReadAsyncUserData + where F: FnOnce(BufferMapAsyncResult<&[T]>) { size: u32, callback: F, + phantom: std::marker::PhantomData, } -struct BufferMapWriteAsyncUserData)> { +struct BufferMapWriteAsyncUserData + where F: FnOnce(BufferMapAsyncResult<&mut [T]>) { size: u32, callback: F, + phantom: std::marker::PhantomData, } impl Buffer { @@ -480,38 +484,46 @@ impl Buffer { wgn::wgpu_buffer_set_sub_data(self.id, offset, data.len() as u32, data.as_ptr()); } - pub fn map_read_async(&self, start: u32, size: u32, callback: F) - where F: FnOnce(BufferMapAsyncResult<&[u8]>) { - extern "C" fn buffer_map_read_callback_wrapper(status: wgn::BufferMapAsyncStatus, data: *const u8, userdata: *mut u8) - where F: FnOnce(BufferMapAsyncResult<&[u8]>) { - let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapReadAsyncUserData) }; - let data = unsafe { slice::from_raw_parts(data, userdata.size as usize) }; + pub fn map_read_async(&self, start: u32, size: u32, callback: F) + where T: 'static + Copy, F: FnOnce(BufferMapAsyncResult<&[T]>) { + let type_size = std::mem::size_of::() as u32; + assert_ne!(type_size, 0); + assert_eq!(size % type_size, 0); + + extern "C" fn buffer_map_read_callback_wrapper(status: wgn::BufferMapAsyncStatus, data: *const u8, userdata: *mut u8) + where F: FnOnce(BufferMapAsyncResult<&[T]>) { + let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapReadAsyncUserData) }; + let data = unsafe { slice::from_raw_parts(data as *const T, userdata.size as usize / std::mem::size_of::()) }; if let wgn::BufferMapAsyncStatus::Success = status { - (userdata.callback)(BufferMapAsyncResult::Success(data)); + (userdata.callback)(BufferMapAsyncResult::Success::<&[T]>(data)); } else { (userdata.callback)(BufferMapAsyncResult::Error); } } - let userdata = Box::new(BufferMapReadAsyncUserData{size, callback}); - wgn::wgpu_buffer_map_read_async(self.id, start, size, buffer_map_read_callback_wrapper::, Box::into_raw(userdata) as *mut u8); + let userdata = Box::new(BufferMapReadAsyncUserData{size, callback, phantom: std::marker::PhantomData}); + wgn::wgpu_buffer_map_read_async(self.id, start, size, buffer_map_read_callback_wrapper::, Box::into_raw(userdata) as *mut u8); } - pub fn map_write_async(&self, start: u32, size: u32, callback: F) - where F: FnOnce(BufferMapAsyncResult<&mut [u8]>) { - extern "C" fn buffer_map_write_callback_wrapper(status: wgn::BufferMapAsyncStatus, data: *mut u8, userdata: *mut u8) - where F: FnOnce(BufferMapAsyncResult<&mut [u8]>) { - let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapWriteAsyncUserData) }; - let data = unsafe { slice::from_raw_parts_mut(data, userdata.size as usize) }; + pub fn map_write_async(&self, start: u32, size: u32, callback: F) + where T: 'static + Copy, F: FnOnce(BufferMapAsyncResult<&mut [T]>) { + let type_size = std::mem::size_of::() as u32; + assert_ne!(type_size, 0); + assert_eq!(size % type_size, 0); + + extern "C" fn buffer_map_write_callback_wrapper(status: wgn::BufferMapAsyncStatus, data: *mut u8, userdata: *mut u8) + where F: FnOnce(BufferMapAsyncResult<&mut [T]>) { + let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapWriteAsyncUserData) }; + let data = unsafe { slice::from_raw_parts_mut(data as *mut T, userdata.size as usize / std::mem::size_of::()) }; if let wgn::BufferMapAsyncStatus::Success = status { - (userdata.callback)(BufferMapAsyncResult::Success(data)); + (userdata.callback)(BufferMapAsyncResult::Success::<&mut [T]>(data)); } else { (userdata.callback)(BufferMapAsyncResult::Error); } } - let userdata = Box::new(BufferMapWriteAsyncUserData{size, callback}); - wgn::wgpu_buffer_map_write_async(self.id, start, size, buffer_map_write_callback_wrapper::, Box::into_raw(userdata) as *mut u8); + let userdata = Box::new(BufferMapWriteAsyncUserData{size, callback, phantom: std::marker::PhantomData}); + wgn::wgpu_buffer_map_write_async(self.id, start, size, buffer_map_write_callback_wrapper::, Box::into_raw(userdata) as *mut u8); } pub fn unmap(&self) {