Remove the Destroyed state from Storage (#4970)

* Remove the Destroyed state from Storage

It used to be how we handled destroying buffers and textures but we moved to different approach.

* Explicit check for destroyed textures/buffers in a few entry points

This used to be checked automatically when getting the resource from the registry, but has to be done manually now that we track we track the destroyed state in the resources.
This commit is contained in:
Nicolas Silva 2024-01-11 11:45:12 +01:00 committed by GitHub
parent b30c0c2e00
commit bc65d84cdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 50 deletions

View File

@ -489,8 +489,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let buffer = hub let buffer = hub
.buffers .buffers
.write() .get(buffer_id)
.get_and_mark_destroyed(buffer_id)
.map_err(|_| resource::DestroyError::Invalid)?; .map_err(|_| resource::DestroyError::Invalid)?;
let _ = buffer.unmap(); let _ = buffer.unmap();
@ -732,8 +731,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let texture = hub let texture = hub
.textures .textures
.write() .get(texture_id)
.get_and_mark_destroyed(texture_id)
.map_err(|_| resource::DestroyError::Invalid)?; .map_err(|_| resource::DestroyError::Invalid)?;
texture.destroy() texture.destroy()
@ -799,6 +797,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Err(_) => break resource::CreateTextureViewError::InvalidTexture, Err(_) => break resource::CreateTextureViewError::InvalidTexture,
}; };
let device = &texture.device; let device = &texture.device;
{
let snatch_guard = device.snatchable_lock.read();
if texture.is_destroyed(&snatch_guard) {
break resource::CreateTextureViewError::InvalidTexture;
}
}
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() { if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::CreateTextureView { trace.add(trace::Action::CreateTextureView {
@ -2386,6 +2390,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}, },
)); ));
} }
let snatch_guard = device.snatchable_lock.read();
if buffer.is_destroyed(&snatch_guard) {
return Err((op, BufferAccessError::Destroyed));
}
{ {
let map_state = &mut *buffer.map_state.lock(); let map_state = &mut *buffer.map_state.lock();
*map_state = match *map_state { *map_state = match *map_state {
@ -2410,10 +2420,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut trackers = buffer.device.as_ref().trackers.lock(); let mut trackers = buffer.device.as_ref().trackers.lock();
trackers.buffers.set_single(&buffer, internal_use); trackers.buffers.set_single(&buffer, internal_use);
//TODO: Check if draining ALL buffers is correct! //TODO: Check if draining ALL buffers is correct!
let snatch_guard = device.snatchable_lock.read();
let _ = trackers.buffers.drain_transitions(&snatch_guard); let _ = trackers.buffers.drain_transitions(&snatch_guard);
} }
drop(snatch_guard);
buffer buffer
}; };
@ -2438,6 +2449,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.get(buffer_id) .get(buffer_id)
.map_err(|_| BufferAccessError::Invalid)?; .map_err(|_| BufferAccessError::Invalid)?;
{
let snatch_guard = buffer.device.snatchable_lock.read();
if buffer.is_destroyed(&snatch_guard) {
return Err(BufferAccessError::Destroyed);
}
}
let range_size = if let Some(size) = size { let range_size = if let Some(size) = size {
size size
} else if offset > buffer.size { } else if offset > buffer.size {
@ -2500,6 +2518,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.get(buffer_id) .get(buffer_id)
.map_err(|_| BufferAccessError::Invalid)?; .map_err(|_| BufferAccessError::Invalid)?;
let snatch_guard = buffer.device.snatchable_lock.read();
if buffer.is_destroyed(&snatch_guard) {
return Err(BufferAccessError::Destroyed);
}
drop(snatch_guard);
if !buffer.device.is_valid() { if !buffer.device.is_valid() {
return Err(DeviceError::Lost.into()); return Err(DeviceError::Lost.into());
} }

View File

@ -1158,8 +1158,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// it, so make sure to set_size on it. // it, so make sure to set_size on it.
used_surface_textures.set_size(hub.textures.read().len()); used_surface_textures.set_size(hub.textures.read().len());
// TODO: ideally we would use `get_and_mark_destroyed` but the code here
// wants to consume the command buffer.
#[allow(unused_mut)] #[allow(unused_mut)]
let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) { let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) {
Ok(cmdbuf) => cmdbuf, Ok(cmdbuf) => cmdbuf,

View File

@ -15,7 +15,6 @@ pub struct RegistryReport {
pub num_allocated: usize, pub num_allocated: usize,
pub num_kept_from_user: usize, pub num_kept_from_user: usize,
pub num_released_from_user: usize, pub num_released_from_user: usize,
pub num_destroyed_from_user: usize,
pub num_error: usize, pub num_error: usize,
pub element_size: usize, pub element_size: usize,
} }
@ -192,7 +191,6 @@ impl<I: id::TypedId, T: Resource<I>> Registry<I, T> {
for element in storage.map.iter() { for element in storage.map.iter() {
match *element { match *element {
Element::Occupied(..) => report.num_kept_from_user += 1, Element::Occupied(..) => report.num_kept_from_user += 1,
Element::Destroyed(..) => report.num_destroyed_from_user += 1,
Element::Vacant => report.num_released_from_user += 1, Element::Vacant => report.num_released_from_user += 1,
Element::Error(..) => report.num_error += 1, Element::Error(..) => report.num_error += 1,
} }

View File

@ -433,6 +433,10 @@ impl<A: HalApi> Buffer<A> {
self.raw.get(guard) self.raw.get(guard)
} }
pub(crate) fn is_destroyed(&self, guard: &SnatchGuard) -> bool {
self.raw.get(guard).is_none()
}
// Note: This must not be called while holding a lock. // Note: This must not be called while holding a lock.
pub(crate) fn unmap(self: &Arc<Self>) -> Result<(), BufferAccessError> { pub(crate) fn unmap(self: &Arc<Self>) -> Result<(), BufferAccessError> {
if let Some((mut operation, status)) = self.unmap_inner()? { if let Some((mut operation, status)) = self.unmap_inner()? {
@ -818,6 +822,10 @@ impl<A: HalApi> Texture<A> {
self.inner.get(snatch_guard)?.raw() self.inner.get(snatch_guard)?.raw()
} }
pub(crate) fn is_destroyed(&self, guard: &SnatchGuard) -> bool {
self.inner.get(guard).is_none()
}
pub(crate) fn inner_mut<'a>( pub(crate) fn inner_mut<'a>(
&'a self, &'a self,
guard: &mut ExclusiveSnatchGuard, guard: &mut ExclusiveSnatchGuard,

View File

@ -14,10 +14,6 @@ pub(crate) enum Element<T> {
/// epoch. /// epoch.
Occupied(Arc<T>, Epoch), Occupied(Arc<T>, Epoch),
/// Like `Occupied`, but the resource has been marked as destroyed
/// and hasn't been dropped yet.
Destroyed(Epoch),
/// Like `Occupied`, but an error occurred when creating the /// Like `Occupied`, but an error occurred when creating the
/// resource. /// resource.
/// ///
@ -78,11 +74,9 @@ where
let (index, epoch, _) = id.unzip(); let (index, epoch, _) = id.unzip();
match self.map.get(index as usize) { match self.map.get(index as usize) {
Some(&Element::Vacant) => false, Some(&Element::Vacant) => false,
Some( Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => {
&Element::Occupied(_, storage_epoch) storage_epoch == epoch
| &Element::Destroyed(storage_epoch) }
| &Element::Error(storage_epoch, _),
) => storage_epoch == epoch,
None => false, None => false,
} }
} }
@ -99,9 +93,7 @@ where
let (result, storage_epoch) = match self.map.get(index as usize) { let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch), Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
Some(&Element::Vacant) => return Ok(None), Some(&Element::Vacant) => return Ok(None),
Some(&Element::Error(epoch, ..)) | Some(&Element::Destroyed(.., epoch)) => { Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
(Err(InvalidId), epoch)
}
None => return Err(InvalidId), None => return Err(InvalidId),
}; };
assert_eq!( assert_eq!(
@ -120,7 +112,6 @@ where
Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch), Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id), Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch), Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
Some(&Element::Destroyed(.., epoch)) => (Err(InvalidId), epoch),
None => return Err(InvalidId), None => return Err(InvalidId),
}; };
assert_eq!( assert_eq!(
@ -151,14 +142,6 @@ where
} }
match std::mem::replace(&mut self.map[index], element) { match std::mem::replace(&mut self.map[index], element) {
Element::Vacant => {} Element::Vacant => {}
Element::Destroyed(storage_epoch) => {
assert_ne!(
epoch,
storage_epoch,
"Index {index:?} of {} is already occupied",
T::TYPE
);
}
Element::Occupied(_, storage_epoch) => { Element::Occupied(_, storage_epoch) => {
assert_ne!( assert_ne!(
epoch, epoch,
@ -209,22 +192,6 @@ where
} }
} }
pub(crate) fn get_and_mark_destroyed(&mut self, id: I) -> Result<Arc<T>, InvalidId> {
let (index, epoch, _) = id.unzip();
let slot = &mut self.map[index as usize];
// borrowck dance: we have to move the element out before we can replace it
// with another variant with the same value.
if let &mut Element::Occupied(_, e) = slot {
if let Element::Occupied(value, storage_epoch) =
std::mem::replace(slot, Element::Destroyed(e))
{
debug_assert_eq!(storage_epoch, epoch);
return Ok(value);
}
}
Err(InvalidId)
}
pub(crate) fn force_replace(&mut self, id: I, value: T) { pub(crate) fn force_replace(&mut self, id: I, value: T) {
log::trace!("User is replacing {}{:?}", T::TYPE, id); log::trace!("User is replacing {}{:?}", T::TYPE, id);
let (index, epoch, _) = id.unzip(); let (index, epoch, _) = id.unzip();
@ -239,10 +206,6 @@ where
assert_eq!(epoch, storage_epoch); assert_eq!(epoch, storage_epoch);
Some(value) Some(value)
} }
Element::Destroyed(storage_epoch) => {
assert_eq!(epoch, storage_epoch);
None
}
Element::Error(..) => None, Element::Error(..) => None,
Element::Vacant => panic!("Cannot remove a vacant resource"), Element::Vacant => panic!("Cannot remove a vacant resource"),
} }