Skip to main content

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