diff --git a/CHANGELOG.md b/CHANGELOG.md index 12aa7ce6a0..1436eccebc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -162,6 +162,7 @@ By @wumpf in [#6849](https://github.com/gfx-rs/wgpu/pull/6849). - Move raytracing alignments into HAL instead of in core. By @Vecvec in [#6563](https://github.com/gfx-rs/wgpu/pull/6563). - Allow for statically linking DXC rather than including separate `.dll` files. By @DouglasDwyer in [#6574](https://github.com/gfx-rs/wgpu/pull/6574). - `DeviceType` and `AdapterInfo` now impl `Hash` by @cwfitzgerald in [#6868](https://github.com/gfx-rs/wgpu/pull/6868) +- Add `wgsl_language_features` for obtaining available WGSL language feature by @sagudev in [#6814](https://github.com/gfx-rs/wgpu/pull/6814) #### Changes diff --git a/Cargo.lock b/Cargo.lock index 49e0517467..66bcb490c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3981,6 +3981,7 @@ name = "wgpu" version = "23.0.1" dependencies = [ "arrayvec", + "bitflags 2.6.0", "cfg_aliases 0.2.1", "document-features", "js-sys", diff --git a/naga/Cargo.toml b/naga/Cargo.toml index 0cbd0f4368..54931163c7 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -75,6 +75,7 @@ codespan-reporting = { version = "0.11.0" } rustc-hash.workspace = true indexmap.workspace = true log = "0.4" +strum.workspace = true spirv = { version = "0.3", optional = true } thiserror.workspace = true serde = { version = "1.0.217", features = ["derive"], optional = true } @@ -102,4 +103,3 @@ ron = "0.8.0" rspirv = { version = "0.11", git = "https://github.com/gfx-rs/rspirv", rev = "b969f175d5663258b4891e44b76c1544da9661ab" } serde = { workspace = true, features = ["derive"] } spirv = { version = "0.3", features = ["deserialize"] } -strum.workspace = true diff --git a/naga/src/front/wgsl/mod.rs b/naga/src/front/wgsl/mod.rs index a54fd66f0a..7c7c0ba88f 100644 --- a/naga/src/front/wgsl/mod.rs +++ b/naga/src/front/wgsl/mod.rs @@ -20,6 +20,10 @@ pub use crate::front::wgsl::error::ParseError; use crate::front::wgsl::lower::Lowerer; use crate::Scalar; +pub use crate::front::wgsl::parse::directive::language_extension::{ + ImplementedLanguageExtension, LanguageExtension, UnimplementedLanguageExtension, +}; + pub struct Frontend { parser: Parser, } diff --git a/naga/src/front/wgsl/parse/directive/language_extension.rs b/naga/src/front/wgsl/parse/directive/language_extension.rs index a80e7aae98..92980b5563 100644 --- a/naga/src/front/wgsl/parse/directive/language_extension.rs +++ b/naga/src/front/wgsl/parse/directive/language_extension.rs @@ -2,11 +2,13 @@ //! //! The focal point of this module is the [`LanguageExtension`] API. -/// A language extension not guaranteed to be present in all environments. +use strum::VariantArray; + +/// A language extension recognized by Naga, but not guaranteed to be present in all environments. /// /// WGSL spec.: #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub(crate) enum LanguageExtension { +pub enum LanguageExtension { #[allow(unused)] Implemented(ImplementedLanguageExtension), Unimplemented(UnimplementedLanguageExtension), @@ -41,7 +43,7 @@ impl LanguageExtension { /// Maps this [`LanguageExtension`] into the sentinel word associated with it in WGSL. pub const fn to_ident(self) -> &'static str { match self { - Self::Implemented(kind) => match kind {}, + Self::Implemented(kind) => kind.to_ident(), Self::Unimplemented(kind) => match kind { UnimplementedLanguageExtension::ReadOnlyAndReadWriteStorageTextures => { Self::READONLY_AND_READWRITE_STORAGE_TEXTURES @@ -61,12 +63,24 @@ impl LanguageExtension { } /// A variant of [`LanguageExtension::Implemented`]. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub(crate) enum ImplementedLanguageExtension {} +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, VariantArray)] +pub enum ImplementedLanguageExtension {} + +impl ImplementedLanguageExtension { + /// Returns slice of all variants of [`ImplementedLanguageExtension`]. + pub const fn all() -> &'static [Self] { + Self::VARIANTS + } + + /// Maps this [`ImplementedLanguageExtension`] into the sentinel word associated with it in WGSL. + pub const fn to_ident(self) -> &'static str { + match self {} + } +} /// A variant of [`LanguageExtension::Unimplemented`]. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub(crate) enum UnimplementedLanguageExtension { +pub enum UnimplementedLanguageExtension { ReadOnlyAndReadWriteStorageTextures, Packed4x8IntegerDotProduct, UnrestrictedPointerParameters, diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index ca757e122c..86a7515223 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -187,6 +187,7 @@ optional = true [dependencies] arrayvec.workspace = true +bitflags.workspace = true document-features.workspace = true log.workspace = true parking_lot.workspace = true diff --git a/wgpu/src/api/instance.rs b/wgpu/src/api/instance.rs index 4b1b6b901f..8f43d0aaa9 100644 --- a/wgpu/src/api/instance.rs +++ b/wgpu/src/api/instance.rs @@ -4,6 +4,23 @@ use crate::{dispatch::InstanceInterface, *}; use std::future::Future; +bitflags::bitflags! { + /// WGSL language extensions. + /// + /// WGSL spec.: + #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] + pub struct WgslLanguageFeatures: u32 { + /// + const ReadOnlyAndReadWriteStorageTextures = 1 << 0; + /// + const Packed4x8IntegerDotProduct = 1 << 1; + /// + const UnrestrictedPointerParameters = 1 << 2; + /// + const PointerCompositeAccess = 1 << 3; + } +} + /// Context for all other wgpu objects. Instance of wgpu. /// /// This is the first thing you create when using wgpu. @@ -385,4 +402,12 @@ impl Instance { pub fn generate_report(&self) -> Option { self.inner.as_core_opt().map(|ctx| ctx.generate_report()) } + + /// Returns set of supported WGSL language extensions supported by this instance. + /// + /// + #[cfg(feature = "wgsl")] + pub fn wgsl_language_features(&self) -> WgslLanguageFeatures { + self.inner.wgsl_language_features() + } } diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 8511aff5ed..46762a5376 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1562,6 +1562,40 @@ impl dispatch::InstanceInterface for ContextWebGpu { // Devices are automatically polled. true } + + #[cfg(feature = "wgsl")] + fn wgsl_language_features(&self) -> crate::WgslLanguageFeatures { + let mut wgsl_language_features = crate::WgslLanguageFeatures::empty(); + if let Some(gpu) = &self.gpu { + gpu.wgsl_language_features() + .keys() + .into_iter() + .map(|wlf| wlf.expect("`WgslLanguageFeatures` elements should be valid")) + .map(|wlf| { + wlf.as_string() + .expect("`WgslLanguageFeatures` should be string set") + }) + .filter_map(|wlf| match wlf.as_str() { + "readonly_and_readwrite_storage_textures" => { + Some(crate::WgslLanguageFeatures::ReadOnlyAndReadWriteStorageTextures) + } + "packed_4x8_integer_dot_product" => { + Some(crate::WgslLanguageFeatures::Packed4x8IntegerDotProduct) + } + "unrestricted_pointer_parameters" => { + Some(crate::WgslLanguageFeatures::UnrestrictedPointerParameters) + } + "pointer_composite_access" => { + Some(crate::WgslLanguageFeatures::PointerCompositeAccess) + } + _ => None, + }) + .for_each(|wlf| { + wgsl_language_features |= wlf; + }) + } + wgsl_language_features + } } impl Drop for ContextWebGpu { diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index c49c65ab42..85221cf074 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -851,6 +851,18 @@ impl dispatch::InstanceInterface for ContextWgpuCore { Err(err) => self.handle_error_fatal(err, "Instance::poll_all_devices"), } } + + #[cfg(feature = "wgsl")] + fn wgsl_language_features(&self) -> crate::WgslLanguageFeatures { + wgc::naga::front::wgsl::ImplementedLanguageExtension::all() + .iter() + .copied() + .fold( + crate::WgslLanguageFeatures::empty(), + #[allow(unreachable_code)] + |acc, wle| acc | match wle {}, + ) + } } impl dispatch::AdapterInterface for CoreAdapter { diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index 6b99664ea7..999825cf15 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -100,6 +100,9 @@ pub trait InstanceInterface: CommonTraits { ) -> Pin>; fn poll_all_devices(&self, force_wait: bool) -> bool; + + #[cfg(feature = "wgsl")] + fn wgsl_language_features(&self) -> crate::WgslLanguageFeatures; } pub trait AdapterInterface: CommonTraits {