1use std::str::FromStr;
4
5#[cfg(feature = "naga-ext")]
6use crate::tplt::AccelerationStructureTags;
7use crate::{Error, Instance, inst::*, syntax::*};
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10pub struct StructMemberType {
11 pub name: String,
12 pub ty: Type,
13 pub size: Option<u32>,
14 pub align: Option<u32>,
15}
16
17impl StructMemberType {
18 pub fn new(name: String, ty: Type) -> Self {
19 Self {
20 name,
21 ty,
22 size: None,
23 align: None,
24 }
25 }
26}
27
28#[derive(Clone, Debug, PartialEq, Eq, Hash)]
29pub struct StructType {
30 pub name: String,
31 pub members: Vec<StructMemberType>,
32}
33
34impl From<StructType> for Type {
35 fn from(value: StructType) -> Self {
36 Self::Struct(Box::new(value))
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, Hash)]
41pub enum TextureType {
42 Sampled1D(SampledType),
44 Sampled2D(SampledType),
45 Sampled2DArray(SampledType),
46 Sampled3D(SampledType),
47 SampledCube(SampledType),
48 SampledCubeArray(SampledType),
49 Multisampled2D(SampledType),
51 DepthMultisampled2D,
52 External,
54 Storage1D(TexelFormat, AccessMode),
56 Storage2D(TexelFormat, AccessMode),
57 Storage2DArray(TexelFormat, AccessMode),
58 Storage3D(TexelFormat, AccessMode),
59 Depth2D,
61 Depth2DArray,
62 DepthCube,
63 DepthCubeArray,
64 #[cfg(feature = "naga-ext")]
65 Sampled1DArray(SampledType),
66 #[cfg(feature = "naga-ext")]
67 Storage1DArray(TexelFormat, AccessMode),
68 #[cfg(feature = "naga-ext")]
69 Multisampled2DArray(SampledType),
70}
71
72#[derive(Clone, Debug, PartialEq, Eq)]
73pub enum TextureDimensions {
74 D1,
75 D2,
76 D3,
77}
78
79impl TextureType {
80 pub fn dimensions(&self) -> TextureDimensions {
81 match self {
82 Self::Sampled1D(_) | Self::Storage1D(_, _) => TextureDimensions::D1,
83 Self::Sampled2D(_)
84 | Self::Sampled2DArray(_)
85 | Self::SampledCube(_)
86 | Self::SampledCubeArray(_)
87 | Self::Multisampled2D(_)
88 | Self::Depth2D
89 | Self::Depth2DArray
90 | Self::DepthCube
91 | Self::DepthCubeArray
92 | Self::DepthMultisampled2D
93 | Self::Storage2D(_, _)
94 | Self::Storage2DArray(_, _)
95 | Self::External => TextureDimensions::D2,
96 Self::Sampled3D(_) | Self::Storage3D(_, _) => TextureDimensions::D3,
97 #[cfg(feature = "naga-ext")]
98 Self::Sampled1DArray(_) | Self::Storage1DArray(_, _) => TextureDimensions::D1,
99 #[cfg(feature = "naga-ext")]
100 Self::Multisampled2DArray(_) => TextureDimensions::D2,
101 }
102 }
103 pub fn sampled_type(&self) -> Option<SampledType> {
104 match self {
105 TextureType::Sampled1D(st) => Some(*st),
106 TextureType::Sampled2D(st) => Some(*st),
107 TextureType::Sampled2DArray(st) => Some(*st),
108 TextureType::Sampled3D(st) => Some(*st),
109 TextureType::SampledCube(st) => Some(*st),
110 TextureType::SampledCubeArray(st) => Some(*st),
111 TextureType::Multisampled2D(st) => Some(*st),
112 TextureType::DepthMultisampled2D => None,
113 TextureType::External => None,
114 TextureType::Storage1D(_, _) => None,
115 TextureType::Storage2D(_, _) => None,
116 TextureType::Storage2DArray(_, _) => None,
117 TextureType::Storage3D(_, _) => None,
118 TextureType::Depth2D => None,
119 TextureType::Depth2DArray => None,
120 TextureType::DepthCube => None,
121 TextureType::DepthCubeArray => None,
122 #[cfg(feature = "naga-ext")]
123 TextureType::Sampled1DArray(st) => Some(*st),
124 #[cfg(feature = "naga-ext")]
125 TextureType::Storage1DArray(_, _) => None,
126 #[cfg(feature = "naga-ext")]
127 TextureType::Multisampled2DArray(st) => Some(*st),
128 }
129 }
130 pub fn channel_type(&self) -> SampledType {
131 match self {
132 TextureType::Sampled1D(st) => *st,
133 TextureType::Sampled2D(st) => *st,
134 TextureType::Sampled2DArray(st) => *st,
135 TextureType::Sampled3D(st) => *st,
136 TextureType::SampledCube(st) => *st,
137 TextureType::SampledCubeArray(st) => *st,
138 TextureType::Multisampled2D(st) => *st,
139 TextureType::DepthMultisampled2D => SampledType::F32,
140 TextureType::External => SampledType::F32,
141 TextureType::Storage1D(f, _) => f.channel_type(),
142 TextureType::Storage2D(f, _) => f.channel_type(),
143 TextureType::Storage2DArray(f, _) => f.channel_type(),
144 TextureType::Storage3D(f, _) => f.channel_type(),
145 TextureType::Depth2D => SampledType::F32,
146 TextureType::Depth2DArray => SampledType::F32,
147 TextureType::DepthCube => SampledType::F32,
148 TextureType::DepthCubeArray => SampledType::F32,
149 #[cfg(feature = "naga-ext")]
150 TextureType::Sampled1DArray(st) => *st,
151 #[cfg(feature = "naga-ext")]
152 TextureType::Storage1DArray(f, _) => f.channel_type(),
153 #[cfg(feature = "naga-ext")]
154 TextureType::Multisampled2DArray(st) => *st,
155 }
156 }
157 pub fn is_depth(&self) -> bool {
159 matches!(
160 self,
161 TextureType::Depth2D
162 | TextureType::Depth2DArray
163 | TextureType::DepthCube
164 | TextureType::DepthCubeArray
165 )
166 }
167 pub fn is_storage(&self) -> bool {
168 match self {
169 TextureType::Storage1D(_, _)
170 | TextureType::Storage2D(_, _)
171 | TextureType::Storage2DArray(_, _)
172 | TextureType::Storage3D(_, _) => true,
173 #[cfg(feature = "naga-ext")]
174 TextureType::Storage1DArray(_, _) => true,
175 _ => false,
176 }
177 }
178 pub fn is_sampled(&self) -> bool {
179 match self {
180 TextureType::Sampled1D(_)
181 | TextureType::Sampled2D(_)
182 | TextureType::Sampled2DArray(_)
183 | TextureType::Sampled3D(_)
184 | TextureType::SampledCube(_)
185 | TextureType::SampledCubeArray(_) => true,
186 #[cfg(feature = "naga-ext")]
187 TextureType::Sampled1DArray(_) => true,
188 _ => false,
189 }
190 }
191 pub fn is_arrayed(&self) -> bool {
192 match self {
193 TextureType::Sampled2DArray(_)
194 | TextureType::SampledCubeArray(_)
195 | TextureType::Storage2DArray(_, _)
196 | TextureType::Depth2DArray
197 | TextureType::DepthCubeArray => true,
198 #[cfg(feature = "naga-ext")]
199 TextureType::Sampled1DArray(_)
200 | TextureType::Storage1DArray(_, _)
201 | TextureType::Multisampled2DArray(_) => true,
202 _ => false,
203 }
204 }
205 pub fn is_multisampled(&self) -> bool {
206 match self {
207 TextureType::Multisampled2D(_) | TextureType::DepthMultisampled2D => true,
208 #[cfg(feature = "naga-ext")]
209 TextureType::Multisampled2DArray(_) => true,
210 _ => false,
211 }
212 }
213 pub fn is_cube(&self) -> bool {
214 matches!(
215 self,
216 TextureType::SampledCube(_)
217 | TextureType::SampledCubeArray(_)
218 | TextureType::DepthCube
219 | TextureType::DepthCubeArray
220 )
221 }
222}
223
224impl TryFrom<&Type> for SampledType {
225 type Error = Error;
226
227 fn try_from(value: &Type) -> Result<Self, Self::Error> {
228 match value {
229 Type::I32 => Ok(SampledType::I32),
230 Type::U32 => Ok(SampledType::U32),
231 Type::F32 => Ok(SampledType::F32),
232 _ => Err(Error::SampledType(value.clone())),
233 }
234 }
235}
236
237impl From<SampledType> for Type {
238 fn from(value: SampledType) -> Self {
239 match value {
240 SampledType::I32 => Type::I32,
241 SampledType::U32 => Type::U32,
242 SampledType::F32 => Type::F32,
243 #[cfg(feature = "naga-ext")]
244 SampledType::U64 => Type::U64,
245 }
246 }
247}
248
249#[derive(Clone, Debug, PartialEq, Eq, Hash)]
250pub enum SamplerType {
251 Sampler,
252 SamplerComparison,
253}
254
255impl FromStr for SamplerType {
256 type Err = ();
257
258 fn from_str(s: &str) -> Result<Self, Self::Err> {
259 match s {
260 "sampler" => Ok(Self::Sampler),
261 "sampler_comparison" => Ok(Self::SamplerComparison),
262 _ => Err(()),
263 }
264 }
265}
266
267#[derive(Clone, Debug, PartialEq, Eq, Hash)]
269pub enum Type {
270 Bool,
271 AbstractInt,
272 AbstractFloat,
273 I32,
274 U32,
275 F32,
276 F16,
277 Struct(Box<StructType>),
278 Array(Box<Type>, Option<usize>),
279 Vec(u8, Box<Type>),
280 Mat(u8, u8, Box<Type>),
281 Atomic(Box<Type>),
282 Ptr(AddressSpace, Box<Type>, AccessMode),
283 Ref(AddressSpace, Box<Type>, AccessMode),
284 Texture(TextureType),
285 Sampler(SamplerType),
286 Unknown,
289 #[cfg(feature = "naga-ext")]
290 I64,
291 #[cfg(feature = "naga-ext")]
292 U64,
293 #[cfg(feature = "naga-ext")]
294 F64,
295 #[cfg(feature = "naga-ext")]
296 BindingArray(Box<Type>, Option<usize>),
297 #[cfg(feature = "naga-ext")]
298 RayQuery(Option<AccelerationStructureTags>),
299 #[cfg(feature = "naga-ext")]
300 AccelerationStructure(Option<AccelerationStructureTags>),
301}
302
303impl Type {
304 pub fn is_scalar(&self) -> bool {
306 match self {
307 Type::Bool
308 | Type::AbstractInt
309 | Type::AbstractFloat
310 | Type::I32
311 | Type::U32
312 | Type::F32
313 | Type::F16 => true,
314 #[cfg(feature = "naga-ext")]
315 Type::I64 | Type::U64 | Type::F64 => true,
316 _ => false,
317 }
318 }
319
320 pub fn is_numeric(&self) -> bool {
322 match self {
323 Type::AbstractInt
324 | Type::AbstractFloat
325 | Type::I32
326 | Type::U32
327 | Type::F32
328 | Type::F16 => true,
329 #[cfg(feature = "naga-ext")]
330 Type::I64 | Type::U64 | Type::F64 => true,
331 _ => false,
332 }
333 }
334
335 pub fn is_integer(&self) -> bool {
337 match self {
338 Type::AbstractInt | Type::I32 | Type::U32 => true,
339 #[cfg(feature = "naga-ext")]
340 Type::I64 | Type::U64 => true,
341 _ => false,
342 }
343 }
344
345 pub fn is_signed(&self) -> bool {
347 match self {
348 Type::AbstractInt | Type::AbstractFloat | Type::I32 | Type::F32 | Type::F16 => true,
349 #[cfg(feature = "naga-ext")]
350 Type::I64 | Type::F64 => true,
351 _ => false,
352 }
353 }
354
355 pub fn is_float(&self) -> bool {
357 match self {
358 Type::AbstractFloat | Type::F32 | Type::F16 => true,
359 #[cfg(feature = "naga-ext")]
360 Type::F64 => true,
361 _ => false,
362 }
363 }
364
365 pub fn is_abstract(&self) -> bool {
367 match self {
368 Type::AbstractInt => true,
369 Type::AbstractFloat => true,
370 Type::Array(ty, _) | Type::Vec(_, ty) | Type::Mat(_, _, ty) => ty.is_abstract(),
371 Type::Struct(s) if s.name.starts_with("__") => {
374 s.members.iter().any(|m| m.ty.is_abstract())
375 }
376 _ => false,
377 }
378 }
379
380 pub fn is_concrete(&self) -> bool {
381 match self {
382 Type::Unknown => false,
383 _ => !self.is_abstract(),
384 }
385 }
386
387 pub fn is_storable(&self) -> bool {
389 self.is_concrete()
390 && match self {
391 Type::Bool
392 | Type::I32
393 | Type::U32
394 | Type::F32
395 | Type::F16
396 | Type::Struct(_)
397 | Type::Array(_, _)
398 | Type::Vec(_, _)
399 | Type::Mat(_, _, _)
400 | Type::Atomic(_) => true,
401 #[cfg(feature = "naga-ext")]
402 Type::I64 | Type::U64 | Type::F64 => true,
403 _ => false,
404 }
405 }
406
407 pub fn is_array(&self) -> bool {
408 matches!(self, Type::Array(_, _))
409 }
410 pub fn is_vec(&self) -> bool {
411 matches!(self, Type::Vec(_, _))
412 }
413 pub fn is_i32(&self) -> bool {
414 matches!(self, Type::I32)
415 }
416 pub fn is_u32(&self) -> bool {
417 matches!(self, Type::U32)
418 }
419 pub fn is_f32(&self) -> bool {
420 matches!(self, Type::F32)
421 }
422 #[cfg(feature = "naga-ext")]
423 pub fn is_i64(&self) -> bool {
424 matches!(self, Type::I64)
425 }
426 #[cfg(feature = "naga-ext")]
427 pub fn is_u64(&self) -> bool {
428 matches!(self, Type::U64)
429 }
430 #[cfg(feature = "naga-ext")]
431 pub fn is_f64(&self) -> bool {
432 matches!(self, Type::F64)
433 }
434 pub fn is_bool(&self) -> bool {
435 matches!(self, Type::Bool)
436 }
437 pub fn is_mat(&self) -> bool {
438 matches!(self, Type::Mat(_, _, _))
439 }
440 pub fn is_abstract_int(&self) -> bool {
441 matches!(self, Type::AbstractInt)
442 }
443
444 pub fn unwrap_atomic(self) -> Box<Type> {
445 match self {
446 Type::Atomic(ty) => ty,
447 val => panic!("called `Type::unwrap_atomic()` on a `{val}` value"),
448 }
449 }
450
451 pub fn unwrap_struct(self) -> Box<StructType> {
452 match self {
453 Type::Struct(ty) => ty,
454 val => panic!("called `Type::unwrap_struct()` on a `{val}` value"),
455 }
456 }
457
458 pub fn unwrap_vec(self) -> (u8, Box<Type>) {
459 match self {
460 Type::Vec(size, ty) => (size, ty),
461 val => panic!("called `Type::unwrap_vec()` on a `{val}` value"),
462 }
463 }
464}
465
466pub trait Ty {
467 fn ty(&self) -> Type;
469
470 fn inner_ty(&self) -> Type {
474 self.ty()
475 }
476}
477
478impl Ty for Type {
479 fn ty(&self) -> Type {
480 self.clone()
481 }
482
483 fn inner_ty(&self) -> Type {
484 match self {
485 Type::Bool => self.clone(),
486 Type::AbstractInt => self.clone(),
487 Type::AbstractFloat => self.clone(),
488 Type::I32 => self.clone(),
489 Type::U32 => self.clone(),
490 Type::F32 => self.clone(),
491 Type::F16 => self.clone(),
492 Type::Struct(_) => self.clone(),
493 Type::Array(ty, _) => ty.ty(),
494 Type::Vec(_, ty) => ty.ty(),
495 Type::Mat(_, _, ty) => ty.ty(),
496 Type::Atomic(ty) => ty.ty(),
497 Type::Ptr(_, ty, _) => ty.ty(),
498 Type::Ref(_, ty, _) => ty.ty(),
499 Type::Texture(_) => self.clone(),
500 Type::Sampler(_) => self.clone(),
501 Type::Unknown => self.clone(),
502 #[cfg(feature = "naga-ext")]
503 Type::I64 => self.clone(),
504 #[cfg(feature = "naga-ext")]
505 Type::U64 => self.clone(),
506 #[cfg(feature = "naga-ext")]
507 Type::F64 => self.clone(),
508 #[cfg(feature = "naga-ext")]
509 Type::BindingArray(ty, _) => ty.ty(),
510 #[cfg(feature = "naga-ext")]
511 Type::RayQuery(_) => self.clone(),
512 #[cfg(feature = "naga-ext")]
513 Type::AccelerationStructure(_) => self.clone(),
514 }
515 }
516}
517
518impl Ty for Instance {
519 fn ty(&self) -> Type {
520 match self {
521 Instance::Literal(l) => l.ty(),
522 Instance::Struct(s) => s.ty(),
523 Instance::Array(a) => a.ty(),
524 Instance::Vec(v) => v.ty(),
525 Instance::Mat(m) => m.ty(),
526 Instance::Ptr(p) => p.ty(),
527 Instance::Ref(r) => r.ty(),
528 Instance::Atomic(a) => a.ty(),
529 Instance::Opaque(t) => t.ty(),
530 }
531 }
532 fn inner_ty(&self) -> Type {
533 match self {
534 Instance::Literal(l) => l.inner_ty(),
535 Instance::Struct(s) => s.inner_ty(),
536 Instance::Array(a) => a.inner_ty(),
537 Instance::Vec(v) => v.inner_ty(),
538 Instance::Mat(m) => m.inner_ty(),
539 Instance::Ptr(p) => p.inner_ty(),
540 Instance::Ref(r) => r.inner_ty(),
541 Instance::Atomic(a) => a.inner_ty(),
542 Instance::Opaque(t) => t.inner_ty(),
543 }
544 }
545}
546
547impl Ty for LiteralInstance {
548 fn ty(&self) -> Type {
549 match self {
550 LiteralInstance::Bool(_) => Type::Bool,
551 LiteralInstance::AbstractInt(_) => Type::AbstractInt,
552 LiteralInstance::AbstractFloat(_) => Type::AbstractFloat,
553 LiteralInstance::I32(_) => Type::I32,
554 LiteralInstance::U32(_) => Type::U32,
555 LiteralInstance::F32(_) => Type::F32,
556 LiteralInstance::F16(_) => Type::F16,
557 #[cfg(feature = "naga-ext")]
558 LiteralInstance::I64(_) => Type::I64,
559 #[cfg(feature = "naga-ext")]
560 LiteralInstance::U64(_) => Type::U64,
561 #[cfg(feature = "naga-ext")]
562 LiteralInstance::F64(_) => Type::F64,
563 }
564 }
565}
566
567impl Ty for StructInstance {
568 fn ty(&self) -> Type {
569 self.ty.clone().into()
570 }
571}
572
573impl Ty for ArrayInstance {
574 fn ty(&self) -> Type {
575 Type::Array(
576 Box::new(self.inner_ty().clone()),
577 (!self.runtime_sized).then_some(self.n()),
578 )
579 }
580 fn inner_ty(&self) -> Type {
581 self.get(0).unwrap().ty()
582 }
583}
584
585impl Ty for VecInstance {
586 fn ty(&self) -> Type {
587 Type::Vec(self.n() as u8, Box::new(self.inner_ty()))
588 }
589 fn inner_ty(&self) -> Type {
590 self.get(0).unwrap().ty()
591 }
592}
593
594impl Ty for MatInstance {
595 fn ty(&self) -> Type {
596 Type::Mat(self.c() as u8, self.r() as u8, Box::new(self.inner_ty()))
597 }
598 fn inner_ty(&self) -> Type {
599 self.get(0, 0).unwrap().ty()
600 }
601}
602
603impl Ty for PtrInstance {
604 fn ty(&self) -> Type {
605 Type::Ptr(
606 self.ptr.space,
607 Box::new(self.ptr.ty.clone()),
608 self.ptr.access,
609 )
610 }
611}
612
613impl Ty for RefInstance {
614 fn ty(&self) -> Type {
615 Type::Ref(self.space, Box::new(self.ty.clone()), self.access)
616 }
617}
618
619impl Ty for AtomicInstance {
620 fn ty(&self) -> Type {
621 Type::Atomic(self.inner_ty().into())
622 }
623 fn inner_ty(&self) -> Type {
624 self.inner().ty()
625 }
626}