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