From ae17ea7625f23e769703e1e28b621c4d18709356 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 27 May 2020 15:53:21 -0400 Subject: [PATCH 1/3] New map_async logic, change the semantic of mapped buffers. --- wgpu-core/src/device/life.rs | 27 +-- wgpu-core/src/device/mod.rs | 306 +++++++++++++++++++--------------- wgpu-core/src/device/queue.rs | 15 ++ wgpu-core/src/resource.rs | 60 +++---- wgpu-types/src/lib.rs | 2 + 5 files changed, 228 insertions(+), 182 deletions(-) diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 4b92d849d2..9d69abfceb 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -657,19 +657,22 @@ impl LifetimeTracker { _ => panic!("No pending mapping."), }; log::debug!("Buffer {:?} map state -> Active", buffer_id); - let host = match mapping.op { - resource::BufferMapOperation::Read { .. } => super::HostMap::Read, - resource::BufferMapOperation::Write { .. } => super::HostMap::Write, + let host = mapping.op.host; + let status = match super::map_buffer(raw, buffer, mapping.sub_range.clone(), host) { + Ok(ptr) => { + buffer.map_state = resource::BufferMapState::Active { + ptr, + sub_range: mapping.sub_range, + host, + }; + resource::BufferMapAsyncStatus::Success + } + Err(e) => { + log::error!("Mapping failed {:?}", e); + resource::BufferMapAsyncStatus::Error + } }; - let result = super::map_buffer(raw, buffer, mapping.sub_range.clone(), host); - if let Ok(ptr) = result { - buffer.map_state = resource::BufferMapState::Active { - ptr, - sub_range: mapping.sub_range, - host, - }; - } - pending_callbacks.push((mapping.op, result)); + pending_callbacks.push((mapping.op, status)); } } pending_callbacks diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index c7b6ec8ef6..a4ec0eb758 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -26,7 +26,7 @@ use wgt::{ }; use std::{ - collections::hash_map::Entry, ffi, iter, marker::PhantomData, ptr, slice, + collections::hash_map::Entry, ffi, iter, marker::PhantomData, mem, ptr, slice, sync::atomic::Ordering, }; @@ -111,18 +111,8 @@ pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::imag pub(crate) type FramebufferKey = AttachmentData; pub(crate) type RenderPassContext = AttachmentData; -// This typedef is needed to work around cbindgen limitations. -type RawBufferMut = *mut u8; -type BufferMapResult = Result; -type BufferMapPendingCallback = (resource::BufferMapOperation, BufferMapResult); - -pub type BufferMapReadCallback = unsafe extern "C" fn( - status: resource::BufferMapAsyncStatus, - data: *const u8, - userdata: *mut u8, -); -pub type BufferMapWriteCallback = - unsafe extern "C" fn(status: resource::BufferMapAsyncStatus, data: *mut u8, userdata: *mut u8); +type BufferMapResult = Result, hal::device::MapError>; +type BufferMapPendingCallback = (resource::BufferMapOperation, resource::BufferMapAsyncStatus); fn map_buffer( raw: &B::Device, @@ -153,7 +143,7 @@ fn map_buffer( HostMap::Write if needs_sync => Some(segment), _ => None, }; - Ok(ptr.as_ptr()) + Ok(ptr) } fn unmap_buffer(raw: &B::Device, buffer: &mut resource::Buffer) { @@ -168,22 +158,8 @@ fn unmap_buffer(raw: &B::Device, buffer: &mut resource::Buffer< //Note: this logic is specifically moved out of `handle_mapping()` in order to // have nothing locked by the time we execute users callback code. fn fire_map_callbacks>(callbacks: I) { - for (operation, result) in callbacks { - let (status, ptr) = match result { - Ok(ptr) => (resource::BufferMapAsyncStatus::Success, ptr), - Err(e) => { - log::error!("failed to map buffer: {:?}", e); - (resource::BufferMapAsyncStatus::Error, ptr::null_mut()) - } - }; - match operation { - resource::BufferMapOperation::Read { callback, userdata } => unsafe { - callback(status, ptr, userdata) - }, - resource::BufferMapOperation::Write { callback, userdata } => unsafe { - callback(status, ptr, userdata) - }, - } + for (operation, status) in callbacks { + unsafe { (operation.callback)(status, operation.user_data) } } } @@ -206,6 +182,8 @@ pub struct Device { pub(crate) private_features: PrivateFeatures, limits: wgt::Limits, extensions: wgt::Extensions, + //TODO: move this behind another mutex. This would allow several methods to switch + // to borrow Device immutably, such as `write_buffer`, `write_texture`, and `buffer_unmap`. pending_writes: queue::PendingWrites, #[cfg(feature = "trace")] pub(crate) trace: Option>, @@ -327,28 +305,36 @@ impl Device { &self, self_id: id::DeviceId, desc: &wgt::BufferDescriptor