From f32cb103b8afd2837aaedbda4dd9c156271050bc Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 5 Jun 2020 02:13:10 -0400 Subject: [PATCH] Implement extensions interface as described in #691 --- player/src/main.rs | 1 + wgpu-core/src/instance.rs | 79 +++++++++++++++++++++++++++------------ wgpu-types/src/lib.rs | 62 ++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 26 deletions(-) diff --git a/player/src/main.rs b/player/src/main.rs index e4638f32d5..a31df952b8 100644 --- a/player/src/main.rs +++ b/player/src/main.rs @@ -497,6 +497,7 @@ fn main() { #[cfg(not(feature = "winit"))] compatible_surface: None, }, + unsafe { wgt::UnsafeExtensions::allow() }, wgc::instance::AdapterInputs::IdSet( &[wgc::id::TypedId::zip(0, 0, backend)], |id| id.backend(), diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index bb7c6c1b81..02b2fa9260 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -118,13 +118,38 @@ pub struct Surface { #[derive(Debug)] pub struct Adapter { pub(crate) raw: hal::adapter::Adapter, + extensions: wgt::Extensions, + limits: wgt::Limits, + unsafe_extensions: wgt::UnsafeExtensions, life_guard: LifeGuard, } impl Adapter { - fn new(raw: hal::adapter::Adapter) -> Self { + fn new(raw: hal::adapter::Adapter, unsafe_extensions: wgt::UnsafeExtensions) -> Self { + let adapter_features = raw.physical_device.features(); + + let mut extensions = wgt::Extensions::default(); + extensions.set( + wgt::Extensions::ANISOTROPIC_FILTERING, + adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY), + ); + if unsafe_extensions.allowed() { + // Unsafe extensions go here + } + + let adapter_limits = raw.physical_device.limits(); + + let limits = wgt::Limits { + max_bind_groups: (adapter_limits.max_bound_descriptor_sets as u32) + .min(MAX_BIND_GROUPS as u32), + _non_exhaustive: unsafe { wgt::NonExhaustive::new() }, + }; + Adapter { raw, + extensions, + limits, + unsafe_extensions, life_guard: LifeGuard::new(), } } @@ -251,7 +276,11 @@ impl Global { self.surfaces.register_identity(id_in, surface, &mut token) } - pub fn enumerate_adapters(&self, inputs: AdapterInputs>) -> Vec { + pub fn enumerate_adapters( + &self, + unsafe_extensions: wgt::UnsafeExtensions, + inputs: AdapterInputs>, + ) -> Vec { let instance = &self.instance; let mut token = Token::root(); let mut adapters = Vec::new(); @@ -264,7 +293,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::new(raw); + let adapter = Adapter::new(raw, unsafe_extensions); log::info!("Adapter Vulkan {:?}", adapter.raw.info); adapters.push(backend::Vulkan::hub(self).adapters.register_identity( id_vulkan.clone(), @@ -279,7 +308,7 @@ impl Global { { if let Some(id_metal) = inputs.find(Backend::Metal) { for raw in instance.metal.enumerate_adapters() { - let adapter = Adapter::new(raw); + let adapter = Adapter::new(raw, unsafe_extensions); log::info!("Adapter Metal {:?}", adapter.raw.info); adapters.push(backend::Metal::hub(self).adapters.register_identity( id_metal.clone(), @@ -294,7 +323,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::new(raw); + let adapter = Adapter::new(raw, unsafe_extensions); log::info!("Adapter Dx12 {:?}", adapter.raw.info); adapters.push(backend::Dx12::hub(self).adapters.register_identity( id_dx12.clone(), @@ -307,7 +336,7 @@ impl Global { if let Some(id_dx11) = inputs.find(Backend::Dx11) { for raw in instance.dx11.enumerate_adapters() { - let adapter = Adapter::new(raw); + let adapter = Adapter::new(raw, unsafe_extensions); log::info!("Adapter Dx11 {:?}", adapter.raw.info); adapters.push(backend::Dx11::hub(self).adapters.register_identity( id_dx11.clone(), @@ -324,6 +353,7 @@ impl Global { pub fn pick_adapter( &self, desc: &RequestAdapterOptions, + unsafe_extensions: wgt::UnsafeExtensions, inputs: AdapterInputs>, ) -> Option { let instance = &self.instance; @@ -462,7 +492,7 @@ impl Global { ))] { if selected < adapters_vk.len() { - let adapter = Adapter::new(adapters_vk.swap_remove(selected)); + let adapter = Adapter::new(adapters_vk.swap_remove(selected), unsafe_extensions); log::info!("Adapter Vulkan {:?}", adapter.raw.info); let id = backend::Vulkan::hub(self).adapters.register_identity( id_vulkan.unwrap(), @@ -476,7 +506,7 @@ impl Global { #[cfg(any(target_os = "ios", target_os = "macos"))] { if selected < adapters_mtl.len() { - let adapter = Adapter::new(adapters_mtl.swap_remove(selected)); + let adapter = Adapter::new(adapters_mtl.swap_remove(selected), unsafe_extensions); log::info!("Adapter Metal {:?}", adapter.raw.info); let id = backend::Metal::hub(self).adapters.register_identity( id_metal.unwrap(), @@ -490,7 +520,7 @@ impl Global { #[cfg(windows)] { if selected < adapters_dx12.len() { - let adapter = Adapter::new(adapters_dx12.swap_remove(selected)); + let adapter = Adapter::new(adapters_dx12.swap_remove(selected), unsafe_extensions); log::info!("Adapter Dx12 {:?}", adapter.raw.info); let id = backend::Dx12::hub(self).adapters.register_identity( id_dx12.unwrap(), @@ -501,7 +531,7 @@ impl Global { } selected -= adapters_dx12.len(); if selected < adapters_dx11.len() { - let adapter = Adapter::new(adapters_dx11.swap_remove(selected)); + let adapter = Adapter::new(adapters_dx11.swap_remove(selected), unsafe_extensions); log::info!("Adapter Dx11 {:?}", adapter.raw.info); let id = backend::Dx11::hub(self).adapters.register_identity( id_dx11.unwrap(), @@ -532,14 +562,7 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); let adapter = &adapter_guard[adapter_id]; - let features = adapter.raw.physical_device.features(); - - let mut extensions = wgt::Extensions::default(); - extensions.set( - wgt::Extensions::ANISOTROPIC_FILTERING, - features.contains(hal::Features::SAMPLER_ANISOTROPY), - ); - extensions + adapter.extensions } pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits { @@ -548,11 +571,7 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); let adapter = &adapter_guard[adapter_id]; - let limits = adapter.raw.physical_device.limits(); - - wgt::Limits { - max_bind_groups: (limits.max_bound_descriptor_sets as u32).min(MAX_BIND_GROUPS as u32), - } + adapter.limits.clone() } pub fn adapter_destroy(&self, adapter_id: AdapterId) { @@ -603,6 +622,20 @@ impl Global { ); } + // Verify all extensions were exposed by the adapter + if !adapter.unsafe_extensions.allowed() { + assert!( + !desc.extensions.intersects(wgt::Extensions::ALL_UNSAFE), + "Cannot enable unsafe extensions without passing UnsafeExtensions::allow() when getting an adapter. Enabled unsafe extensions: {:?}", + desc.extensions & wgt::Extensions::ALL_UNSAFE + ) + } + assert!( + adapter.extensions.contains(desc.extensions), + "Cannot enable extensions that adapter doesn't support. Unsupported extensions: {:?}", + desc.extensions - adapter.extensions + ); + // Check features needed by extensions if desc .extensions diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index c34d0cfacf..a90cbadce6 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -100,6 +100,30 @@ impl From for BackendBit { } } +/// This type is not to be constructed by any users of wgpu. If you construct this type, any semver +/// guarantees made by wgpu are invalidated and a non-breaking change may break your code. +/// +/// If you are here trying to construct it, the solution is to use partial construction with the +/// default: +/// +/// ```ignore +/// let limits = Limits { +/// max_bind_groups: 2, +/// ..Limits::default() +/// } +/// ``` +#[doc(hidden)] +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "trace", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct NonExhaustive(()); + +impl NonExhaustive { + pub unsafe fn new() -> Self { + Self(()) + } +} + bitflags::bitflags! { #[repr(transparent)] #[derive(Default)] @@ -110,7 +134,33 @@ bitflags::bitflags! { /// but it is not yet implemented. /// /// https://github.com/gpuweb/gpuweb/issues/696 - const ANISOTROPIC_FILTERING = 0x01; + const ANISOTROPIC_FILTERING = 0x0000_0000_0001_0000; + /// Extensions which are part of the upstream webgpu standard + const ALL_WEBGPU = 0x0000_0000_0000_FFFF; + /// Extensions that require activating the unsafe extension flag + const ALL_UNSAFE = 0xFFFF_0000_0000_0000; + /// Extensions that are only available when targeting native (not web) + const ALL_NATIVE = 0xFFFF_FFFF_FFFF_0000; + } +} + +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "trace", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct UnsafeExtensions { + allow_unsafe: bool, +} +impl UnsafeExtensions { + pub unsafe fn allow() -> Self { + Self { allow_unsafe: true } + } + pub fn disallow() -> Self { + Self { + allow_unsafe: false, + } + } + pub fn allowed(self) -> bool { + self.allow_unsafe } } @@ -120,11 +170,15 @@ bitflags::bitflags! { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct Limits { pub max_bind_groups: u32, + pub _non_exhaustive: NonExhaustive, } impl Default for Limits { fn default() -> Self { - Limits { max_bind_groups: 4 } + Limits { + max_bind_groups: 4, + _non_exhaustive: unsafe { NonExhaustive::new() }, + } } } @@ -941,7 +995,7 @@ impl Default for FilterMode { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Default, Clone, Debug, PartialEq)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct SamplerDescriptor { @@ -960,6 +1014,7 @@ pub struct SamplerDescriptor { /// /// Valid values: 1, 2, 4, 8, and 16. pub anisotropy_clamp: Option, + pub _non_exhaustive: NonExhaustive, } impl SamplerDescriptor { @@ -976,6 +1031,7 @@ impl SamplerDescriptor { lod_max_clamp: self.lod_max_clamp, compare: self.compare, anisotropy_clamp: self.anisotropy_clamp, + _non_exhaustive: self._non_exhaustive, } } }