diff --git a/player/src/main.rs b/player/src/main.rs index e4638f32d5d..a0070e2ad23 100644 --- a/player/src/main.rs +++ b/player/src/main.rs @@ -486,7 +486,11 @@ fn main() { global.instance_create_surface(&window, wgc::id::TypedId::zip(0, 1, wgt::Backend::Empty)); let device = match actions.pop() { - Some(trace::Action::Init { desc, backend }) => { + Some(trace::Action::Init { + desc, + allow_unsafe, + backend, + }) => { log::info!("Initializing the device for backend: {:?}", backend); let adapter = global .pick_adapter( @@ -509,6 +513,7 @@ fn main() { gfx_select!(adapter => global.adapter_request_device( adapter, &desc, + allow_unsafe, None, wgc::id::TypedId::zip(1, 0, wgt::Backend::Empty) )) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 10024a15ad8..978ab5fe0ab 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -198,6 +198,7 @@ impl Device { hal_limits: hal::Limits, supports_texture_d24_s8: bool, desc: &wgt::DeviceDescriptor, + #[allow(unused)] allow_unsafe: wgt::UnsafeExtensions, trace_path: Option<&std::path::Path>, ) -> Self { // don't start submission index at zero @@ -243,6 +244,7 @@ impl Device { Ok(mut trace) => { trace.add(Action::Init { desc: desc.clone(), + allow_unsafe, backend: B::VARIANT, }); Some(Mutex::new(trace)) diff --git a/wgpu-core/src/device/trace.rs b/wgpu-core/src/device/trace.rs index 632136d87f1..57d13a1d066 100644 --- a/wgpu-core/src/device/trace.rs +++ b/wgpu-core/src/device/trace.rs @@ -97,6 +97,7 @@ pub struct RenderPipelineDescriptor { pub enum Action { Init { desc: wgt::DeviceDescriptor, + allow_unsafe: wgt::UnsafeExtensions, backend: wgt::Backend, }, CreateBuffer { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index bb7c6c1b81b..0d3ecfb63e6 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -10,7 +10,10 @@ use crate::{ power, LifeGuard, Stored, MAX_BIND_GROUPS, }; -use wgt::{Backend, BackendBit, DeviceDescriptor, PowerPreference, BIND_BUFFER_ALIGNMENT}; +use wgt::{ + Backend, BackendBit, DeviceDescriptor, Extensions, PowerPreference, UnsafeExtensions, + BIND_BUFFER_ALIGNMENT, +}; #[cfg(feature = "replay")] use serde::Deserialize; @@ -526,7 +529,7 @@ impl Global { AdapterInfo::from_gfx(adapter.raw.info.clone(), adapter_id.backend()) } - pub fn adapter_extensions(&self, adapter_id: AdapterId) -> wgt::Extensions { + pub fn adapter_extensions(&self, adapter_id: AdapterId) -> Extensions { let hub = B::hub(self); let mut token = Token::root(); let (adapter_guard, _) = hub.adapters.read(&mut token); @@ -552,6 +555,7 @@ impl Global { wgt::Limits { max_bind_groups: (limits.max_bound_descriptor_sets as u32).min(MAX_BIND_GROUPS as u32), + _non_exhaustive: wgt::NonExhaustive, } } @@ -579,9 +583,18 @@ impl Global { &self, adapter_id: AdapterId, desc: &DeviceDescriptor, + allow_unsafe: UnsafeExtensions, trace_path: Option<&std::path::Path>, id_in: Input, ) -> DeviceId { + if desc.extensions.contains(Extensions::UNSAFE_EXTENSIONS) { + assert!( + allow_unsafe.allowed(), + "Cannot enable unsafe extension without UnsafeExtensions::allow(). Enabled unsafe extensions: {:?}", + desc.extensions & Extensions::UNSAFE_EXTENSIONS + ); + } + let hub = B::hub(self); let mut token = Token::root(); let device = { @@ -604,10 +617,7 @@ impl Global { } // Check features needed by extensions - if desc - .extensions - .contains(wgt::Extensions::ANISOTROPIC_FILTERING) - { + if desc.extensions.contains(Extensions::ANISOTROPIC_FILTERING) { assert!( available_features.contains(hal::Features::SAMPLER_ANISOTROPY), "Missing feature SAMPLER_ANISOTROPY for anisotropic filtering extension" @@ -660,6 +670,7 @@ impl Global { limits, supports_texture_d24_s8, desc, + allow_unsafe, trace_path, ) }; diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index c34d0cfacf4..634fa80b1b1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -100,6 +100,24 @@ 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; + bitflags::bitflags! { #[repr(transparent)] #[derive(Default)] @@ -110,7 +128,33 @@ bitflags::bitflags! { /// but it is not yet implemented. /// /// https://github.com/gpuweb/gpuweb/issues/696 - const ANISOTROPIC_FILTERING = 0x01; + const ANISOTROPIC_FILTERING = 0x0000_0001_0000_0000; + /// Extensions which are part of the upstream webgpu standard + const WEBGPU_EXTENSIONS = 0x0000_0000_0000_FFFF; + /// Extensions that require activating the unsafe extension flag + const UNSAFE_EXTENSIONS = 0xFFFF_0000_0000_0000; + /// Extensions that are only available when targeting native (not web) + const NATIVE_EXTENSIONS = 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 +164,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: NonExhaustive, + } } } @@ -941,7 +989,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 +1008,7 @@ pub struct SamplerDescriptor { /// /// Valid values: 1, 2, 4, 8, and 16. pub anisotropy_clamp: Option, + pub _non_exhaustive: NonExhaustive, } impl SamplerDescriptor { @@ -976,6 +1025,7 @@ impl SamplerDescriptor { lod_max_clamp: self.lod_max_clamp, compare: self.compare, anisotropy_clamp: self.anisotropy_clamp, + _non_exhaustive: self._non_exhaustive, } } }