Skip to content

Commit 524ff72

Browse files
committed
Typed mapping of buffers
Add a sprinkling of generics to remove the need for unsafe code to typecast slices resulting from mapping buffers.
1 parent 193eec6 commit 524ff72

File tree

3 files changed

+44
-33
lines changed

3 files changed

+44
-33
lines changed

examples/hello_compute_rust/main.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,9 @@ fn main() {
9696
encoder.copy_buffer_to_buffer(&storage_buffer, 0, &staging_buffer, 0, size);
9797

9898

99-
staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u8]>| {
99+
staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u32]>| {
100100
if let wgpu::BufferMapAsyncResult::Success(data) = result {
101-
let results = unsafe { ::std::slice::from_raw_parts(data.as_ptr() as *const u32, data.len() / std::mem::size_of::<u32>()) };
102-
println!("Times: {:?}", results);
101+
println!("Times: {:?}", data);
103102
}
104103

105104
staging_buffer.unmap();

gfx-examples/src/cube.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod framework;
22

33

4-
#[derive(Clone)]
4+
#[derive(Clone, Copy)]
55
struct Vertex {
66
pos: [f32; 4],
77
tex_coord: [f32; 2],
@@ -123,9 +123,9 @@ impl framework::Example for Example {
123123
});
124124

125125
//vertex_buf.set_sub_data(0, framework::cast_slice(&vertex_data));
126-
vertex_buf.map_write_async(0, vertex_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| {
126+
vertex_buf.map_write_async(0, vertex_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [Vertex]>| {
127127
if let wgpu::BufferMapAsyncResult::Success(data) = result {
128-
unsafe { std::ptr::copy_nonoverlapping(vertex_data.as_ptr() as *const u8, data.as_mut_ptr(), vertex_buffer_length) };
128+
data.copy_from_slice(&vertex_data);
129129
}
130130

131131
vertex_buf.unmap();
@@ -136,9 +136,9 @@ impl framework::Example for Example {
136136
usage: wgpu::BufferUsageFlags::INDEX | wgpu::BufferUsageFlags::TRANSFER_DST | wgpu::BufferUsageFlags::MAP_WRITE,
137137
});
138138
// index_buf.set_sub_data(0, framework::cast_slice(&index_data));
139-
index_buf.map_write_async(0, index_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| {
139+
index_buf.map_write_async(0, index_buffer_length as u32, |result: wgpu::BufferMapAsyncResult<&mut [u16]>| {
140140
if let wgpu::BufferMapAsyncResult::Success(data) = result {
141-
unsafe { std::ptr::copy_nonoverlapping(index_data.as_ptr() as *const u8, data.as_mut_ptr(), index_buffer_length) };
141+
data.copy_from_slice(&index_data);
142142
}
143143

144144
index_buf.unmap();
@@ -191,7 +191,7 @@ impl framework::Example for Example {
191191
// temp_buf.set_sub_data(0, &texels);
192192
temp_buf.map_write_async(0, texels.len() as u32, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| {
193193
if let wgpu::BufferMapAsyncResult::Success(data) = result {
194-
unsafe { std::ptr::copy_nonoverlapping(texels.as_ptr() as *const u8, data.as_mut_ptr(), texels.len()) };
194+
data.copy_from_slice(&texels);
195195
}
196196

197197
temp_buf.unmap();
@@ -237,9 +237,9 @@ impl framework::Example for Example {
237237
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
238238
let mx_ref: &[f32; 16] = mx_total.as_ref();
239239
// uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
240-
uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| {
240+
uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [f32]>| {
241241
if let wgpu::BufferMapAsyncResult::Success(data) = result {
242-
unsafe { std::ptr::copy_nonoverlapping(mx_ref.as_ptr() as *const u8, data.as_mut_ptr(), 64) };
242+
data.copy_from_slice(mx_ref);
243243
}
244244

245245
uniform_buf.unmap();
@@ -343,9 +343,9 @@ impl framework::Example for Example {
343343
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
344344
let mx_ref: &[f32; 16] = mx_total.as_ref();
345345
// self.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
346-
self.uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [u8]>| {
346+
self.uniform_buf.map_write_async(0, 64, |result: wgpu::BufferMapAsyncResult<&mut [f32]>| {
347347
if let wgpu::BufferMapAsyncResult::Success(data) = result {
348-
unsafe { std::ptr::copy_nonoverlapping(mx_ref.as_ptr() as *const u8, data.as_mut_ptr(), 64) };
348+
data.copy_from_slice(mx_ref);
349349
}
350350

351351
self.uniform_buf.unmap();

wgpu-rs/src/lib.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -465,53 +465,65 @@ pub enum BufferMapAsyncResult<T> {
465465
Error,
466466
}
467467

468-
struct BufferMapReadAsyncUserData<F: FnOnce(BufferMapAsyncResult<&[u8]>)> {
468+
struct BufferMapReadAsyncUserData<T,F>
469+
where F: FnOnce(BufferMapAsyncResult<&[T]>) {
469470
size: u32,
470471
callback: F,
472+
phantom: std::marker::PhantomData<T>,
471473
}
472474

473-
struct BufferMapWriteAsyncUserData<F: FnOnce(BufferMapAsyncResult<&mut [u8]>)> {
475+
struct BufferMapWriteAsyncUserData<T, F>
476+
where F: FnOnce(BufferMapAsyncResult<&mut [T]>) {
474477
size: u32,
475478
callback: F,
479+
phantom: std::marker::PhantomData<T>,
476480
}
477481

478482
impl Buffer {
479483
pub fn set_sub_data(&self, offset: u32, data: &[u8]) {
480484
wgn::wgpu_buffer_set_sub_data(self.id, offset, data.len() as u32, data.as_ptr());
481485
}
482486

483-
pub fn map_read_async<F>(&self, start: u32, size: u32, callback: F)
484-
where F: FnOnce(BufferMapAsyncResult<&[u8]>) {
485-
extern "C" fn buffer_map_read_callback_wrapper<F>(status: wgn::BufferMapAsyncStatus, data: *const u8, userdata: *mut u8)
486-
where F: FnOnce(BufferMapAsyncResult<&[u8]>) {
487-
let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapReadAsyncUserData<F>) };
488-
let data = unsafe { slice::from_raw_parts(data, userdata.size as usize) };
487+
pub fn map_read_async<T, F>(&self, start: u32, size: u32, callback: F)
488+
where T: 'static + Copy, F: FnOnce(BufferMapAsyncResult<&[T]>) {
489+
let type_size = std::mem::size_of::<T>() as u32;
490+
assert_ne!(type_size, 0);
491+
assert_eq!(size % type_size, 0);
492+
493+
extern "C" fn buffer_map_read_callback_wrapper<T, F>(status: wgn::BufferMapAsyncStatus, data: *const u8, userdata: *mut u8)
494+
where F: FnOnce(BufferMapAsyncResult<&[T]>) {
495+
let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapReadAsyncUserData<T, F>) };
496+
let data = unsafe { slice::from_raw_parts(data as *const T, userdata.size as usize / std::mem::size_of::<T>()) };
489497
if let wgn::BufferMapAsyncStatus::Success = status {
490-
(userdata.callback)(BufferMapAsyncResult::Success(data));
498+
(userdata.callback)(BufferMapAsyncResult::Success::<&[T]>(data));
491499
} else {
492500
(userdata.callback)(BufferMapAsyncResult::Error);
493501
}
494502
}
495503

496-
let userdata = Box::new(BufferMapReadAsyncUserData{size, callback});
497-
wgn::wgpu_buffer_map_read_async(self.id, start, size, buffer_map_read_callback_wrapper::<F>, Box::into_raw(userdata) as *mut u8);
504+
let userdata = Box::new(BufferMapReadAsyncUserData{size, callback, phantom: std::marker::PhantomData});
505+
wgn::wgpu_buffer_map_read_async(self.id, start, size, buffer_map_read_callback_wrapper::<T, F>, Box::into_raw(userdata) as *mut u8);
498506
}
499507

500-
pub fn map_write_async<F>(&self, start: u32, size: u32, callback: F)
501-
where F: FnOnce(BufferMapAsyncResult<&mut [u8]>) {
502-
extern "C" fn buffer_map_write_callback_wrapper<F>(status: wgn::BufferMapAsyncStatus, data: *mut u8, userdata: *mut u8)
503-
where F: FnOnce(BufferMapAsyncResult<&mut [u8]>) {
504-
let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapWriteAsyncUserData<F>) };
505-
let data = unsafe { slice::from_raw_parts_mut(data, userdata.size as usize) };
508+
pub fn map_write_async<T, F>(&self, start: u32, size: u32, callback: F)
509+
where T: 'static + Copy, F: FnOnce(BufferMapAsyncResult<&mut [T]>) {
510+
let type_size = std::mem::size_of::<T>() as u32;
511+
assert_ne!(type_size, 0);
512+
assert_eq!(size % type_size, 0);
513+
514+
extern "C" fn buffer_map_write_callback_wrapper<T, F>(status: wgn::BufferMapAsyncStatus, data: *mut u8, userdata: *mut u8)
515+
where F: FnOnce(BufferMapAsyncResult<&mut [T]>) {
516+
let userdata = unsafe { Box::from_raw(userdata as *mut BufferMapWriteAsyncUserData<T, F>) };
517+
let data = unsafe { slice::from_raw_parts_mut(data as *mut T, userdata.size as usize / std::mem::size_of::<T>()) };
506518
if let wgn::BufferMapAsyncStatus::Success = status {
507-
(userdata.callback)(BufferMapAsyncResult::Success(data));
519+
(userdata.callback)(BufferMapAsyncResult::Success::<&mut [T]>(data));
508520
} else {
509521
(userdata.callback)(BufferMapAsyncResult::Error);
510522
}
511523
}
512524

513-
let userdata = Box::new(BufferMapWriteAsyncUserData{size, callback});
514-
wgn::wgpu_buffer_map_write_async(self.id, start, size, buffer_map_write_callback_wrapper::<F>, Box::into_raw(userdata) as *mut u8);
525+
let userdata = Box::new(BufferMapWriteAsyncUserData{size, callback, phantom: std::marker::PhantomData});
526+
wgn::wgpu_buffer_map_write_async(self.id, start, size, buffer_map_write_callback_wrapper::<T, F>, Box::into_raw(userdata) as *mut u8);
515527
}
516528

517529
pub fn unmap(&self) {

0 commit comments

Comments
 (0)