Error types for buffer mapping API

This commit is contained in:
Gabriel Majeri 2020-07-18 11:48:14 +03:00
parent 73b230871e
commit ec12d9547d
3 changed files with 54 additions and 38 deletions

View File

@ -390,7 +390,8 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
self.queue_write_buffer::<B>(device, id, range.start, &bin); self.queue_write_buffer::<B>(device, id, range.start, &bin);
} else { } else {
self.device_wait_for_buffer::<B>(device, id).unwrap(); self.device_wait_for_buffer::<B>(device, id).unwrap();
self.device_set_buffer_sub_data::<B>(device, id, range.start, &bin[..size]); self.device_set_buffer_sub_data::<B>(device, id, range.start, &bin[..size])
.unwrap();
} }
} }
A::WriteTexture { A::WriteTexture {

View File

@ -97,7 +97,8 @@ impl Test {
callback: map_callback, callback: map_callback,
user_data: ptr::null_mut(), user_data: ptr::null_mut(),
} }
)); ))
.unwrap();
} }
println!("\t\t\tWaiting..."); println!("\t\t\tWaiting...");
@ -107,7 +108,8 @@ impl Test {
println!("\t\t\tChecking {}", expect.name); println!("\t\t\tChecking {}", expect.name);
let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend); let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend);
let ptr = let ptr =
gfx_select!(device => global.buffer_get_mapped_range(buffer, expect.offset, None)); gfx_select!(device => global.buffer_get_mapped_range(buffer, expect.offset, None))
.unwrap();
let contents = unsafe { slice::from_raw_parts(ptr, expect.data.len()) }; let contents = unsafe { slice::from_raw_parts(ptr, expect.data.len()) };
assert_eq!(&expect.data[..], contents); assert_eq!(&expect.data[..], contents);
} }

View File

@ -9,7 +9,8 @@ use crate::{
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Hub, Input, Token}, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Hub, Input, Token},
id, pipeline, resource, span, swap_chain, id, pipeline, resource, span, swap_chain,
track::{BufferState, TextureState, TrackerSet}, track::{BufferState, TextureState, TrackerSet},
validation, FastHashMap, LifeGuard, MultiRefCount, PrivateFeatures, Stored, SubmissionIndex, validation::{self, check_buffer_usage, MissingBufferUsageError},
FastHashMap, LifeGuard, MultiRefCount, PrivateFeatures, Stored, SubmissionIndex,
MAX_BIND_GROUPS, MAX_BIND_GROUPS,
}; };
@ -125,7 +126,6 @@ impl RenderPassContext {
} }
} }
type BufferMapResult = Result<ptr::NonNull<u8>, hal::device::MapError>;
type BufferMapPendingCallback = (resource::BufferMapOperation, resource::BufferMapAsyncStatus); type BufferMapPendingCallback = (resource::BufferMapOperation, resource::BufferMapAsyncStatus);
fn map_buffer<B: hal::Backend>( fn map_buffer<B: hal::Backend>(
@ -133,7 +133,7 @@ fn map_buffer<B: hal::Backend>(
buffer: &mut resource::Buffer<B>, buffer: &mut resource::Buffer<B>,
sub_range: hal::buffer::SubRange, sub_range: hal::buffer::SubRange,
kind: HostMap, kind: HostMap,
) -> BufferMapResult { ) -> Result<ptr::NonNull<u8>, BufferMapError> {
let (ptr, segment, needs_sync) = { let (ptr, segment, needs_sync) = {
let segment = hal::memory::Segment { let segment = hal::memory::Segment {
offset: sub_range.offset, offset: sub_range.offset,
@ -783,7 +783,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
buffer_id: id::BufferId, buffer_id: id::BufferId,
offset: BufferAddress, offset: BufferAddress,
data: &[u8], data: &[u8],
) { ) -> Result<(), BufferMapError> {
span!(_guard, INFO, "Device::set_buffer_sub_data"); span!(_guard, INFO, "Device::set_buffer_sub_data");
let hub = B::hub(self); let hub = B::hub(self);
@ -793,11 +793,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (mut buffer_guard, _) = hub.buffers.write(&mut token); let (mut buffer_guard, _) = hub.buffers.write(&mut token);
let device = &device_guard[device_id]; let device = &device_guard[device_id];
let mut buffer = &mut buffer_guard[buffer_id]; let mut buffer = &mut buffer_guard[buffer_id];
assert!( check_buffer_usage(buffer.usage, wgt::BufferUsage::MAP_WRITE)?;
buffer.usage.contains(wgt::BufferUsage::MAP_WRITE),
"Buffer usage {:?} must contain usage flag MAP_WRITE",
buffer.usage
);
//assert!(buffer isn't used by the GPU); //assert!(buffer isn't used by the GPU);
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -815,7 +811,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
None => (), None => (),
}; };
match map_buffer( let ptr = map_buffer(
&device.raw, &device.raw,
&mut buffer, &mut buffer,
hal::buffer::SubRange { hal::buffer::SubRange {
@ -823,17 +819,15 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
size: Some(data.len() as BufferAddress), size: Some(data.len() as BufferAddress),
}, },
HostMap::Write, HostMap::Write,
) { )?;
Ok(ptr) => unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), data.len()); unsafe {
}, ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), data.len());
Err(e) => {
log::error!("failed to map a buffer: {:?}", e);
return;
}
} }
unmap_buffer(&device.raw, buffer); unmap_buffer(&device.raw, buffer);
Ok(())
} }
pub fn device_get_buffer_sub_data<B: GfxBackend>( pub fn device_get_buffer_sub_data<B: GfxBackend>(
@ -2852,7 +2846,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
buffer_id: id::BufferId, buffer_id: id::BufferId,
range: Range<BufferAddress>, range: Range<BufferAddress>,
op: resource::BufferMapOperation, op: resource::BufferMapOperation,
) { ) -> Result<(), BufferMapError> {
span!(_guard, INFO, "Device::buffer_map_async"); span!(_guard, INFO, "Device::buffer_map_async");
let hub = B::hub(self); let hub = B::hub(self);
@ -2863,26 +2857,24 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
HostMap::Write => (wgt::BufferUsage::MAP_WRITE, resource::BufferUse::MAP_WRITE), HostMap::Write => (wgt::BufferUsage::MAP_WRITE, resource::BufferUse::MAP_WRITE),
}; };
assert_eq!(range.start % wgt::COPY_BUFFER_ALIGNMENT, 0); if range.start % wgt::COPY_BUFFER_ALIGNMENT != 0
assert_eq!(range.end % wgt::COPY_BUFFER_ALIGNMENT, 0); || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0
{
return Err(BufferMapError::UnalignedRange);
}
let (device_id, ref_count) = { let (device_id, ref_count) = {
let (mut buffer_guard, _) = hub.buffers.write(&mut token); let (mut buffer_guard, _) = hub.buffers.write(&mut token);
let buffer = &mut buffer_guard[buffer_id]; let buffer = &mut buffer_guard[buffer_id];
assert!( check_buffer_usage(buffer.usage, pub_usage)?;
buffer.usage.contains(pub_usage),
"Buffer usage {:?} must contain usage flag(s) {:?}",
buffer.usage,
pub_usage
);
buffer.map_state = match buffer.map_state { buffer.map_state = match buffer.map_state {
resource::BufferMapState::Init { .. } | resource::BufferMapState::Active { .. } => { resource::BufferMapState::Init { .. } | resource::BufferMapState::Active { .. } => {
panic!("Buffer already mapped") return Err(BufferMapError::AlreadyMapped);
} }
resource::BufferMapState::Waiting(_) => { resource::BufferMapState::Waiting(_) => {
op.call_error(); op.call_error();
return; return Ok(());
} }
resource::BufferMapState::Idle => { resource::BufferMapState::Idle => {
resource::BufferMapState::Waiting(resource::BufferPendingMapping { resource::BufferMapState::Waiting(resource::BufferPendingMapping {
@ -2908,6 +2900,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.change_replace(buffer_id, &ref_count, (), internal_use); .change_replace(buffer_id, &ref_count, (), internal_use);
device.lock_life(&mut token).map(buffer_id, ref_count); device.lock_life(&mut token).map(buffer_id, ref_count);
Ok(())
} }
pub fn buffer_get_mapped_range<B: GfxBackend>( pub fn buffer_get_mapped_range<B: GfxBackend>(
@ -2915,7 +2909,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
buffer_id: id::BufferId, buffer_id: id::BufferId,
offset: BufferAddress, offset: BufferAddress,
_size: Option<BufferSize>, _size: Option<BufferSize>,
) -> *mut u8 { ) -> Result<*mut u8, BufferNotMappedError> {
span!(_guard, INFO, "Device::buffer_get_mapped_range"); span!(_guard, INFO, "Device::buffer_get_mapped_range");
let hub = B::hub(self); let hub = B::hub(self);
@ -2926,16 +2920,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
match buffer.map_state { match buffer.map_state {
resource::BufferMapState::Init { ptr, .. } resource::BufferMapState::Init { ptr, .. }
| resource::BufferMapState::Active { ptr, .. } => unsafe { | resource::BufferMapState::Active { ptr, .. } => unsafe {
ptr.as_ptr().offset(offset as isize) Ok(ptr.as_ptr().offset(offset as isize))
}, },
resource::BufferMapState::Idle | resource::BufferMapState::Waiting(_) => { resource::BufferMapState::Idle | resource::BufferMapState::Waiting(_) => {
log::error!("Buffer is not mapped"); Err(BufferNotMappedError)
ptr::null_mut()
} }
} }
} }
pub fn buffer_unmap<B: GfxBackend>(&self, buffer_id: id::BufferId) { pub fn buffer_unmap<B: GfxBackend>(
&self,
buffer_id: id::BufferId,
) -> Result<(), BufferNotMappedError> {
span!(_guard, INFO, "Device::buffer_unmap"); span!(_guard, INFO, "Device::buffer_unmap");
let hub = B::hub(self); let hub = B::hub(self);
@ -3005,7 +3001,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.consume_temp(stage_buffer, stage_memory); .consume_temp(stage_buffer, stage_memory);
} }
resource::BufferMapState::Idle => { resource::BufferMapState::Idle => {
log::error!("Buffer is not mapped"); return Err(BufferNotMappedError);
} }
resource::BufferMapState::Waiting(_) => {} resource::BufferMapState::Waiting(_) => {}
resource::BufferMapState::Active { resource::BufferMapState::Active {
@ -3036,6 +3032,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
unmap_buffer(&device.raw, buffer); unmap_buffer(&device.raw, buffer);
} }
} }
Ok(())
} }
} }
@ -3057,3 +3054,19 @@ pub enum CreateTextureError {
)] )]
InvalidMipLevelCount(u32), InvalidMipLevelCount(u32),
} }
#[derive(Clone, Debug, Error)]
pub enum BufferMapError {
#[error(transparent)]
MissingBufferUsage(#[from] MissingBufferUsageError),
#[error(transparent)]
MapError(#[from] hal::device::MapError),
#[error("buffer map range is not aligned to {}", wgt::COPY_BUFFER_ALIGNMENT)]
UnalignedRange,
#[error("buffer is already mapped")]
AlreadyMapped,
}
#[derive(Clone, Debug, Error)]
#[error("buffer is not mapped")]
pub struct BufferNotMappedError;