diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/wgpu-core/src/device/global.rs | 33 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/life.rs | 15 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/mod.rs | 11 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/queue.rs | 17 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/resource.rs | 20 |
5 files changed, 74 insertions, 22 deletions
diff --git a/third_party/rust/wgpu-core/src/device/global.rs b/third_party/rust/wgpu-core/src/device/global.rs index 539b92e0f3..0c97e1b504 100644 --- a/third_party/rust/wgpu-core/src/device/global.rs +++ b/third_party/rust/wgpu-core/src/device/global.rs @@ -192,7 +192,15 @@ impl Global { let ptr = if map_size == 0 { std::ptr::NonNull::dangling() } else { - match map_buffer(device.raw(), &buffer, 0, map_size, HostMap::Write) { + let snatch_guard = device.snatchable_lock.read(); + match map_buffer( + device.raw(), + &buffer, + 0, + map_size, + HostMap::Write, + &snatch_guard, + ) { Ok(ptr) => ptr, Err(e) => { to_destroy.push(buffer); @@ -2008,9 +2016,10 @@ impl Global { } // Wait for all work to finish before configuring the surface. + let snatch_guard = device.snatchable_lock.read(); let fence = device.fence.read(); let fence = fence.as_ref().unwrap(); - match device.maintain(fence, wgt::Maintain::Wait) { + match device.maintain(fence, wgt::Maintain::Wait, snatch_guard) { Ok((closures, _)) => { user_callbacks = closures; } @@ -2120,9 +2129,10 @@ impl Global { device: &crate::device::Device<A>, maintain: wgt::Maintain<queue::WrappedSubmissionIndex>, ) -> Result<DevicePoll, WaitIdleError> { + let snatch_guard = device.snatchable_lock.read(); let fence = device.fence.read(); let fence = fence.as_ref().unwrap(); - let (closures, queue_empty) = device.maintain(fence, maintain)?; + let (closures, queue_empty) = device.maintain(fence, maintain, snatch_guard)?; // Some deferred destroys are scheduled in maintain so run this right after // to avoid holding on to them until the next device poll. @@ -2240,6 +2250,15 @@ impl Global { } } + // This is a test-only function to force the device into an + // invalid state by inserting an error value in its place in + // the registry. + pub fn device_make_invalid<A: HalApi>(&self, device_id: DeviceId) { + let hub = A::hub(self); + hub.devices + .force_replace_with_error(device_id, "Made invalid."); + } + pub fn device_drop<A: HalApi>(&self, device_id: DeviceId) { profiling::scope!("Device::drop"); api_log!("Device::drop {device_id:?}"); @@ -2275,7 +2294,7 @@ impl Global { ) { let hub = A::hub(self); - if let Ok(device) = hub.devices.get(device_id) { + if let Ok(Some(device)) = hub.devices.try_get(device_id) { let mut life_tracker = device.lock_life(); if let Some(existing_closure) = life_tracker.device_lost_closure.take() { // It's important to not hold the lock while calling the closure. @@ -2284,6 +2303,12 @@ impl Global { life_tracker = device.lock_life(); } life_tracker.device_lost_closure = Some(device_lost_closure); + } else { + // No device? Okay. Just like we have to call any existing closure + // before we drop it, we need to call this closure before we exit + // this function, because there's no device that is ever going to + // call it. + device_lost_closure.call(DeviceLostReason::DeviceInvalid, "".to_string()); } } diff --git a/third_party/rust/wgpu-core/src/device/life.rs b/third_party/rust/wgpu-core/src/device/life.rs index 7b06a4a30b..af345015df 100644 --- a/third_party/rust/wgpu-core/src/device/life.rs +++ b/third_party/rust/wgpu-core/src/device/life.rs @@ -12,6 +12,7 @@ use crate::{ self, Buffer, DestroyedBuffer, DestroyedTexture, QuerySet, Resource, Sampler, StagingBuffer, Texture, TextureView, }, + snatch::SnatchGuard, track::{ResourceTracker, Tracker, TrackerIndex}, FastHashMap, SubmissionIndex, }; @@ -309,12 +310,12 @@ impl<A: HalApi> LifetimeTracker<A> { } pub fn post_submit(&mut self) { - for v in self.future_suspected_buffers.drain(..).take(1) { + for v in self.future_suspected_buffers.drain(..) { self.suspected_resources .buffers .insert(v.as_info().tracker_index(), v); } - for v in self.future_suspected_textures.drain(..).take(1) { + for v in self.future_suspected_textures.drain(..) { self.suspected_resources .textures .insert(v.as_info().tracker_index(), v); @@ -780,6 +781,7 @@ impl<A: HalApi> LifetimeTracker<A> { &mut self, raw: &A::Device, trackers: &Mutex<Tracker<A>>, + snatch_guard: &SnatchGuard, ) -> Vec<super::BufferMapPendingClosure> { if self.ready_to_map.is_empty() { return Vec::new(); @@ -816,7 +818,14 @@ impl<A: HalApi> LifetimeTracker<A> { log::debug!("Buffer {tracker_index:?} map state -> Active"); let host = mapping.op.host; let size = mapping.range.end - mapping.range.start; - match super::map_buffer(raw, &buffer, mapping.range.start, size, host) { + match super::map_buffer( + raw, + &buffer, + mapping.range.start, + size, + host, + snatch_guard, + ) { Ok(ptr) => { *buffer.map_state.lock() = resource::BufferMapState::Active { ptr, diff --git a/third_party/rust/wgpu-core/src/device/mod.rs b/third_party/rust/wgpu-core/src/device/mod.rs index 7ecda830a3..e2ab6c2690 100644 --- a/third_party/rust/wgpu-core/src/device/mod.rs +++ b/third_party/rust/wgpu-core/src/device/mod.rs @@ -3,9 +3,10 @@ use crate::{ hal_api::HalApi, hub::Hub, id::{BindGroupLayoutId, PipelineLayoutId}, - resource::{Buffer, BufferAccessResult}, - resource::{BufferAccessError, BufferMapOperation}, - resource_log, Label, DOWNLEVEL_ERROR_MESSAGE, + resource::{Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation}, + resource_log, + snatch::SnatchGuard, + Label, DOWNLEVEL_ERROR_MESSAGE, }; use arrayvec::ArrayVec; @@ -317,10 +318,10 @@ fn map_buffer<A: HalApi>( offset: BufferAddress, size: BufferAddress, kind: HostMap, + snatch_guard: &SnatchGuard, ) -> Result<ptr::NonNull<u8>, BufferAccessError> { - let snatch_guard = buffer.device.snatchable_lock.read(); let raw_buffer = buffer - .raw(&snatch_guard) + .raw(snatch_guard) .ok_or(BufferAccessError::Destroyed)?; let mapping = unsafe { raw.map_buffer(raw_buffer, offset..offset + size) diff --git a/third_party/rust/wgpu-core/src/device/queue.rs b/third_party/rust/wgpu-core/src/device/queue.rs index 6ebb9eb09b..3cb5f695a7 100644 --- a/third_party/rust/wgpu-core/src/device/queue.rs +++ b/third_party/rust/wgpu-core/src/device/queue.rs @@ -815,6 +815,7 @@ impl Global { &mut trackers.textures, &device.alignments, device.zero_buffer.as_ref().unwrap(), + &device.snatchable_lock.read(), ) .map_err(QueueWriteError::from)?; } @@ -1084,6 +1085,7 @@ impl Global { &mut trackers.textures, &device.alignments, device.zero_buffer.as_ref().unwrap(), + &device.snatchable_lock.read(), ) .map_err(QueueWriteError::from)?; } @@ -1147,6 +1149,9 @@ impl Global { let device = queue.device.as_ref().unwrap(); + let snatch_guard = device.snatchable_lock.read(); + + // Fence lock must be acquired after the snatch lock everywhere to avoid deadlocks. let mut fence = device.fence.write(); let fence = fence.as_mut().unwrap(); let submit_index = device @@ -1155,9 +1160,7 @@ impl Global { + 1; let mut active_executions = Vec::new(); - let mut used_surface_textures = track::TextureUsageScope::new(); - - let snatch_guard = device.snatchable_lock.read(); + let mut used_surface_textures = track::TextureUsageScope::default(); let mut submit_surface_textures_owned = SmallVec::<[_; 2]>::new(); @@ -1391,10 +1394,10 @@ impl Global { //Note: locking the trackers has to be done after the storages let mut trackers = device.trackers.lock(); baked - .initialize_buffer_memory(&mut *trackers) + .initialize_buffer_memory(&mut *trackers, &snatch_guard) .map_err(|err| QueueSubmitError::DestroyedBuffer(err.0))?; baked - .initialize_texture_memory(&mut *trackers, device) + .initialize_texture_memory(&mut *trackers, device, &snatch_guard) .map_err(|err| QueueSubmitError::DestroyedTexture(err.0))?; //Note: stateless trackers are not merged: // device already knows these resources exist. @@ -1435,7 +1438,7 @@ impl Global { baked.encoder.end_encoding().unwrap() }; baked.list.push(present); - used_surface_textures = track::TextureUsageScope::new(); + used_surface_textures = track::TextureUsageScope::default(); } // done @@ -1542,7 +1545,7 @@ impl Global { // This will schedule destruction of all resources that are no longer needed // by the user but used in the command stream, among other things. - let (closures, _) = match device.maintain(fence, wgt::Maintain::Poll) { + let (closures, _) = match device.maintain(fence, wgt::Maintain::Poll, snatch_guard) { Ok(closures) => closures, Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu), diff --git a/third_party/rust/wgpu-core/src/device/resource.rs b/third_party/rust/wgpu-core/src/device/resource.rs index 28ba0eafb1..4892aecb75 100644 --- a/third_party/rust/wgpu-core/src/device/resource.rs +++ b/third_party/rust/wgpu-core/src/device/resource.rs @@ -28,7 +28,10 @@ use crate::{ resource_log, snatch::{SnatchGuard, SnatchLock, Snatchable}, storage::Storage, - track::{BindGroupStates, TextureSelector, Tracker, TrackerIndexAllocators}, + track::{ + BindGroupStates, TextureSelector, Tracker, TrackerIndexAllocators, UsageScope, + UsageScopePool, + }, validation::{ self, check_buffer_usage, check_texture_usage, validate_color_attachment_bytes_per_sample, }, @@ -97,6 +100,8 @@ pub struct Device<A: HalApi> { pub(crate) command_allocator: Mutex<Option<CommandAllocator<A>>>, //Note: The submission index here corresponds to the last submission that is done. pub(crate) active_submission_index: AtomicU64, //SubmissionIndex, + // NOTE: if both are needed, the `snatchable_lock` must be consistently acquired before the + // `fence` lock to avoid deadlocks. pub(crate) fence: RwLock<Option<A::Fence>>, pub(crate) snatchable_lock: SnatchLock, @@ -135,6 +140,7 @@ pub struct Device<A: HalApi> { pub(crate) deferred_destroy: Mutex<Vec<DeferredDestroy<A>>>, #[cfg(feature = "trace")] pub(crate) trace: Mutex<Option<trace::Trace>>, + pub(crate) usage_scopes: UsageScopePool<A>, } pub(crate) enum DeferredDestroy<A: HalApi> { @@ -296,6 +302,7 @@ impl<A: HalApi> Device<A> { instance_flags, pending_writes: Mutex::new(Some(pending_writes)), deferred_destroy: Mutex::new(Vec::new()), + usage_scopes: Default::default(), }) } @@ -387,6 +394,7 @@ impl<A: HalApi> Device<A> { &'this self, fence: &A::Fence, maintain: wgt::Maintain<queue::WrappedSubmissionIndex>, + snatch_guard: SnatchGuard, ) -> Result<(UserClosures, bool), WaitIdleError> { profiling::scope!("Device::maintain"); let last_done_index = if maintain.is_wait() { @@ -440,7 +448,8 @@ impl<A: HalApi> Device<A> { life_tracker.triage_mapped(); } - let mapping_closures = life_tracker.handle_mapping(self.raw(), &self.trackers); + let mapping_closures = + life_tracker.handle_mapping(self.raw(), &self.trackers, &snatch_guard); let queue_empty = life_tracker.queue_empty(); @@ -467,8 +476,9 @@ impl<A: HalApi> Device<A> { } } - // Don't hold the lock while calling release_gpu_resources. + // Don't hold the locks while calling release_gpu_resources. drop(life_tracker); + drop(snatch_guard); if should_release_gpu_resource { self.release_gpu_resources(); @@ -3568,6 +3578,10 @@ impl<A: HalApi> Device<A> { let _ = texture.destroy(); } } + + pub(crate) fn new_usage_scope(&self) -> UsageScope<'_, A> { + UsageScope::new_pooled(&self.usage_scopes, &self.tracker_indices) + } } impl<A: HalApi> Device<A> { |