diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 1abc6d8ade..63270106af 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -16,7 +16,7 @@ use hal::Device as _; use parking_lot::Mutex; use thiserror::Error; -use std::sync::atomic::Ordering; +use std::{mem, sync::atomic::Ordering}; /// A struct that keeps lists of resources that are no longer needed by the user. #[derive(Debug, Default)] @@ -230,6 +230,15 @@ impl LifetimeTracker { } } + self.active.alloc().init(ActiveSubmission { + index, + last_resources, + mapped: Vec::new(), + encoders, + }); + } + + pub fn post_submit(&mut self) { self.suspected_resources.buffers.extend( self.future_suspected_buffers .drain(..) @@ -240,13 +249,6 @@ impl LifetimeTracker { .drain(..) .map(|stored| stored.value), ); - - self.active.alloc().init(ActiveSubmission { - index, - last_resources, - mapped: Vec::new(), - encoders, - }); } pub(crate) fn map(&mut self, value: id::Valid, ref_count: RefCount) { @@ -305,6 +307,20 @@ impl LifetimeTracker { } impl LifetimeTracker { + pub(super) fn schedule_texture_view_for_destruction( + &mut self, + id: id::Valid, + view: resource::TextureView, + ) { + let submit_index = view.life_guard.submission_index.load(Ordering::Acquire); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .texture_views + .push((id, view.raw)); + } + pub(super) fn triage_suspected( &mut self, hub: &Hub, @@ -362,7 +378,8 @@ impl LifetimeTracker { let (mut guard, _) = hub.texture_views.write(token); let mut trackers = trackers.lock(); - for id in self.suspected_resources.texture_views.drain(..) { + let mut list = mem::take(&mut self.suspected_resources.texture_views); + for id in list.drain(..) { if trackers.views.remove_abandoned(id) { #[cfg(feature = "trace")] if let Some(t) = trace { @@ -371,22 +388,16 @@ impl LifetimeTracker { if let Some(res) = hub.texture_views.unregister_locked(id.0, &mut *guard) { match res.source { - resource::TextureViewSource::Native(source_id) => { + resource::TextureViewSource::Native(ref source_id) => { self.suspected_resources.textures.push(source_id.value); } resource::TextureViewSource::SwapChain { .. } => {} }; - - let submit_index = res.life_guard.submission_index.load(Ordering::Acquire); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .texture_views - .push((id, res.raw)); + self.schedule_texture_view_for_destruction(id, res); } } } + self.suspected_resources.texture_views = list; } if !self.suspected_resources.textures.is_empty() { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 60b405328a..26d224b5ce 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -333,30 +333,22 @@ impl Device { }) } - fn lock_life_internal<'this, 'token: 'this>( - tracker: &'this Mutex>, - _token: &mut Token<'token, Self>, - ) -> MutexGuard<'this, life::LifetimeTracker> { - tracker.lock() - } - fn lock_life<'this, 'token: 'this>( &'this self, //TODO: fix this - the token has to be borrowed for the lock - token: &mut Token<'token, Self>, + _token: &mut Token<'token, Self>, ) -> MutexGuard<'this, life::LifetimeTracker> { - Self::lock_life_internal(&self.life_tracker, token) + self.life_tracker.lock() } - pub(crate) fn suspect_texture_view_for_destruction<'this, 'token: 'this>( + pub(crate) fn schedule_rogue_texture_view_for_destruction<'this, 'token: 'this>( &'this self, view_id: id::Valid, + view: resource::TextureView, token: &mut Token<'token, Self>, ) { self.lock_life(token) - .suspected_resources - .texture_views - .push(view_id); + .schedule_texture_view_for_destruction(view_id, view); } fn maintain<'this, 'token: 'this, G: GlobalIdentityHandlerFactory>( diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 130070aecd..a68766a835 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -808,14 +808,6 @@ impl Global { } } - let callbacks = match device.maintain(&hub, false, &mut token) { - Ok(callbacks) => callbacks, - Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), - Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu), - }; - - device.temp_suspected.clear(); - profiling::scope!("cleanup"); if let Some(pending_execution) = device.pending_writes.post_submit( &device.command_allocator, @@ -824,12 +816,27 @@ impl Global { ) { active_executions.push(pending_execution); } - super::Device::lock_life_internal(&device.life_tracker, &mut token).track_submission( + + // this will register the new submission to the life time tracker + let mut pending_write_resources = mem::take(&mut device.pending_writes.temp_resources); + device.lock_life(&mut token).track_submission( submit_index, - device.pending_writes.temp_resources.drain(..), + pending_write_resources.drain(..), active_executions, ); + // 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 callbacks = match device.maintain(&hub, false, &mut token) { + Ok(callbacks) => callbacks, + Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), + Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu), + }; + + device.pending_writes.temp_resources = pending_write_resources; + device.temp_suspected.clear(); + device.lock_life(&mut token).post_submit(); + callbacks }; diff --git a/wgpu-core/src/swap_chain.rs b/wgpu-core/src/swap_chain.rs index 3910dd01be..7919247d7f 100644 --- a/wgpu-core/src/swap_chain.rs +++ b/wgpu-core/src/swap_chain.rs @@ -267,11 +267,11 @@ impl Global { .ok_or(SwapChainError::AlreadyAcquired)?; drop(swap_chain_guard); - device.suspect_texture_view_for_destruction(view_id.value, &mut token); - let (mut view_guard, _) = hub.texture_views.write(&mut token); - let view = &mut view_guard[view_id.value]; - let _ = view.life_guard.ref_count.take(); + let (view, _) = hub.texture_views.unregister(view_id.value.0, &mut token); + if let Some(view) = view { + device.schedule_rogue_texture_view_for_destruction(view_id.value, view, &mut token); + } suf_texture };