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