From 4b82121501a61c2c2e11cb472d70ba54af3aa12d Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Tue, 2 Jan 2024 12:33:14 +0100 Subject: [PATCH] Snatch the raw texture when destroying it --- wgpu-core/src/device/global.rs | 27 +----------- wgpu-core/src/device/life.rs | 43 ++++++++++++++++++- wgpu-core/src/device/queue.rs | 5 ++- wgpu-core/src/resource.rs | 76 ++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 30 deletions(-) diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index d5917d58e5..fed4b50a5a 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -736,32 +736,7 @@ impl Global { .get_and_mark_destroyed(texture_id) .map_err(|_| resource::DestroyError::Invalid)?; - let device = &texture.device; - - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::FreeTexture(texture_id)); - } - - let last_submit_index = texture.info.submission_index(); - - let snatch_guard = texture.device.snatchable_lock.read(); - - if let Some(resource::TextureInner::Native { .. }) = texture.inner.get(&snatch_guard) { - let temp = queue::TempResource::Texture(texture.clone()); - let mut guard = device.pending_writes.lock(); - let pending_writes = guard.as_mut().unwrap(); - if pending_writes.dst_textures.contains_key(&texture_id) { - pending_writes.temp_resources.push(temp); - } else { - drop(guard); - device - .lock_life() - .schedule_resource_destruction(temp, last_submit_index); - } - } - - Ok(()) + texture.destroy() } pub fn texture_drop(&self, texture_id: id::TextureId, wait: bool) { diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 08e75ce00a..1a533cfb38 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -15,8 +15,8 @@ use crate::{ }, pipeline::{ComputePipeline, RenderPipeline}, resource::{ - self, Buffer, DestroyedBuffer, QuerySet, Resource, Sampler, StagingBuffer, Texture, - TextureView, + self, Buffer, DestroyedBuffer, DestroyedTexture, QuerySet, Resource, Sampler, + StagingBuffer, Texture, TextureView, }, track::{ResourceTracker, Tracker}, FastHashMap, SubmissionIndex, @@ -43,6 +43,7 @@ pub(crate) struct ResourceMaps { pub render_bundles: FastHashMap>>, pub query_sets: FastHashMap>>, pub destroyed_buffers: FastHashMap>>, + pub destroyed_textures: FastHashMap>>, } impl ResourceMaps { @@ -61,6 +62,7 @@ impl ResourceMaps { render_bundles: FastHashMap::default(), query_sets: FastHashMap::default(), destroyed_buffers: FastHashMap::default(), + destroyed_textures: FastHashMap::default(), } } @@ -79,6 +81,7 @@ impl ResourceMaps { render_bundles, query_sets, destroyed_buffers, + destroyed_textures, } = self; buffers.clear(); staging_buffers.clear(); @@ -93,6 +96,7 @@ impl ResourceMaps { render_bundles.clear(); query_sets.clear(); destroyed_buffers.clear(); + destroyed_textures.clear(); } pub(crate) fn extend(&mut self, mut other: Self) { @@ -110,6 +114,7 @@ impl ResourceMaps { render_bundles, query_sets, destroyed_buffers, + destroyed_textures, } = self; buffers.extend(other.buffers.drain()); staging_buffers.extend(other.staging_buffers.drain()); @@ -124,6 +129,7 @@ impl ResourceMaps { render_bundles.extend(other.render_bundles.drain()); query_sets.extend(other.query_sets.drain()); destroyed_buffers.extend(other.destroyed_buffers.drain()); + destroyed_textures.extend(other.destroyed_textures.drain()); } } @@ -298,6 +304,11 @@ impl LifetimeTracker { TempResource::Texture(raw) => { last_resources.textures.insert(raw.as_info().id(), raw); } + TempResource::DestroyedTexture(destroyed) => { + last_resources + .destroyed_textures + .insert(destroyed.id, destroyed); + } } } @@ -404,6 +415,9 @@ impl LifetimeTracker { TempResource::Texture(raw) => { resources.textures.insert(raw.as_info().id(), raw); } + TempResource::DestroyedTexture(destroyed) => { + resources.destroyed_textures.insert(destroyed.id, destroyed); + } } } @@ -680,6 +694,27 @@ impl LifetimeTracker { } } + fn triage_suspected_destroyed_textures( + &mut self, + #[cfg(feature = "trace")] trace: &mut Option<&mut trace::Trace>, + ) { + for (id, texture) in self.suspected_resources.destroyed_textures.drain() { + let submit_index = texture.submission_index; + if let Some(resources) = self.active.iter_mut().find(|a| a.index == submit_index) { + resources + .last_resources + .destroyed_textures + .insert(id, texture); + } else { + self.free_resources.destroyed_textures.insert(id, texture); + } + #[cfg(feature = "trace")] + if let Some(ref mut t) = *trace { + t.add(trace::Action::DestroyTexture(id)); + } + } + } + fn triage_suspected_compute_pipelines( &mut self, trackers: &Mutex>, @@ -913,6 +948,10 @@ impl LifetimeTracker { #[cfg(feature = "trace")] &mut trace, ); + self.triage_suspected_destroyed_textures( + #[cfg(feature = "trace")] + &mut trace, + ); } /// Determine which buffers are ready to map, and which must wait for the diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index eacf4d4b36..249935bffe 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -16,8 +16,8 @@ use crate::{ identity::{GlobalIdentityHandlerFactory, Input}, init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, resource::{ - Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, Resource, ResourceInfo, - ResourceType, StagingBuffer, Texture, TextureInner, + Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource, + ResourceInfo, ResourceType, StagingBuffer, Texture, TextureInner, }, resource_log, track, FastHashMap, SubmissionIndex, }; @@ -164,6 +164,7 @@ pub enum TempResource { Buffer(Arc>), StagingBuffer(Arc>), DestroyedBuffer(Arc>), + DestroyedTexture(Arc>), Texture(Arc>), } diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 37c95731e0..395b82517b 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -835,6 +835,50 @@ impl Texture { } } } + + pub(crate) fn destroy(self: &Arc) -> Result<(), DestroyError> { + let device = &self.device; + let texture_id = self.info.id(); + + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::FreeTexture(texture_id)); + } + + let temp = { + let snatch_guard = device.snatchable_lock.write(); + let raw = match self.inner.snatch(snatch_guard) { + Some(TextureInner::Native { raw }) => raw, + Some(TextureInner::Surface { .. }) => { + return Ok(()); + } + None => { + return Err(resource::DestroyError::AlreadyDestroyed); + } + }; + + queue::TempResource::DestroyedTexture(Arc::new(DestroyedTexture { + raw: Some(raw), + device: Arc::clone(&self.device), + submission_index: self.info.submission_index(), + id: self.info.id.unwrap(), + label: self.info.label.clone(), + })) + }; + + let mut pending_writes = device.pending_writes.lock(); + let pending_writes = pending_writes.as_mut().unwrap(); + if pending_writes.dst_textures.contains_key(&texture_id) { + pending_writes.temp_resources.push(temp); + } else { + let last_submit_index = self.info.submission_index(); + device + .lock_life() + .schedule_resource_destruction(temp, last_submit_index); + } + + Ok(()) + } } impl Global { @@ -927,6 +971,38 @@ impl Global { } } +/// A texture that has been marked as destroyed and is staged for actual deletion soon. +#[derive(Debug)] +pub struct DestroyedTexture { + raw: Option, + device: Arc>, + label: String, + pub(crate) id: TextureId, + pub(crate) submission_index: u64, +} + +impl DestroyedTexture { + pub fn label(&self) -> &dyn Debug { + if !self.label.is_empty() { + return &self.label; + } + + &self.id + } +} + +impl Drop for DestroyedTexture { + fn drop(&mut self) { + if let Some(raw) = self.raw.take() { + resource_log!("Deallocate raw Texture (destroyed) {:?}", self.label()); + unsafe { + use hal::Device; + self.device.raw().destroy_texture(raw); + } + } + } +} + #[derive(Clone, Copy, Debug)] pub enum TextureErrorDimension { X,