diff --git a/CHANGELOG.md b/CHANGELOG.md index d69de7f0c9..ea3d15279a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -274,6 +274,7 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Add `Feature::SHADER_UNUSED_VERTEX_OUTPUT` to allow unused vertex shader outputs. By @Aaron1011 in [#4116](https://github.com/gfx-rs/wgpu/pull/4116). - Fix a panic in `surface_configure`. By @nical in [#4220](https://github.com/gfx-rs/wgpu/pull/4220) and [#4227](https://github.com/gfx-rs/wgpu/pull/4227) - Pipelines register their implicit layouts in error cases. By @bradwerth in [#4624](https://github.com/gfx-rs/wgpu/pull/4624) +- Better handle explicit destruction of textures and buffers. By @nical in [#4657](https://github.com/gfx-rs/wgpu/pull/4657) #### Vulkan diff --git a/tests/tests/gpu.rs b/tests/tests/gpu.rs index c10df13ed7..efa15df60c 100644 --- a/tests/tests/gpu.rs +++ b/tests/tests/gpu.rs @@ -16,6 +16,7 @@ mod device; mod encoder; mod external_texture; mod instance; +mod life_cycle; mod occlusion_query; mod partially_bounded_arrays; mod pipeline; diff --git a/tests/tests/life_cycle.rs b/tests/tests/life_cycle.rs new file mode 100644 index 0000000000..1622547bc3 --- /dev/null +++ b/tests/tests/life_cycle.rs @@ -0,0 +1,63 @@ +use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters}; + +#[gpu_test] +static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default().expect_fail(FailureCase::always())) + .run_sync(|ctx| { + let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); + + buffer.destroy(); + + buffer.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + buffer + .slice(..) + .map_async(wgpu::MapMode::Write, move |_| {}); + + buffer.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + buffer.destroy(); + + buffer.destroy(); + }); + +#[gpu_test] +static TEXTURE_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { + let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: 128, + height: 128, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, // multisampling is not supported for clear + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Snorm, + usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + + texture.destroy(); + + texture.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + texture.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + texture.destroy(); + + texture.destroy(); +}); diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index c05e25f90d..ca6b756a52 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -495,8 +495,8 @@ impl Global { log::trace!("Buffer::destroy {buffer_id:?}"); let (mut buffer_guard, _) = hub.buffers.write(&mut token); - let buffer = buffer_guard - .get_mut(buffer_id) + let mut buffer = buffer_guard + .take_and_mark_destroyed(buffer_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[buffer.device_id.value]; @@ -506,7 +506,7 @@ impl Global { | &BufferMapState::Init { .. } | &BufferMapState::Active { .. } => { - self.buffer_unmap_inner(buffer_id, buffer, device) + self.buffer_unmap_inner(buffer_id, &mut buffer, device) .unwrap_or(None) } _ => None, @@ -800,8 +800,8 @@ impl Global { let (mut device_guard, mut token) = hub.devices.write(&mut token); let (mut texture_guard, _) = hub.textures.write(&mut token); - let texture = texture_guard - .get_mut(texture_id) + let mut texture = texture_guard + .take_and_mark_destroyed(texture_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[texture.device_id.value]; diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 07387b0194..2dcec0d327 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -169,6 +169,21 @@ impl Storage { self.insert_impl(index as usize, Element::Error(epoch, label.to_string())) } + pub(crate) fn take_and_mark_destroyed(&mut self, id: I) -> Result { + let (index, epoch, _) = id.unzip(); + match std::mem::replace( + &mut self.map[index as usize], + Element::Error(epoch, String::new()), + ) { + Element::Vacant => panic!("Cannot mark a vacant resource destroyed"), + Element::Occupied(value, storage_epoch) => { + assert_eq!(epoch, storage_epoch); + Ok(value) + } + _ => Err(InvalidId), + } + } + pub(crate) fn force_replace(&mut self, id: I, value: T) { let (index, epoch, _) = id.unzip(); self.map[index as usize] = Element::Occupied(value, epoch);