diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index e8c20477e3..1633eba9aa 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -64,6 +64,7 @@ pub struct BindGroupLayoutDescriptor { pub struct BindGroupLayout { pub(crate) raw: B::DescriptorSetLayout, pub(crate) device_id: Stored, + pub(crate) life_guard: LifeGuard, pub(crate) entries: FastHashMap, pub(crate) desc_counts: DescriptorCounts, pub(crate) dynamic_count: usize, @@ -81,7 +82,7 @@ pub struct PipelineLayout { pub(crate) raw: B::PipelineLayout, pub(crate) device_id: Stored, pub(crate) life_guard: LifeGuard, - pub(crate) bind_group_layout_ids: ArrayVec<[BindGroupLayoutId; wgt::MAX_BIND_GROUPS]>, + pub(crate) bind_group_layout_ids: ArrayVec<[Stored; wgt::MAX_BIND_GROUPS]>, } #[repr(C)] diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index baa8820228..1a545f1ff1 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -182,13 +182,13 @@ impl Global { binder.reset_expectations(pipeline_layout.bind_group_layout_ids.len()); let mut is_compatible = true; - for (index, (entry, &bgl_id)) in binder + for (index, (entry, bgl_id)) in binder .entries .iter_mut() .zip(&pipeline_layout.bind_group_layout_ids) .enumerate() { - match entry.expect_layout(bgl_id) { + match entry.expect_layout(bgl_id.value) { LayoutChange::Match(bg_id, offsets) if is_compatible => { let desc_set = bind_group_guard[bg_id].raw.raw(); unsafe { diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index b3aa0b91db..7f53f4831f 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -944,14 +944,14 @@ impl Global { .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); let mut is_compatible = true; - for (index, (entry, &bgl_id)) in state + for (index, (entry, bgl_id)) in state .binder .entries .iter_mut() .zip(&pipeline_layout.bind_group_layout_ids) .enumerate() { - match entry.expect_layout(bgl_id) { + match entry.expect_layout(bgl_id.value) { LayoutChange::Match(bg_id, offsets) if is_compatible => { let desc_set = bind_group_guard[bg_id].raw.raw(); unsafe { diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 765193adba..856e9db5e3 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -29,6 +29,7 @@ pub struct SuspectedResources { pub(crate) bind_groups: Vec, pub(crate) compute_pipelines: Vec, pub(crate) render_pipelines: Vec, + pub(crate) bind_group_layouts: Vec>, pub(crate) pipeline_layouts: Vec>, } @@ -41,6 +42,7 @@ impl SuspectedResources { self.bind_groups.clear(); self.compute_pipelines.clear(); self.render_pipelines.clear(); + self.bind_group_layouts.clear(); self.pipeline_layouts.clear(); } @@ -54,6 +56,8 @@ impl SuspectedResources { .extend_from_slice(&other.compute_pipelines); self.render_pipelines .extend_from_slice(&other.render_pipelines); + self.bind_group_layouts + .extend_from_slice(&other.bind_group_layouts); self.pipeline_layouts .extend_from_slice(&other.pipeline_layouts); } @@ -72,6 +76,7 @@ struct NonReferencedResources { desc_sets: Vec>, compute_pipes: Vec, graphics_pipes: Vec, + descriptor_set_layouts: Vec, pipeline_layouts: Vec, } @@ -86,6 +91,7 @@ impl NonReferencedResources { desc_sets: Vec::new(), compute_pipes: Vec::new(), graphics_pipes: Vec::new(), + descriptor_set_layouts: Vec::new(), pipeline_layouts: Vec::new(), } } @@ -99,6 +105,8 @@ impl NonReferencedResources { self.desc_sets.extend(other.desc_sets); self.compute_pipes.extend(other.compute_pipes); self.graphics_pipes.extend(other.graphics_pipes); + assert!(other.descriptor_set_layouts.is_empty()); + assert!(other.pipeline_layouts.is_empty()); } unsafe fn clean( @@ -145,6 +153,9 @@ impl NonReferencedResources { for raw in self.graphics_pipes.drain(..) { device.destroy_graphics_pipeline(raw); } + for raw in self.descriptor_set_layouts.drain(..) { + device.destroy_descriptor_set_layout(raw); + } for raw in self.pipeline_layouts.drain(..) { device.destroy_pipeline_layout(raw); } @@ -455,6 +466,25 @@ impl LifetimeTracker { } } + if !self.suspected_resources.bind_group_layouts.is_empty() { + let (mut guard, _) = hub.bind_group_layouts.write(token); + + for Stored { + value: id, + ref_count, + } in self.suspected_resources.bind_group_layouts.drain(..) + { + //Note: this has to happen after all the suspected pipelines are destroyed + if ref_count.load() == 1 { + #[cfg(feature = "trace")] + trace.map(|t| t.lock().add(trace::Action::DestroyBindGroupLayout(id))); + hub.bind_group_layouts.free_id(id); + let layout = guard.remove(id).unwrap(); + self.free_resources.descriptor_set_layouts.push(layout.raw); + } + } + } + if !self.suspected_resources.pipeline_layouts.is_empty() { let (mut guard, _) = hub.pipeline_layouts.write(token); diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index eacc4e8fd3..ea79773fb3 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -943,6 +943,7 @@ impl Global { value: device_id, ref_count: device.life_guard.add_ref(), }, + life_guard: LifeGuard::new(), entries: entry_map, desc_counts: raw_bindings.iter().cloned().collect(), dynamic_count: entries.iter().filter(|b| b.has_dynamic_offset).count(), @@ -958,15 +959,24 @@ impl Global { ) { let hub = B::hub(self); let mut token = Token::root(); + let (device_id, ref_count) = { + let (mut bind_group_layout_guard, _) = hub.bind_group_layouts.write(&mut token); + let layout = &mut bind_group_layout_guard[bind_group_layout_id]; + ( + layout.device_id.value, + layout.life_guard.ref_count.take().unwrap(), + ) + }; + let (device_guard, mut token) = hub.devices.read(&mut token); - let (bgl, _) = hub + device_guard[device_id] + .lock_life(&mut token) + .suspected_resources .bind_group_layouts - .unregister(bind_group_layout_id, &mut token); - unsafe { - device_guard[bgl.device_id.value] - .raw - .destroy_descriptor_set_layout(bgl.raw); - } + .push(Stored { + value: bind_group_layout_id, + ref_count, + }); } pub fn device_create_pipeline_layout( @@ -1008,7 +1018,16 @@ impl Global { ref_count: device.life_guard.add_ref(), }, life_guard: LifeGuard::new(), - bind_group_layout_ids: bind_group_layout_ids.iter().cloned().collect(), + bind_group_layout_ids: { + let (bind_group_layout_guard, _) = hub.bind_group_layouts.read(&mut token); + bind_group_layout_ids + .iter() + .map(|&id| Stored { + value: id, + ref_count: bind_group_layout_guard[id].life_guard.add_ref(), + }) + .collect() + }, }; hub.pipeline_layouts .register_identity(id_in, layout, &mut token)