diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 4f6f1c14b0..577a7e39ca 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -372,15 +372,19 @@ impl Device { let mapping_closures = life_tracker.handle_mapping(self.raw(), &self.trackers); + let queue_empty = life_tracker.queue_empty(); + // Detect if we have been destroyed and now need to lose the device. // If we are invalid (set at start of destroy) and our queue is empty, // and we have a DeviceLostClosure, return the closure to be called by // our caller. This will complete the steps for both destroy and for // "lose the device". let mut device_lost_invocations = SmallVec::new(); - if !self.is_valid() && life_tracker.queue_empty() { - // We can release gpu resources associated with this device. - self.release_gpu_resources(); + let mut should_release_gpu_resource = false; + if !self.is_valid() && queue_empty { + // We can release gpu resources associated with this device (but not + // while holding the life_tracker lock). + should_release_gpu_resource = true; // If we have a DeviceLostClosure, build an invocation with the // reason DeviceLostReason::Destroyed and no message. @@ -393,12 +397,19 @@ impl Device { } } + // Don't hold the lock while calling release_gpu_resources. + drop(life_tracker); + + if should_release_gpu_resource { + self.release_gpu_resources(); + } + let closures = UserClosures { mappings: mapping_closures, submissions: submission_closures, device_lost_invocations, }; - Ok((closures, life_tracker.queue_empty())) + Ok((closures, queue_empty)) } pub(crate) fn untrack(&self, trackers: &Tracker) {