diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 3c51e6bebd..05facd7741 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -361,7 +361,7 @@ impl Global { let (context, sample_count) = { use hal::{adapter::PhysicalDevice as _, device::Device as _}; - let limits = adapter_guard[device.adapter_id] + let limits = adapter_guard[device.adapter_id.value] .raw .physical_device .limits(); diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index f797e72a30..062f072b30 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -181,7 +181,7 @@ fn fire_map_callbacks>(callback #[derive(Debug)] pub struct Device { pub(crate) raw: B::Device, - pub(crate) adapter_id: id::AdapterId, + pub(crate) adapter_id: Stored, pub(crate) queue_group: hal::queue::QueueGroup, pub(crate) com_allocator: command::CommandAllocator, mem_allocator: Mutex>, @@ -200,7 +200,7 @@ pub struct Device { impl Device { pub(crate) fn new( raw: B::Device, - adapter_id: id::AdapterId, + adapter_id: Stored, queue_group: hal::queue::QueueGroup, mem_props: hal::adapter::MemoryProperties, non_coherent_atom_size: u64, @@ -246,18 +246,18 @@ impl Device { } } - fn lock_life<'a>( - &'a self, - _token: &mut Token<'a, Self>, - ) -> MutexGuard<'a, life::LifetimeTracker> { + fn lock_life<'this, 'token: 'this>( + &'this self, + _token: &mut Token<'token, Self>, + ) -> MutexGuard<'this, life::LifetimeTracker> { self.life_tracker.lock() } - fn maintain<'a, G: GlobalIdentityHandlerFactory>( - &'a self, + fn maintain<'this, 'token: 'this, G: GlobalIdentityHandlerFactory>( + &'this self, global: &Global, force_wait: bool, - token: &mut Token<'a, Self>, + token: &mut Token<'token, Self>, ) -> Vec { let mut life_tracker = self.lock_life(token); @@ -2003,8 +2003,13 @@ impl Global { let (caps, formats) = { let suf = B::get_surface_mut(surface); - let adapter = &adapter_guard[device.adapter_id]; - assert!(suf.supports_queue_family(&adapter.raw.queue_families[0])); + let adapter = &adapter_guard[device.adapter_id.value]; + assert!( + suf.supports_queue_family(&adapter.raw.queue_families[0]), + "Surface {:?} doesn't support queue family {:?}", + suf, + &adapter.raw.queue_families[0] + ); let formats = suf.supported_formats(&adapter.raw.physical_device); let caps = suf.capabilities(&adapter.raw.physical_device); (caps, formats) @@ -2098,9 +2103,18 @@ impl Global { pub fn device_destroy(&self, device_id: id::DeviceId) { let hub = B::hub(self); let mut token = Token::root(); - let (device, mut token) = hub.devices.unregister(device_id, &mut token); - device.maintain(self, true, &mut token); - drop(token); + let device = { + let (device, mut token) = hub.devices.unregister(device_id, &mut token); + device.maintain(self, true, &mut token); + device + }; + + // Adapter is only referenced by the device and itself. + // This isn't a robust way to destroy them, we should find a better one. + if device.adapter_id.ref_count.load() == 1 { + let (_adapter, _) = hub.adapters.unregister(device.adapter_id.value, &mut token); + } + device.dispose(); } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index a1795e1e15..41df8217f3 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -7,7 +7,7 @@ use crate::{ device::Device, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Token}, id::{AdapterId, DeviceId, SurfaceId}, - power, + power, LifeGuard, Stored, }; use wgt::{Backend, BackendBit, DeviceDescriptor, PowerPreference, BIND_BUFFER_ALIGNMENT}; @@ -120,6 +120,16 @@ pub struct Surface { #[derive(Debug)] pub struct Adapter { pub(crate) raw: hal::adapter::Adapter, + life_guard: LifeGuard, +} + +impl Adapter { + fn new(raw: hal::adapter::Adapter) -> Self { + Adapter { + raw, + life_guard: LifeGuard::new(), + } + } } /// Metadata about a backend adapter. @@ -227,7 +237,7 @@ impl Global { if let Some(ref inst) = instance.vulkan { if let Some(id_vulkan) = inputs.find(Backend::Vulkan) { for raw in inst.enumerate_adapters() { - let adapter = Adapter { raw }; + let adapter = Adapter::new(raw); log::info!("Adapter Vulkan {:?}", adapter.raw.info); adapters.push(backend::Vulkan::hub(self).adapters.register_identity( id_vulkan.clone(), @@ -242,7 +252,7 @@ impl Global { { if let Some(id_metal) = inputs.find(Backend::Metal) { for raw in instance.metal.enumerate_adapters() { - let adapter = Adapter { raw }; + let adapter = Adapter::new(raw); log::info!("Adapter Metal {:?}", adapter.raw.info); adapters.push(backend::Metal::hub(self).adapters.register_identity( id_metal.clone(), @@ -257,7 +267,7 @@ impl Global { if let Some(ref inst) = instance.dx12 { if let Some(id_dx12) = inputs.find(Backend::Dx12) { for raw in inst.enumerate_adapters() { - let adapter = Adapter { raw }; + let adapter = Adapter::new(raw); log::info!("Adapter Dx12 {:?}", adapter.raw.info); adapters.push(backend::Dx12::hub(self).adapters.register_identity( id_dx12.clone(), @@ -270,7 +280,7 @@ impl Global { if let Some(id_dx11) = inputs.find(Backend::Dx11) { for raw in instance.dx11.enumerate_adapters() { - let adapter = Adapter { raw }; + let adapter = Adapter::new(raw); log::info!("Adapter Dx11 {:?}", adapter.raw.info); adapters.push(backend::Dx11::hub(self).adapters.register_identity( id_dx11.clone(), @@ -425,9 +435,7 @@ impl Global { ))] { if selected < adapters_vk.len() { - let adapter = Adapter { - raw: adapters_vk.swap_remove(selected), - }; + let adapter = Adapter::new(adapters_vk.swap_remove(selected)); log::info!("Adapter Vulkan {:?}", adapter.raw.info); let id = backend::Vulkan::hub(self).adapters.register_identity( id_vulkan.unwrap(), @@ -441,9 +449,7 @@ impl Global { #[cfg(any(target_os = "ios", target_os = "macos"))] { if selected < adapters_mtl.len() { - let adapter = Adapter { - raw: adapters_mtl.swap_remove(selected), - }; + let adapter = Adapter::new(adapters_mtl.swap_remove(selected)); log::info!("Adapter Metal {:?}", adapter.raw.info); let id = backend::Metal::hub(self).adapters.register_identity( id_metal.unwrap(), @@ -457,9 +463,7 @@ impl Global { #[cfg(windows)] { if selected < adapters_dx12.len() { - let adapter = Adapter { - raw: adapters_dx12.swap_remove(selected), - }; + let adapter = Adapter::new(adapters_dx12.swap_remove(selected)); log::info!("Adapter Dx12 {:?}", adapter.raw.info); let id = backend::Dx12::hub(self).adapters.register_identity( id_dx12.unwrap(), @@ -470,9 +474,7 @@ impl Global { } selected -= adapters_dx12.len(); if selected < adapters_dx11.len() { - let adapter = Adapter { - raw: adapters_dx11.swap_remove(selected), - }; + let adapter = Adapter::new(adapters_dx11.swap_remove(selected)); log::info!("Adapter Dx11 {:?}", adapter.raw.info); let id = backend::Dx11::hub(self).adapters.register_identity( id_dx11.unwrap(), @@ -500,7 +502,19 @@ impl Global { pub fn adapter_destroy(&self, adapter_id: AdapterId) { let hub = B::hub(self); let mut token = Token::root(); - let (_adapter, _) = hub.adapters.unregister(adapter_id, &mut token); + let (mut guard, _) = hub.adapters.write(&mut token); + + if guard[adapter_id] + .life_guard + .ref_count + .take() + .unwrap() + .load() + == 1 + { + hub.adapters.free_id(adapter_id); + let _adapter = guard.remove(adapter_id).unwrap(); + } } } @@ -516,11 +530,12 @@ impl Global { let mut token = Token::root(); let device = { let (adapter_guard, _) = hub.adapters.read(&mut token); - let adapter = &adapter_guard[adapter_id].raw; + let adapter = &adapter_guard[adapter_id]; + let phd = &adapter.raw.physical_device; let wishful_features = hal::Features::VERTEX_STORES_AND_ATOMICS | hal::Features::FRAGMENT_STORES_AND_ATOMICS | hal::Features::NDC_Y_UP; - let enabled_features = adapter.physical_device.features() & wishful_features; + let enabled_features = adapter.raw.physical_device.features() & wishful_features; if enabled_features != wishful_features { log::warn!( "Missing features: {:?}", @@ -529,18 +544,14 @@ impl Global { } let family = adapter + .raw .queue_families .iter() .find(|family| family.queue_type().supports_graphics()) .unwrap(); - let mut gpu = unsafe { - adapter - .physical_device - .open(&[(family, &[1.0])], enabled_features) - .unwrap() - }; + let mut gpu = unsafe { phd.open(&[(family, &[1.0])], enabled_features).unwrap() }; - let limits = adapter.physical_device.limits(); + let limits = phd.limits(); assert_eq!( 0, BIND_BUFFER_ALIGNMENT % limits.min_storage_buffer_offset_alignment, @@ -560,17 +571,18 @@ impl Global { ); } - let mem_props = adapter.physical_device.memory_properties(); - - let supports_texture_d24_s8 = adapter - .physical_device + let mem_props = phd.memory_properties(); + let supports_texture_d24_s8 = phd .format_properties(Some(hal::format::Format::D24UnormS8Uint)) .optimal_tiling .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT); Device::new( gpu.device, - adapter_id, + Stored { + value: adapter_id, + ref_count: adapter.life_guard.add_ref(), + }, gpu.queue_groups.swap_remove(0), mem_props, limits.non_coherent_atom_size as u64,