Snatch the raw texture when destroying it

This commit is contained in:
Nicolas Silva 2024-01-02 12:33:14 +01:00 committed by Teodor Tanasoaia
parent 95c451a3b8
commit 4b82121501
4 changed files with 121 additions and 30 deletions

View File

@ -736,32 +736,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.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<A: HalApi>(&self, texture_id: id::TextureId, wait: bool) {

View File

@ -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<A: HalApi> {
pub render_bundles: FastHashMap<RenderBundleId, Arc<RenderBundle<A>>>,
pub query_sets: FastHashMap<QuerySetId, Arc<QuerySet<A>>>,
pub destroyed_buffers: FastHashMap<BufferId, Arc<DestroyedBuffer<A>>>,
pub destroyed_textures: FastHashMap<TextureId, Arc<DestroyedTexture<A>>>,
}
impl<A: HalApi> ResourceMaps<A> {
@ -61,6 +62,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles: FastHashMap::default(),
query_sets: FastHashMap::default(),
destroyed_buffers: FastHashMap::default(),
destroyed_textures: FastHashMap::default(),
}
}
@ -79,6 +81,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles,
query_sets,
destroyed_buffers,
destroyed_textures,
} = self;
buffers.clear();
staging_buffers.clear();
@ -93,6 +96,7 @@ impl<A: HalApi> ResourceMaps<A> {
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<A: HalApi> ResourceMaps<A> {
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<A: HalApi> ResourceMaps<A> {
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<A: HalApi> LifetimeTracker<A> {
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<A: HalApi> LifetimeTracker<A> {
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<A: HalApi> LifetimeTracker<A> {
}
}
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<Tracker<A>>,
@ -913,6 +948,10 @@ impl<A: HalApi> LifetimeTracker<A> {
#[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

View File

@ -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<A: HalApi> {
Buffer(Arc<Buffer<A>>),
StagingBuffer(Arc<StagingBuffer<A>>),
DestroyedBuffer(Arc<DestroyedBuffer<A>>),
DestroyedTexture(Arc<DestroyedTexture<A>>),
Texture(Arc<Texture<A>>),
}

View File

@ -835,6 +835,50 @@ impl<A: HalApi> Texture<A> {
}
}
}
pub(crate) fn destroy(self: &Arc<Self>) -> 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<G: GlobalIdentityHandlerFactory> Global<G> {
@ -927,6 +971,38 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
/// A texture that has been marked as destroyed and is staged for actual deletion soon.
#[derive(Debug)]
pub struct DestroyedTexture<A: HalApi> {
raw: Option<A::Texture>,
device: Arc<Device<A>>,
label: String,
pub(crate) id: TextureId,
pub(crate) submission_index: u64,
}
impl<A: HalApi> DestroyedTexture<A> {
pub fn label(&self) -> &dyn Debug {
if !self.label.is_empty() {
return &self.label;
}
&self.id
}
}
impl<A: HalApi> Drop for DestroyedTexture<A> {
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,