Skip to main content

naga/front/wgsl/parse/
conv.rs

1use crate::front::wgsl::parse::directive::enable_extension::{
2    EnableExtensions, ImplementedEnableExtension,
3};
4use crate::front::wgsl::{Error, Result, Scalar};
5use crate::{ImageClass, ImageDimension, Span, TypeInner, VectorSize};
6
7use alloc::boxed::Box;
8
9pub fn map_address_space<'a>(
10    word: &str,
11    span: Span,
12    enable_extensions: &EnableExtensions,
13) -> Result<'a, crate::AddressSpace> {
14    match word {
15        "private" => Ok(crate::AddressSpace::Private),
16        "workgroup" => Ok(crate::AddressSpace::WorkGroup),
17        "uniform" => Ok(crate::AddressSpace::Uniform),
18        "storage" => Ok(crate::AddressSpace::Storage {
19            access: crate::StorageAccess::default(),
20        }),
21        "immediate" => Ok(crate::AddressSpace::Immediate),
22        "function" => Ok(crate::AddressSpace::Function),
23        "task_payload" => {
24            enable_extensions.require(ImplementedEnableExtension::WgpuMeshShader, span)?;
25            Ok(crate::AddressSpace::TaskPayload)
26        }
27        "ray_payload" => {
28            if enable_extensions.contains(ImplementedEnableExtension::WgpuRayTracingPipeline) {
29                Ok(crate::AddressSpace::RayPayload)
30            } else {
31                Err(Box::new(Error::EnableExtensionNotEnabled {
32                    span,
33                    kind: ImplementedEnableExtension::WgpuRayTracingPipeline.into(),
34                }))
35            }
36        }
37        "incoming_ray_payload" => {
38            if enable_extensions.contains(ImplementedEnableExtension::WgpuRayTracingPipeline) {
39                Ok(crate::AddressSpace::IncomingRayPayload)
40            } else {
41                Err(Box::new(Error::EnableExtensionNotEnabled {
42                    span,
43                    kind: ImplementedEnableExtension::WgpuRayTracingPipeline.into(),
44                }))
45            }
46        }
47        _ => Err(Box::new(Error::UnknownAddressSpace(span))),
48    }
49}
50
51pub fn map_access_mode(word: &str, span: Span) -> Result<'_, crate::StorageAccess> {
52    match word {
53        "read" => Ok(crate::StorageAccess::LOAD),
54        "write" => Ok(crate::StorageAccess::STORE),
55        "read_write" => Ok(crate::StorageAccess::LOAD | crate::StorageAccess::STORE),
56        "atomic" => Ok(crate::StorageAccess::ATOMIC
57            | crate::StorageAccess::LOAD
58            | crate::StorageAccess::STORE),
59        _ => Err(Box::new(Error::UnknownAccess(span))),
60    }
61}
62
63pub fn map_ray_flag(
64    enable_extensions: &EnableExtensions,
65    word: &str,
66    span: Span,
67) -> Result<'static, ()> {
68    match word {
69        "vertex_return" => {
70            if !enable_extensions.contains(ImplementedEnableExtension::WgpuRayQueryVertexReturn) {
71                return Err(Box::new(Error::EnableExtensionNotEnabled {
72                    span,
73                    kind: ImplementedEnableExtension::WgpuRayQueryVertexReturn.into(),
74                }));
75            }
76            Ok(())
77        }
78        _ => Err(Box::new(Error::UnknownRayFlag(span))),
79    }
80}
81
82pub fn map_cooperative_role(word: &str, span: Span) -> Result<'_, crate::CooperativeRole> {
83    match word {
84        "A" => Ok(crate::CooperativeRole::A),
85        "B" => Ok(crate::CooperativeRole::B),
86        "C" => Ok(crate::CooperativeRole::C),
87        _ => Err(Box::new(Error::UnknownAccess(span))),
88    }
89}
90
91pub fn map_built_in(
92    enable_extensions: &EnableExtensions,
93    word: &str,
94    span: Span,
95) -> Result<'static, crate::BuiltIn> {
96    let built_in = match word {
97        "position" => crate::BuiltIn::Position { invariant: false },
98        // vertex
99        "vertex_index" => crate::BuiltIn::VertexIndex,
100        "instance_index" => crate::BuiltIn::InstanceIndex,
101        "view_index" => crate::BuiltIn::ViewIndex,
102        "clip_distances" => crate::BuiltIn::ClipDistances,
103        // fragment
104        "front_facing" => crate::BuiltIn::FrontFacing,
105        "frag_depth" => crate::BuiltIn::FragDepth,
106        "primitive_index" => crate::BuiltIn::PrimitiveIndex,
107        "draw_index" => crate::BuiltIn::DrawIndex,
108        "barycentric" => crate::BuiltIn::Barycentric { perspective: true },
109        "barycentric_no_perspective" => crate::BuiltIn::Barycentric { perspective: false },
110        "sample_index" => crate::BuiltIn::SampleIndex,
111        "sample_mask" => crate::BuiltIn::SampleMask,
112        // compute
113        "global_invocation_id" => crate::BuiltIn::GlobalInvocationId,
114        "local_invocation_id" => crate::BuiltIn::LocalInvocationId,
115        "local_invocation_index" => crate::BuiltIn::LocalInvocationIndex,
116        "workgroup_id" => crate::BuiltIn::WorkGroupId,
117        "num_workgroups" => crate::BuiltIn::NumWorkGroups,
118        // subgroup
119        "num_subgroups" => crate::BuiltIn::NumSubgroups,
120        "subgroup_id" => crate::BuiltIn::SubgroupId,
121        "subgroup_size" => crate::BuiltIn::SubgroupSize,
122        "subgroup_invocation_id" => crate::BuiltIn::SubgroupInvocationId,
123        // mesh
124        "cull_primitive" => crate::BuiltIn::CullPrimitive,
125        "point_index" => crate::BuiltIn::PointIndex,
126        "line_indices" => crate::BuiltIn::LineIndices,
127        "triangle_indices" => crate::BuiltIn::TriangleIndices,
128        "mesh_task_size" => crate::BuiltIn::MeshTaskSize,
129        // mesh global variable
130        "vertex_count" => crate::BuiltIn::VertexCount,
131        "vertices" => crate::BuiltIn::Vertices,
132        "primitive_count" => crate::BuiltIn::PrimitiveCount,
133        "primitives" => crate::BuiltIn::Primitives,
134        // ray tracing pipeline
135        "ray_invocation_id" => crate::BuiltIn::RayInvocationId,
136        "num_ray_invocations" => crate::BuiltIn::NumRayInvocations,
137        "instance_custom_data" => crate::BuiltIn::InstanceCustomData,
138        "geometry_index" => crate::BuiltIn::GeometryIndex,
139        "world_ray_origin" => crate::BuiltIn::WorldRayOrigin,
140        "world_ray_direction" => crate::BuiltIn::WorldRayDirection,
141        "object_ray_origin" => crate::BuiltIn::ObjectRayOrigin,
142        "object_ray_direction" => crate::BuiltIn::ObjectRayDirection,
143        "ray_t_min" => crate::BuiltIn::RayTmin,
144        "ray_t_current_max" => crate::BuiltIn::RayTCurrentMax,
145        "object_to_world" => crate::BuiltIn::ObjectToWorld,
146        "world_to_object" => crate::BuiltIn::WorldToObject,
147        "hit_kind" => crate::BuiltIn::HitKind,
148        "hit_barycentrics" => crate::BuiltIn::HitBarycentrics,
149        _ => return Err(Box::new(Error::UnknownBuiltin(span))),
150    };
151    match built_in {
152        crate::BuiltIn::ClipDistances => {
153            enable_extensions.require(ImplementedEnableExtension::ClipDistances, span)?
154        }
155        crate::BuiltIn::PrimitiveIndex => {
156            enable_extensions.require(ImplementedEnableExtension::PrimitiveIndex, span)?
157        }
158        crate::BuiltIn::DrawIndex => {
159            enable_extensions.require(ImplementedEnableExtension::DrawIndex, span)?
160        }
161        crate::BuiltIn::CullPrimitive
162        | crate::BuiltIn::PointIndex
163        | crate::BuiltIn::LineIndices
164        | crate::BuiltIn::TriangleIndices
165        | crate::BuiltIn::VertexCount
166        | crate::BuiltIn::Vertices
167        | crate::BuiltIn::PrimitiveCount
168        | crate::BuiltIn::Primitives => {
169            enable_extensions.require(ImplementedEnableExtension::WgpuMeshShader, span)?
170        }
171        _ => {}
172    }
173    Ok(built_in)
174}
175
176pub fn map_interpolation(
177    enable_extensions: &EnableExtensions,
178    word: &str,
179    span: Span,
180) -> Result<'static, crate::Interpolation> {
181    match word {
182        "linear" => Ok(crate::Interpolation::Linear),
183        "flat" => Ok(crate::Interpolation::Flat),
184        "perspective" => Ok(crate::Interpolation::Perspective),
185        "per_vertex" => {
186            enable_extensions.require(ImplementedEnableExtension::WgpuPerVertex, span)?;
187            Ok(crate::Interpolation::PerVertex)
188        }
189        _ => Err(Box::new(Error::UnknownAttribute(span))),
190    }
191}
192
193pub fn map_sampling(word: &str, span: Span) -> Result<'_, crate::Sampling> {
194    match word {
195        "center" => Ok(crate::Sampling::Center),
196        "centroid" => Ok(crate::Sampling::Centroid),
197        "sample" => Ok(crate::Sampling::Sample),
198        "first" => Ok(crate::Sampling::First),
199        "either" => Ok(crate::Sampling::Either),
200        _ => Err(Box::new(Error::UnknownAttribute(span))),
201    }
202}
203
204pub fn map_storage_format(word: &str, span: Span) -> Result<'_, crate::StorageFormat> {
205    use crate::StorageFormat as Sf;
206    Ok(match word {
207        "r8unorm" => Sf::R8Unorm,
208        "r8snorm" => Sf::R8Snorm,
209        "r8uint" => Sf::R8Uint,
210        "r8sint" => Sf::R8Sint,
211        "r16unorm" => Sf::R16Unorm,
212        "r16snorm" => Sf::R16Snorm,
213        "r16uint" => Sf::R16Uint,
214        "r16sint" => Sf::R16Sint,
215        "r16float" => Sf::R16Float,
216        "rg8unorm" => Sf::Rg8Unorm,
217        "rg8snorm" => Sf::Rg8Snorm,
218        "rg8uint" => Sf::Rg8Uint,
219        "rg8sint" => Sf::Rg8Sint,
220        "r32uint" => Sf::R32Uint,
221        "r32sint" => Sf::R32Sint,
222        "r32float" => Sf::R32Float,
223        "rg16unorm" => Sf::Rg16Unorm,
224        "rg16snorm" => Sf::Rg16Snorm,
225        "rg16uint" => Sf::Rg16Uint,
226        "rg16sint" => Sf::Rg16Sint,
227        "rg16float" => Sf::Rg16Float,
228        "rgba8unorm" => Sf::Rgba8Unorm,
229        "rgba8snorm" => Sf::Rgba8Snorm,
230        "rgba8uint" => Sf::Rgba8Uint,
231        "rgba8sint" => Sf::Rgba8Sint,
232        "rgb10a2uint" => Sf::Rgb10a2Uint,
233        "rgb10a2unorm" => Sf::Rgb10a2Unorm,
234        "rg11b10ufloat" => Sf::Rg11b10Ufloat,
235        "r64uint" => Sf::R64Uint,
236        "rg32uint" => Sf::Rg32Uint,
237        "rg32sint" => Sf::Rg32Sint,
238        "rg32float" => Sf::Rg32Float,
239        "rgba16unorm" => Sf::Rgba16Unorm,
240        "rgba16snorm" => Sf::Rgba16Snorm,
241        "rgba16uint" => Sf::Rgba16Uint,
242        "rgba16sint" => Sf::Rgba16Sint,
243        "rgba16float" => Sf::Rgba16Float,
244        "rgba32uint" => Sf::Rgba32Uint,
245        "rgba32sint" => Sf::Rgba32Sint,
246        "rgba32float" => Sf::Rgba32Float,
247        "bgra8unorm" => Sf::Bgra8Unorm,
248        _ => return Err(Box::new(Error::UnknownStorageFormat(span))),
249    })
250}
251
252pub fn map_derivative(word: &str) -> Option<(crate::DerivativeAxis, crate::DerivativeControl)> {
253    use crate::{DerivativeAxis as Axis, DerivativeControl as Ctrl};
254    match word {
255        "dpdxCoarse" => Some((Axis::X, Ctrl::Coarse)),
256        "dpdyCoarse" => Some((Axis::Y, Ctrl::Coarse)),
257        "fwidthCoarse" => Some((Axis::Width, Ctrl::Coarse)),
258        "dpdxFine" => Some((Axis::X, Ctrl::Fine)),
259        "dpdyFine" => Some((Axis::Y, Ctrl::Fine)),
260        "fwidthFine" => Some((Axis::Width, Ctrl::Fine)),
261        "dpdx" => Some((Axis::X, Ctrl::None)),
262        "dpdy" => Some((Axis::Y, Ctrl::None)),
263        "fwidth" => Some((Axis::Width, Ctrl::None)),
264        _ => None,
265    }
266}
267
268pub fn map_relational_fun(word: &str) -> Option<crate::RelationalFunction> {
269    match word {
270        "any" => Some(crate::RelationalFunction::Any),
271        "all" => Some(crate::RelationalFunction::All),
272        _ => None,
273    }
274}
275
276pub fn map_standard_fun(word: &str) -> Option<crate::MathFunction> {
277    use crate::MathFunction as Mf;
278    Some(match word {
279        // comparison
280        "abs" => Mf::Abs,
281        "min" => Mf::Min,
282        "max" => Mf::Max,
283        "clamp" => Mf::Clamp,
284        "saturate" => Mf::Saturate,
285        // trigonometry
286        "cos" => Mf::Cos,
287        "cosh" => Mf::Cosh,
288        "sin" => Mf::Sin,
289        "sinh" => Mf::Sinh,
290        "tan" => Mf::Tan,
291        "tanh" => Mf::Tanh,
292        "acos" => Mf::Acos,
293        "acosh" => Mf::Acosh,
294        "asin" => Mf::Asin,
295        "asinh" => Mf::Asinh,
296        "atan" => Mf::Atan,
297        "atanh" => Mf::Atanh,
298        "atan2" => Mf::Atan2,
299        "radians" => Mf::Radians,
300        "degrees" => Mf::Degrees,
301        // decomposition
302        "ceil" => Mf::Ceil,
303        "floor" => Mf::Floor,
304        "round" => Mf::Round,
305        "fract" => Mf::Fract,
306        "trunc" => Mf::Trunc,
307        "modf" => Mf::Modf,
308        "frexp" => Mf::Frexp,
309        "ldexp" => Mf::Ldexp,
310        // exponent
311        "exp" => Mf::Exp,
312        "exp2" => Mf::Exp2,
313        "log" => Mf::Log,
314        "log2" => Mf::Log2,
315        "pow" => Mf::Pow,
316        // geometry
317        "dot" => Mf::Dot,
318        "dot4I8Packed" => Mf::Dot4I8Packed,
319        "dot4U8Packed" => Mf::Dot4U8Packed,
320        "cross" => Mf::Cross,
321        "distance" => Mf::Distance,
322        "length" => Mf::Length,
323        "normalize" => Mf::Normalize,
324        "faceForward" => Mf::FaceForward,
325        "reflect" => Mf::Reflect,
326        "refract" => Mf::Refract,
327        // computational
328        "sign" => Mf::Sign,
329        "fma" => Mf::Fma,
330        "mix" => Mf::Mix,
331        "step" => Mf::Step,
332        "smoothstep" => Mf::SmoothStep,
333        "sqrt" => Mf::Sqrt,
334        "inverseSqrt" => Mf::InverseSqrt,
335        "transpose" => Mf::Transpose,
336        "determinant" => Mf::Determinant,
337        "quantizeToF16" => Mf::QuantizeToF16,
338        // bits
339        "countTrailingZeros" => Mf::CountTrailingZeros,
340        "countLeadingZeros" => Mf::CountLeadingZeros,
341        "countOneBits" => Mf::CountOneBits,
342        "reverseBits" => Mf::ReverseBits,
343        "extractBits" => Mf::ExtractBits,
344        "insertBits" => Mf::InsertBits,
345        "firstTrailingBit" => Mf::FirstTrailingBit,
346        "firstLeadingBit" => Mf::FirstLeadingBit,
347        // data packing
348        "pack4x8snorm" => Mf::Pack4x8snorm,
349        "pack4x8unorm" => Mf::Pack4x8unorm,
350        "pack2x16snorm" => Mf::Pack2x16snorm,
351        "pack2x16unorm" => Mf::Pack2x16unorm,
352        "pack2x16float" => Mf::Pack2x16float,
353        "pack4xI8" => Mf::Pack4xI8,
354        "pack4xU8" => Mf::Pack4xU8,
355        "pack4xI8Clamp" => Mf::Pack4xI8Clamp,
356        "pack4xU8Clamp" => Mf::Pack4xU8Clamp,
357        // data unpacking
358        "unpack4x8snorm" => Mf::Unpack4x8snorm,
359        "unpack4x8unorm" => Mf::Unpack4x8unorm,
360        "unpack2x16snorm" => Mf::Unpack2x16snorm,
361        "unpack2x16unorm" => Mf::Unpack2x16unorm,
362        "unpack2x16float" => Mf::Unpack2x16float,
363        "unpack4xI8" => Mf::Unpack4xI8,
364        "unpack4xU8" => Mf::Unpack4xU8,
365        _ => return None,
366    })
367}
368
369pub fn map_conservative_depth(word: &str, span: Span) -> Result<'_, crate::ConservativeDepth> {
370    use crate::ConservativeDepth as Cd;
371    match word {
372        "greater_equal" => Ok(Cd::GreaterEqual),
373        "less_equal" => Ok(Cd::LessEqual),
374        "unchanged" => Ok(Cd::Unchanged),
375        _ => Err(Box::new(Error::UnknownConservativeDepth(span))),
376    }
377}
378
379pub fn map_subgroup_operation(
380    word: &str,
381) -> Option<(crate::SubgroupOperation, crate::CollectiveOperation)> {
382    use crate::CollectiveOperation as co;
383    use crate::SubgroupOperation as sg;
384    Some(match word {
385        "subgroupAll" => (sg::All, co::Reduce),
386        "subgroupAny" => (sg::Any, co::Reduce),
387        "subgroupAdd" => (sg::Add, co::Reduce),
388        "subgroupMul" => (sg::Mul, co::Reduce),
389        "subgroupMin" => (sg::Min, co::Reduce),
390        "subgroupMax" => (sg::Max, co::Reduce),
391        "subgroupAnd" => (sg::And, co::Reduce),
392        "subgroupOr" => (sg::Or, co::Reduce),
393        "subgroupXor" => (sg::Xor, co::Reduce),
394        "subgroupExclusiveAdd" => (sg::Add, co::ExclusiveScan),
395        "subgroupExclusiveMul" => (sg::Mul, co::ExclusiveScan),
396        "subgroupInclusiveAdd" => (sg::Add, co::InclusiveScan),
397        "subgroupInclusiveMul" => (sg::Mul, co::InclusiveScan),
398        _ => return None,
399    })
400}
401
402pub enum TypeGenerator {
403    Vector {
404        size: VectorSize,
405    },
406    Matrix {
407        columns: VectorSize,
408        rows: VectorSize,
409    },
410    Array,
411    Atomic,
412    Pointer,
413    SampledTexture {
414        dim: ImageDimension,
415        arrayed: bool,
416        multi: bool,
417    },
418    StorageTexture {
419        dim: ImageDimension,
420        arrayed: bool,
421    },
422    BindingArray,
423    AccelerationStructure,
424    RayQuery,
425    CooperativeMatrix {
426        columns: crate::CooperativeSize,
427        rows: crate::CooperativeSize,
428    },
429}
430
431pub enum PredeclaredType {
432    TypeInner(TypeInner),
433    RayDesc,
434    RayIntersection,
435    TypeGenerator(TypeGenerator),
436}
437impl From<TypeInner> for PredeclaredType {
438    fn from(value: TypeInner) -> Self {
439        Self::TypeInner(value)
440    }
441}
442impl From<TypeGenerator> for PredeclaredType {
443    fn from(value: TypeGenerator) -> Self {
444        Self::TypeGenerator(value)
445    }
446}
447
448pub fn map_predeclared_type(
449    enable_extensions: &EnableExtensions,
450    span: Span,
451    word: &str,
452) -> Result<'static, Option<PredeclaredType>> {
453    use Scalar as Sc;
454    use TypeInner as Ti;
455    use VectorSize as Vs;
456
457    #[rustfmt::skip]
458    let ty = match word {
459        // predeclared types
460
461        // scalars
462        "bool" => Ti::Scalar(Sc::BOOL).into(),
463        "i32" => Ti::Scalar(Sc::I32).into(),
464        "u32" => Ti::Scalar(Sc::U32).into(),
465        "f32" => Ti::Scalar(Sc::F32).into(),
466        "i16" => Ti::Scalar(Sc::I16).into(),
467        "u16" => Ti::Scalar(Sc::U16).into(),
468        "f16" => Ti::Scalar(Sc::F16).into(),
469        "i64" => Ti::Scalar(Sc::I64).into(),
470        "u64" => Ti::Scalar(Sc::U64).into(),
471        "f64" => Ti::Scalar(Sc::F64).into(),
472        // vector aliases
473        "vec2i" => Ti::Vector { size: Vs::Bi,   scalar: Sc::I32 }.into(),
474        "vec3i" => Ti::Vector { size: Vs::Tri,  scalar: Sc::I32 }.into(),
475        "vec4i" => Ti::Vector { size: Vs::Quad, scalar: Sc::I32 }.into(),
476        "vec2u" => Ti::Vector { size: Vs::Bi,   scalar: Sc::U32 }.into(),
477        "vec3u" => Ti::Vector { size: Vs::Tri,  scalar: Sc::U32 }.into(),
478        "vec4u" => Ti::Vector { size: Vs::Quad, scalar: Sc::U32 }.into(),
479        "vec2f" => Ti::Vector { size: Vs::Bi,   scalar: Sc::F32 }.into(),
480        "vec3f" => Ti::Vector { size: Vs::Tri,  scalar: Sc::F32 }.into(),
481        "vec4f" => Ti::Vector { size: Vs::Quad, scalar: Sc::F32 }.into(),
482        "vec2h" => Ti::Vector { size: Vs::Bi,   scalar: Sc::F16 }.into(),
483        "vec3h" => Ti::Vector { size: Vs::Tri,  scalar: Sc::F16 }.into(),
484        "vec4h" => Ti::Vector { size: Vs::Quad, scalar: Sc::F16 }.into(),
485        // matrix aliases
486        "mat2x2f" => Ti::Matrix { columns: Vs::Bi,   rows: Vs::Bi,   scalar: Sc::F32 }.into(),
487        "mat2x3f" => Ti::Matrix { columns: Vs::Bi,   rows: Vs::Tri,  scalar: Sc::F32 }.into(),
488        "mat2x4f" => Ti::Matrix { columns: Vs::Bi,   rows: Vs::Quad, scalar: Sc::F32 }.into(),
489        "mat3x2f" => Ti::Matrix { columns: Vs::Tri,  rows: Vs::Bi,   scalar: Sc::F32 }.into(),
490        "mat3x3f" => Ti::Matrix { columns: Vs::Tri,  rows: Vs::Tri,  scalar: Sc::F32 }.into(),
491        "mat3x4f" => Ti::Matrix { columns: Vs::Tri,  rows: Vs::Quad, scalar: Sc::F32 }.into(),
492        "mat4x2f" => Ti::Matrix { columns: Vs::Quad, rows: Vs::Bi,   scalar: Sc::F32 }.into(),
493        "mat4x3f" => Ti::Matrix { columns: Vs::Quad, rows: Vs::Tri,  scalar: Sc::F32 }.into(),
494        "mat4x4f" => Ti::Matrix { columns: Vs::Quad, rows: Vs::Quad, scalar: Sc::F32 }.into(),
495        "mat2x2h" => Ti::Matrix { columns: Vs::Bi,   rows: Vs::Bi,   scalar: Sc::F16 }.into(),
496        "mat2x3h" => Ti::Matrix { columns: Vs::Bi,   rows: Vs::Tri,  scalar: Sc::F16 }.into(),
497        "mat2x4h" => Ti::Matrix { columns: Vs::Bi,   rows: Vs::Quad, scalar: Sc::F16 }.into(),
498        "mat3x2h" => Ti::Matrix { columns: Vs::Tri,  rows: Vs::Bi,   scalar: Sc::F16 }.into(),
499        "mat3x3h" => Ti::Matrix { columns: Vs::Tri,  rows: Vs::Tri,  scalar: Sc::F16 }.into(),
500        "mat3x4h" => Ti::Matrix { columns: Vs::Tri,  rows: Vs::Quad, scalar: Sc::F16 }.into(),
501        "mat4x2h" => Ti::Matrix { columns: Vs::Quad, rows: Vs::Bi,   scalar: Sc::F16 }.into(),
502        "mat4x3h" => Ti::Matrix { columns: Vs::Quad, rows: Vs::Tri,  scalar: Sc::F16 }.into(),
503        "mat4x4h" => Ti::Matrix { columns: Vs::Quad, rows: Vs::Quad, scalar: Sc::F16 }.into(),
504        // samplers
505        "sampler" =>            Ti::Sampler { comparison: false }.into(),
506        "sampler_comparison" => Ti::Sampler { comparison: true }.into(),
507        // depth textures
508        "texture_depth_2d" =>              Ti::Image { dim: ImageDimension::D2,   arrayed: false, class: ImageClass::Depth { multi: false } }.into(),
509        "texture_depth_2d_array" =>        Ti::Image { dim: ImageDimension::D2,   arrayed: true,  class: ImageClass::Depth { multi: false } }.into(),
510        "texture_depth_cube" =>            Ti::Image { dim: ImageDimension::Cube, arrayed: false, class: ImageClass::Depth { multi: false } }.into(),
511        "texture_depth_cube_array" =>      Ti::Image { dim: ImageDimension::Cube, arrayed: true,  class: ImageClass::Depth { multi: false } }.into(),
512        "texture_depth_multisampled_2d" => Ti::Image { dim: ImageDimension::D2,   arrayed: false, class: ImageClass::Depth { multi: true  } }.into(),
513        // external texture
514        "texture_external" => Ti::Image { dim: ImageDimension::D2, arrayed: false, class: ImageClass::External }.into(),
515        // ray desc
516        "RayDesc" => PredeclaredType::RayDesc,
517        // ray intersection
518        "RayIntersection" => PredeclaredType::RayIntersection,
519
520        // predeclared type generators
521
522        // vector
523        "vec2" => TypeGenerator::Vector { size: Vs::Bi   }.into(),
524        "vec3" => TypeGenerator::Vector { size: Vs::Tri  }.into(),
525        "vec4" => TypeGenerator::Vector { size: Vs::Quad }.into(),
526        // matrix
527        "mat2x2" => TypeGenerator::Matrix { columns: Vs::Bi,   rows: Vs::Bi   }.into(),
528        "mat2x3" => TypeGenerator::Matrix { columns: Vs::Bi,   rows: Vs::Tri  }.into(),
529        "mat2x4" => TypeGenerator::Matrix { columns: Vs::Bi,   rows: Vs::Quad }.into(),
530        "mat3x2" => TypeGenerator::Matrix { columns: Vs::Tri,  rows: Vs::Bi   }.into(),
531        "mat3x3" => TypeGenerator::Matrix { columns: Vs::Tri,  rows: Vs::Tri  }.into(),
532        "mat3x4" => TypeGenerator::Matrix { columns: Vs::Tri,  rows: Vs::Quad }.into(),
533        "mat4x2" => TypeGenerator::Matrix { columns: Vs::Quad, rows: Vs::Bi   }.into(),
534        "mat4x3" => TypeGenerator::Matrix { columns: Vs::Quad, rows: Vs::Tri  }.into(),
535        "mat4x4" => TypeGenerator::Matrix { columns: Vs::Quad, rows: Vs::Quad }.into(),
536        // array
537        "array" => TypeGenerator::Array.into(),
538        // atomic
539        "atomic" => TypeGenerator::Atomic.into(),
540        // pointer
541        "ptr" => TypeGenerator::Pointer.into(),
542        // sampled textures
543        "texture_1d" =>               TypeGenerator::SampledTexture { dim: ImageDimension::D1,   arrayed: false, multi: false }.into(),
544        "texture_2d" =>               TypeGenerator::SampledTexture { dim: ImageDimension::D2,   arrayed: false, multi: false }.into(),
545        "texture_2d_array" =>         TypeGenerator::SampledTexture { dim: ImageDimension::D2,   arrayed: true,  multi: false }.into(),
546        "texture_3d" =>               TypeGenerator::SampledTexture { dim: ImageDimension::D3,   arrayed: false, multi: false }.into(),
547        "texture_cube" =>             TypeGenerator::SampledTexture { dim: ImageDimension::Cube, arrayed: false, multi: false }.into(),
548        "texture_cube_array" =>       TypeGenerator::SampledTexture { dim: ImageDimension::Cube, arrayed: true,  multi: false }.into(),
549        "texture_multisampled_2d" =>  TypeGenerator::SampledTexture { dim: ImageDimension::D2,   arrayed: false, multi: true  }.into(),
550        // storage textures
551        "texture_storage_1d" =>       TypeGenerator::StorageTexture { dim: ImageDimension::D1,   arrayed: false }.into(),
552        "texture_storage_2d" =>       TypeGenerator::StorageTexture { dim: ImageDimension::D2,   arrayed: false }.into(),
553        "texture_storage_2d_array" => TypeGenerator::StorageTexture { dim: ImageDimension::D2,   arrayed: true  }.into(),
554        "texture_storage_3d" =>       TypeGenerator::StorageTexture { dim: ImageDimension::D3,   arrayed: false }.into(),
555        // binding array
556        "binding_array" => TypeGenerator::BindingArray.into(),
557        // acceleration structure
558        "acceleration_structure" => TypeGenerator::AccelerationStructure.into(),
559        // ray query
560        "ray_query" => TypeGenerator::RayQuery.into(),
561        // cooperative matrix
562        "coop_mat8x8" => TypeGenerator::CooperativeMatrix {
563            columns: crate::CooperativeSize::Eight,
564            rows: crate::CooperativeSize::Eight,
565        }.into(),
566        "coop_mat16x16" => TypeGenerator::CooperativeMatrix {
567            columns: crate::CooperativeSize::Sixteen,
568            rows: crate::CooperativeSize::Sixteen,
569        }.into(),
570        _ => return Ok(None),
571    };
572
573    // Check for the enable extension required to use this type, if any.
574    // Slice should be at least len one otherwise extension_needed should be None.
575    let extensions_needed: Option<&[_]> = match ty {
576        PredeclaredType::TypeInner(ref ty) if ty.scalar() == Some(Sc::F16) => {
577            Some(&[ImplementedEnableExtension::F16])
578        }
579        PredeclaredType::TypeInner(ref ty) if matches!(ty.scalar(), Some(s) if s == Sc::I16 || s == Sc::U16) => {
580            Some(&[ImplementedEnableExtension::WgpuInt16])
581        }
582        PredeclaredType::RayDesc
583        | PredeclaredType::RayIntersection
584        | PredeclaredType::TypeGenerator(TypeGenerator::AccelerationStructure)
585        | PredeclaredType::TypeGenerator(TypeGenerator::RayQuery) => Some(&[
586            ImplementedEnableExtension::WgpuRayQuery,
587            ImplementedEnableExtension::WgpuRayTracingPipeline,
588        ]),
589        PredeclaredType::TypeGenerator(TypeGenerator::CooperativeMatrix { .. }) => {
590            Some(&[ImplementedEnableExtension::WgpuCooperativeMatrix])
591        }
592        PredeclaredType::TypeGenerator(TypeGenerator::BindingArray) => {
593            Some(&[ImplementedEnableExtension::WgpuBindingArray])
594        }
595        _ => None,
596    };
597    if let Some(extensions_needed) = extensions_needed {
598        let mut any_extension_enabled = false;
599        for extension_needed in extensions_needed {
600            if enable_extensions.contains(*extension_needed) {
601                any_extension_enabled = true;
602            }
603        }
604        if !any_extension_enabled {
605            return Err(Box::new(Error::EnableExtensionNotEnabled {
606                span,
607                kind: extensions_needed[0].into(),
608            }));
609        }
610    }
611
612    Ok(Some(ty))
613}