[rs] Use u8 slices for buffer mapping

This commit is contained in:
Jacob Greenfield
2019-11-21 17:32:01 -05:00
parent 7c548b5edf
commit ae18c20fa2
2 changed files with 39 additions and 80 deletions

View File

@@ -37,7 +37,6 @@ rev = "73b33ea76e2f91b3114aa7640b1d60518d39f915"
[dependencies]
arrayvec = "0.5"
raw-window-handle = "0.3"
zerocopy = "0.2"
[dev-dependencies]
cgmath = "0.17"
@@ -46,3 +45,4 @@ glsl-to-spirv = "0.1"
log = "0.4"
png = "0.15"
winit = "0.20.0-alpha4"
zerocopy = "0.2"

View File

@@ -1,9 +1,7 @@
//! A cross-platform graphics and compute library based on WebGPU.
use arrayvec::ArrayVec;
use zerocopy::{AsBytes, FromBytes, LayoutVerified};
use std::convert::TryFrom;
use std::ffi::CString;
use std::ops::Range;
use std::ptr;
@@ -493,27 +491,12 @@ impl<'a> TextureCopyView<'a> {
}
/// A buffer being created, mapped in host memory.
pub struct CreateBufferMapped<'a, T> {
pub struct CreateBufferMapped<'a> {
id: wgc::id::BufferId,
pub data: &'a mut [T],
pub data: &'a mut [u8],
}
impl<'a, T> CreateBufferMapped<'a, T>
where
T: Copy,
{
/// Copies a slice into the mapped buffer and unmaps it, returning a [`Buffer`].
///
/// `slice` and `self.data` must have the same length.
///
/// # Panics
///
/// Panics if the slices have different lengths.
pub fn fill_from_slice(self, slice: &[T]) -> Buffer {
self.data.copy_from_slice(slice);
self.finish()
}
impl CreateBufferMapped<'_> {
/// Unmaps the buffer from host memory and returns a [`Buffer`].
pub fn finish(self) -> Buffer {
wgn::wgpu_buffer_unmap(self.id);
@@ -813,32 +796,32 @@ impl Device {
/// Creates a new buffer and maps it into host-visible memory.
///
/// This returns a [`CreateBufferMapped<T>`], which exposes a `&mut [T]`. The actual [`Buffer`]
/// This returns a [`CreateBufferMapped`], which exposes a `&mut [u8]`. The actual [`Buffer`]
/// will not be created until calling [`CreateBufferMapped::finish`].
pub fn create_buffer_mapped<'a, T>(
&'a self,
count: usize,
usage: BufferUsage,
) -> CreateBufferMapped<'a, T>
where
T: 'static + Copy + AsBytes + FromBytes,
{
let type_size = std::mem::size_of::<T>() as BufferAddress;
assert_ne!(type_size, 0);
pub fn create_buffer_mapped(&self, size: usize, usage: BufferUsage) -> CreateBufferMapped<'_> {
assert_ne!(size, 0);
let desc = BufferDescriptor {
size: (type_size * count as BufferAddress).max(1),
size: size as BufferAddress,
usage,
};
let mut ptr: *mut u8 = std::ptr::null_mut();
let id = wgn::wgpu_device_create_buffer_mapped(self.id, &desc, &mut ptr as *mut *mut u8);
let data = unsafe { std::slice::from_raw_parts_mut(ptr as *mut T, count) };
let data = unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, size) };
CreateBufferMapped { id, data }
}
/// Creates a new buffer, maps it into host-visible memory, copies data from the given slice,
/// and finally unmaps it, returning a [`Buffer`].
pub fn create_buffer_with_data(&self, data: &[u8], usage: BufferUsage) -> Buffer {
let mapped = self.create_buffer_mapped(data.len(), usage);
mapped.data.copy_from_slice(data);
mapped.finish()
}
/// Creates a new [`Texture`].
///
/// `desc` specifies the general format of the texture.
@@ -888,50 +871,39 @@ impl<T> Drop for BufferAsyncMapping<T> {
}
}
struct BufferMapReadAsyncUserData<T, F>
struct BufferMapReadAsyncUserData<F>
where
T: FromBytes,
F: FnOnce(BufferMapAsyncResult<&[T]>),
F: FnOnce(BufferMapAsyncResult<&[u8]>),
{
size: BufferAddress,
size: usize,
callback: F,
buffer_id: wgc::id::BufferId,
phantom: std::marker::PhantomData<T>,
}
struct BufferMapWriteAsyncUserData<T, F>
struct BufferMapWriteAsyncUserData<F>
where
T: AsBytes + FromBytes,
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
F: FnOnce(BufferMapAsyncResult<&mut [u8]>),
{
size: BufferAddress,
size: usize,
callback: F,
buffer_id: wgc::id::BufferId,
phantom: std::marker::PhantomData<T>,
}
impl Buffer {
pub fn map_read_async<T, F>(&self, start: BufferAddress, count: usize, callback: F)
pub fn map_read_async<F>(&self, start: BufferAddress, size: usize, callback: F)
where
T: 'static + FromBytes,
F: FnOnce(BufferMapAsyncResult<&[T]>),
F: FnOnce(BufferMapAsyncResult<&[u8]>),
{
extern "C" fn buffer_map_read_callback_wrapper<T, F>(
extern "C" fn buffer_map_read_callback_wrapper<F>(
status: BufferMapAsyncStatus,
data: *const u8,
user_data: *mut u8,
) where
T: FromBytes,
F: FnOnce(BufferMapAsyncResult<&[T]>),
F: FnOnce(BufferMapAsyncResult<&[u8]>),
{
let user_data =
unsafe { Box::from_raw(user_data as *mut BufferMapReadAsyncUserData<T, F>) };
let data: &[u8] = unsafe {
slice::from_raw_parts(data as *const u8, usize::try_from(user_data.size).unwrap())
};
let data = LayoutVerified::new_slice(data)
.expect("could not interpret bytes as &[T]")
.into_slice();
unsafe { Box::from_raw(user_data as *mut BufferMapReadAsyncUserData<F>) };
let data: &[u8] = unsafe { slice::from_raw_parts(data as *const u8, user_data.size) };
match status {
BufferMapAsyncStatus::Success => (user_data.callback)(Ok(BufferAsyncMapping {
data,
@@ -941,44 +913,34 @@ impl Buffer {
}
}
let size = (count * std::mem::size_of::<T>()) as BufferAddress;
let user_data = Box::new(BufferMapReadAsyncUserData {
size,
callback,
buffer_id: self.id,
phantom: std::marker::PhantomData,
});
wgn::wgpu_buffer_map_read_async(
self.id,
start,
size,
buffer_map_read_callback_wrapper::<T, F>,
size as BufferAddress,
buffer_map_read_callback_wrapper::<F>,
Box::into_raw(user_data) as *mut u8,
);
}
pub fn map_write_async<T, F>(&self, start: BufferAddress, count: usize, callback: F)
pub fn map_write_async<F>(&self, start: BufferAddress, size: usize, callback: F)
where
T: 'static + AsBytes + FromBytes,
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
F: FnOnce(BufferMapAsyncResult<&mut [u8]>),
{
extern "C" fn buffer_map_write_callback_wrapper<T, F>(
extern "C" fn buffer_map_write_callback_wrapper<F>(
status: BufferMapAsyncStatus,
data: *mut u8,
user_data: *mut u8,
) where
T: AsBytes + FromBytes,
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
F: FnOnce(BufferMapAsyncResult<&mut [u8]>),
{
let user_data =
unsafe { Box::from_raw(user_data as *mut BufferMapWriteAsyncUserData<T, F>) };
let data = unsafe {
slice::from_raw_parts_mut(data as *mut u8, usize::try_from(user_data.size).unwrap())
};
let data = LayoutVerified::new_slice(data)
.expect("could not interpret bytes as &mut [T]")
.into_mut_slice();
unsafe { Box::from_raw(user_data as *mut BufferMapWriteAsyncUserData<F>) };
let data = unsafe { slice::from_raw_parts_mut(data as *mut u8, user_data.size) };
match status {
BufferMapAsyncStatus::Success => (user_data.callback)(Ok(BufferAsyncMapping {
data,
@@ -988,19 +950,16 @@ impl Buffer {
}
}
let size = (count * std::mem::size_of::<T>()) as BufferAddress;
let user_data = Box::new(BufferMapWriteAsyncUserData {
size,
callback,
buffer_id: self.id,
phantom: std::marker::PhantomData,
});
wgn::wgpu_buffer_map_write_async(
self.id,
start,
size,
buffer_map_write_callback_wrapper::<T, F>,
size as BufferAddress,
buffer_map_write_callback_wrapper::<F>,
Box::into_raw(user_data) as *mut u8,
);
}