naga/front/wgsl/parse/directive/
enable_extension.rs

1//! `enable …;` extensions in WGSL.
2//!
3//! The focal point of this module is the [`EnableExtension`] API.
4
5use crate::front::wgsl::{Error, Result};
6use crate::Span;
7
8use alloc::boxed::Box;
9
10/// Tracks the status of every enable-extension known to Naga.
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub(crate) struct EnableExtensions {
13    wgpu_mesh_shader: bool,
14    wgpu_ray_query: bool,
15    wgpu_ray_query_vertex_return: bool,
16    wgpu_ray_tracing_pipelines: bool,
17    dual_source_blending: bool,
18    /// Whether `enable f16;` was written earlier in the shader module.
19    f16: bool,
20    clip_distances: bool,
21    wgpu_cooperative_matrix: bool,
22    draw_index: bool,
23    primitive_index: bool,
24}
25
26impl EnableExtensions {
27    pub(crate) const fn empty() -> Self {
28        Self {
29            wgpu_mesh_shader: false,
30            wgpu_ray_query: false,
31            wgpu_ray_query_vertex_return: false,
32            wgpu_ray_tracing_pipelines: false,
33            f16: false,
34            dual_source_blending: false,
35            clip_distances: false,
36            wgpu_cooperative_matrix: false,
37            draw_index: false,
38            primitive_index: false,
39        }
40    }
41
42    /// Add an enable-extension to the set requested by a module.
43    pub(crate) const fn add(&mut self, ext: ImplementedEnableExtension) {
44        let field = match ext {
45            ImplementedEnableExtension::WgpuMeshShader => &mut self.wgpu_mesh_shader,
46            ImplementedEnableExtension::WgpuRayQuery => &mut self.wgpu_ray_query,
47            ImplementedEnableExtension::WgpuRayQueryVertexReturn => {
48                &mut self.wgpu_ray_query_vertex_return
49            }
50            ImplementedEnableExtension::WgpuRayTracingPipeline => {
51                &mut self.wgpu_ray_tracing_pipelines
52            }
53            ImplementedEnableExtension::DualSourceBlending => &mut self.dual_source_blending,
54            ImplementedEnableExtension::F16 => &mut self.f16,
55            ImplementedEnableExtension::ClipDistances => &mut self.clip_distances,
56            ImplementedEnableExtension::WgpuCooperativeMatrix => &mut self.wgpu_cooperative_matrix,
57            ImplementedEnableExtension::DrawIndex => &mut self.draw_index,
58            ImplementedEnableExtension::PrimitiveIndex => &mut self.primitive_index,
59        };
60        *field = true;
61    }
62
63    /// Query whether an enable-extension tracked here has been requested.
64    pub(crate) const fn contains(&self, ext: ImplementedEnableExtension) -> bool {
65        match ext {
66            ImplementedEnableExtension::WgpuMeshShader => self.wgpu_mesh_shader,
67            ImplementedEnableExtension::WgpuRayQuery => self.wgpu_ray_query,
68            ImplementedEnableExtension::WgpuRayQueryVertexReturn => {
69                self.wgpu_ray_query_vertex_return
70            }
71            ImplementedEnableExtension::WgpuRayTracingPipeline => self.wgpu_ray_tracing_pipelines,
72            ImplementedEnableExtension::DualSourceBlending => self.dual_source_blending,
73            ImplementedEnableExtension::F16 => self.f16,
74            ImplementedEnableExtension::ClipDistances => self.clip_distances,
75            ImplementedEnableExtension::WgpuCooperativeMatrix => self.wgpu_cooperative_matrix,
76            ImplementedEnableExtension::DrawIndex => self.draw_index,
77            ImplementedEnableExtension::PrimitiveIndex => self.primitive_index,
78        }
79    }
80
81    pub(crate) fn require(
82        &self,
83        ext: ImplementedEnableExtension,
84        span: Span,
85    ) -> Result<'static, ()> {
86        if !self.contains(ext) {
87            Err(Box::new(Error::EnableExtensionNotEnabled {
88                span,
89                kind: ext.into(),
90            }))
91        } else {
92            Ok(())
93        }
94    }
95}
96
97impl Default for EnableExtensions {
98    fn default() -> Self {
99        Self::empty()
100    }
101}
102
103/// An enable-extension not guaranteed to be present in all environments.
104///
105/// WGSL spec.: <https://www.w3.org/TR/WGSL/#enable-extensions-sec>
106#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
107pub enum EnableExtension {
108    Implemented(ImplementedEnableExtension),
109    Unimplemented(UnimplementedEnableExtension),
110}
111
112impl From<ImplementedEnableExtension> for EnableExtension {
113    fn from(value: ImplementedEnableExtension) -> Self {
114        Self::Implemented(value)
115    }
116}
117
118impl EnableExtension {
119    const F16: &'static str = "f16";
120    const CLIP_DISTANCES: &'static str = "clip_distances";
121    const DUAL_SOURCE_BLENDING: &'static str = "dual_source_blending";
122    const MESH_SHADER: &'static str = "wgpu_mesh_shader";
123    const RAY_QUERY: &'static str = "wgpu_ray_query";
124    const RAY_QUERY_VERTEX_RETURN: &'static str = "wgpu_ray_query_vertex_return";
125    const RAY_TRACING_PIPELINE: &'static str = "wgpu_ray_tracing_pipeline";
126    const COOPERATIVE_MATRIX: &'static str = "wgpu_cooperative_matrix";
127    const SUBGROUPS: &'static str = "subgroups";
128    const PRIMITIVE_INDEX: &'static str = "primitive_index";
129    const DRAW_INDEX: &'static str = "draw_index";
130
131    /// Convert from a sentinel word in WGSL into its associated [`EnableExtension`], if possible.
132    pub(crate) fn from_ident(word: &str, span: Span) -> Result<'_, Self> {
133        Ok(match word {
134            Self::F16 => Self::Implemented(ImplementedEnableExtension::F16),
135            Self::CLIP_DISTANCES => Self::Implemented(ImplementedEnableExtension::ClipDistances),
136            Self::DUAL_SOURCE_BLENDING => {
137                Self::Implemented(ImplementedEnableExtension::DualSourceBlending)
138            }
139            Self::MESH_SHADER => Self::Implemented(ImplementedEnableExtension::WgpuMeshShader),
140            Self::RAY_QUERY => Self::Implemented(ImplementedEnableExtension::WgpuRayQuery),
141            Self::RAY_QUERY_VERTEX_RETURN => {
142                Self::Implemented(ImplementedEnableExtension::WgpuRayQueryVertexReturn)
143            }
144            Self::RAY_TRACING_PIPELINE => {
145                Self::Implemented(ImplementedEnableExtension::WgpuRayTracingPipeline)
146            }
147            Self::COOPERATIVE_MATRIX => {
148                Self::Implemented(ImplementedEnableExtension::WgpuCooperativeMatrix)
149            }
150            Self::SUBGROUPS => Self::Unimplemented(UnimplementedEnableExtension::Subgroups),
151            Self::DRAW_INDEX => Self::Implemented(ImplementedEnableExtension::DrawIndex),
152            Self::PRIMITIVE_INDEX => Self::Implemented(ImplementedEnableExtension::PrimitiveIndex),
153            _ => return Err(Box::new(Error::UnknownEnableExtension(span, word))),
154        })
155    }
156
157    /// Maps this [`EnableExtension`] into the sentinel word associated with it in WGSL.
158    pub const fn to_ident(self) -> &'static str {
159        match self {
160            Self::Implemented(kind) => match kind {
161                ImplementedEnableExtension::WgpuMeshShader => Self::MESH_SHADER,
162                ImplementedEnableExtension::WgpuRayQuery => Self::RAY_QUERY,
163                ImplementedEnableExtension::WgpuRayQueryVertexReturn => {
164                    Self::RAY_QUERY_VERTEX_RETURN
165                }
166                ImplementedEnableExtension::WgpuCooperativeMatrix => Self::COOPERATIVE_MATRIX,
167                ImplementedEnableExtension::DualSourceBlending => Self::DUAL_SOURCE_BLENDING,
168                ImplementedEnableExtension::F16 => Self::F16,
169                ImplementedEnableExtension::ClipDistances => Self::CLIP_DISTANCES,
170                ImplementedEnableExtension::DrawIndex => Self::DRAW_INDEX,
171                ImplementedEnableExtension::PrimitiveIndex => Self::PRIMITIVE_INDEX,
172                ImplementedEnableExtension::WgpuRayTracingPipeline => Self::RAY_TRACING_PIPELINE,
173            },
174            Self::Unimplemented(kind) => match kind {
175                UnimplementedEnableExtension::Subgroups => Self::SUBGROUPS,
176            },
177        }
178    }
179}
180
181/// A variant of [`EnableExtension::Implemented`].
182#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
183#[cfg_attr(test, derive(strum::VariantArray))]
184pub enum ImplementedEnableExtension {
185    /// Enables `f16`/`half` primitive support in all shader languages.
186    ///
187    /// In the WGSL standard, this corresponds to [`enable f16;`].
188    ///
189    /// [`enable f16;`]: https://www.w3.org/TR/WGSL/#extension-f16
190    F16,
191    /// Enables the `blend_src` attribute in WGSL.
192    ///
193    /// In the WGSL standard, this corresponds to [`enable dual_source_blending;`].
194    ///
195    /// [`enable dual_source_blending;`]: https://www.w3.org/TR/WGSL/#extension-dual_source_blending
196    DualSourceBlending,
197    /// Enables the `clip_distances` variable in WGSL.
198    ///
199    /// In the WGSL standard, this corresponds to [`enable clip_distances;`].
200    ///
201    /// [`enable clip_distances;`]: https://www.w3.org/TR/WGSL/#extension-clip_distances
202    ClipDistances,
203    /// Enables the `wgpu_mesh_shader` extension, native only
204    WgpuMeshShader,
205    /// Enables the `wgpu_ray_query` extension, native only.
206    WgpuRayQuery,
207    /// Enables the `wgpu_ray_query_vertex_return` extension, native only.
208    WgpuRayQueryVertexReturn,
209    /// Enables the `wgpu_ray_tracing_pipeline` extension, native only.
210    WgpuRayTracingPipeline,
211    /// Enables the `wgpu_cooperative_matrix` extension, native only.
212    WgpuCooperativeMatrix,
213    /// Enables the `draw_index` builtin. Not currently part of the WGSL spec but probably will be at some point.
214    DrawIndex,
215    /// Enables the `@builtin(primitive_index)` attribute in WGSL.
216    ///
217    /// In the WGSL standard, this corresponds to [`enable primitive-index;`].
218    ///
219    /// [`enable primitive-index;`]: https://www.w3.org/TR/WGSL/#extension-primitive_index
220    PrimitiveIndex,
221}
222
223impl ImplementedEnableExtension {
224    /// A slice of all variants of [`ImplementedEnableExtension`].
225    pub const VARIANTS: &'static [Self] = &[
226        Self::F16,
227        Self::DualSourceBlending,
228        Self::ClipDistances,
229        Self::WgpuMeshShader,
230        Self::WgpuRayQuery,
231        Self::WgpuRayQueryVertexReturn,
232        Self::WgpuRayTracingPipeline,
233        Self::WgpuCooperativeMatrix,
234        Self::DrawIndex,
235        Self::PrimitiveIndex,
236    ];
237
238    /// Returns slice of all variants of [`ImplementedEnableExtension`].
239    pub const fn all() -> &'static [Self] {
240        Self::VARIANTS
241    }
242
243    /// Returns the capability required for this enable extension.
244    pub const fn capability(self) -> crate::valid::Capabilities {
245        use crate::valid::Capabilities as C;
246        match self {
247            Self::F16 => C::SHADER_FLOAT16,
248            Self::DualSourceBlending => C::DUAL_SOURCE_BLENDING,
249            Self::ClipDistances => C::CLIP_DISTANCE,
250            Self::WgpuMeshShader => C::MESH_SHADER,
251            Self::WgpuRayQuery => C::RAY_QUERY,
252            Self::WgpuRayQueryVertexReturn => C::RAY_HIT_VERTEX_POSITION,
253            Self::WgpuCooperativeMatrix => C::COOPERATIVE_MATRIX,
254            Self::WgpuRayTracingPipeline => C::RAY_TRACING_PIPELINE,
255            Self::DrawIndex => C::DRAW_INDEX,
256            Self::PrimitiveIndex => C::PRIMITIVE_INDEX,
257        }
258    }
259}
260
261#[test]
262/// Asserts that the manual implementation of VARIANTS is the same as the derived strum version would be
263/// while still allowing strum to be a dev-only dependency
264fn test_manual_variants_array_is_correct() {
265    assert_eq!(
266        <ImplementedEnableExtension as strum::VariantArray>::VARIANTS,
267        ImplementedEnableExtension::VARIANTS
268    );
269}
270
271/// A variant of [`EnableExtension::Unimplemented`].
272#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
273pub enum UnimplementedEnableExtension {
274    /// Enables subgroup built-ins in all languages.
275    ///
276    /// In the WGSL standard, this corresponds to [`enable subgroups;`].
277    ///
278    /// [`enable subgroups;`]: https://www.w3.org/TR/WGSL/#extension-subgroups
279    Subgroups,
280}
281
282impl UnimplementedEnableExtension {
283    pub(crate) const fn tracking_issue_num(self) -> u16 {
284        match self {
285            Self::Subgroups => 5555,
286        }
287    }
288}