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)]
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)]
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)]
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 _ => false,
372 }
373 }
374
375 pub fn is_concrete(&self) -> bool {
376 match self {
377 Type::Unknown => false,
378 _ => !self.is_abstract(),
379 }
380 }
381
382 pub fn is_storable(&self) -> bool {
384 self.is_concrete()
385 && match self {
386 Type::Bool
387 | Type::I32
388 | Type::U32
389 | Type::F32
390 | Type::F16
391 | Type::Struct(_)
392 | Type::Array(_, _)
393 | Type::Vec(_, _)
394 | Type::Mat(_, _, _)
395 | Type::Atomic(_) => true,
396 #[cfg(feature = "naga-ext")]
397 Type::I64 | Type::U64 | Type::F64 => true,
398 _ => false,
399 }
400 }
401
402 pub fn is_array(&self) -> bool {
403 matches!(self, Type::Array(_, _))
404 }
405 pub fn is_vec(&self) -> bool {
406 matches!(self, Type::Vec(_, _))
407 }
408 pub fn is_i32(&self) -> bool {
409 matches!(self, Type::I32)
410 }
411 pub fn is_u32(&self) -> bool {
412 matches!(self, Type::U32)
413 }
414 pub fn is_f32(&self) -> bool {
415 matches!(self, Type::F32)
416 }
417 #[cfg(feature = "naga-ext")]
418 pub fn is_i64(&self) -> bool {
419 matches!(self, Type::I64)
420 }
421 #[cfg(feature = "naga-ext")]
422 pub fn is_u64(&self) -> bool {
423 matches!(self, Type::U64)
424 }
425 #[cfg(feature = "naga-ext")]
426 pub fn is_f64(&self) -> bool {
427 matches!(self, Type::F64)
428 }
429 pub fn is_bool(&self) -> bool {
430 matches!(self, Type::Bool)
431 }
432 pub fn is_mat(&self) -> bool {
433 matches!(self, Type::Mat(_, _, _))
434 }
435 pub fn is_abstract_int(&self) -> bool {
436 matches!(self, Type::AbstractInt)
437 }
438
439 pub fn unwrap_atomic(self) -> Box<Type> {
440 match self {
441 Type::Atomic(ty) => ty,
442 val => panic!("called `Type::unwrap_atomic()` on a `{val}` value"),
443 }
444 }
445
446 pub fn unwrap_struct(self) -> Box<StructType> {
447 match self {
448 Type::Struct(ty) => ty,
449 val => panic!("called `Type::unwrap_struct()` on a `{val}` value"),
450 }
451 }
452
453 pub fn unwrap_vec(self) -> (u8, Box<Type>) {
454 match self {
455 Type::Vec(size, ty) => (size, ty),
456 val => panic!("called `Type::unwrap_vec()` on a `{val}` value"),
457 }
458 }
459}
460
461pub trait Ty {
462 fn ty(&self) -> Type;
464
465 fn inner_ty(&self) -> Type {
469 self.ty()
470 }
471}
472
473impl Ty for Type {
474 fn ty(&self) -> Type {
475 self.clone()
476 }
477
478 fn inner_ty(&self) -> Type {
479 match self {
480 Type::Bool => self.clone(),
481 Type::AbstractInt => self.clone(),
482 Type::AbstractFloat => self.clone(),
483 Type::I32 => self.clone(),
484 Type::U32 => self.clone(),
485 Type::F32 => self.clone(),
486 Type::F16 => self.clone(),
487 Type::Struct(_) => self.clone(),
488 Type::Array(ty, _) => ty.ty(),
489 Type::Vec(_, ty) => ty.ty(),
490 Type::Mat(_, _, ty) => ty.ty(),
491 Type::Atomic(ty) => ty.ty(),
492 Type::Ptr(_, ty, _) => ty.ty(),
493 Type::Ref(_, ty, _) => ty.ty(),
494 Type::Texture(_) => self.clone(),
495 Type::Sampler(_) => self.clone(),
496 Type::Unknown => self.clone(),
497 #[cfg(feature = "naga-ext")]
498 Type::I64 => self.clone(),
499 #[cfg(feature = "naga-ext")]
500 Type::U64 => self.clone(),
501 #[cfg(feature = "naga-ext")]
502 Type::F64 => self.clone(),
503 #[cfg(feature = "naga-ext")]
504 Type::BindingArray(ty, _) => ty.ty(),
505 #[cfg(feature = "naga-ext")]
506 Type::RayQuery(_) => self.clone(),
507 #[cfg(feature = "naga-ext")]
508 Type::AccelerationStructure(_) => self.clone(),
509 }
510 }
511}
512
513impl Ty for Instance {
514 fn ty(&self) -> Type {
515 match self {
516 Instance::Literal(l) => l.ty(),
517 Instance::Struct(s) => s.ty(),
518 Instance::Array(a) => a.ty(),
519 Instance::Vec(v) => v.ty(),
520 Instance::Mat(m) => m.ty(),
521 Instance::Ptr(p) => p.ty(),
522 Instance::Ref(r) => r.ty(),
523 Instance::Atomic(a) => a.ty(),
524 Instance::Deferred(t) => t.ty(),
525 }
526 }
527 fn inner_ty(&self) -> Type {
528 match self {
529 Instance::Literal(l) => l.inner_ty(),
530 Instance::Struct(s) => s.inner_ty(),
531 Instance::Array(a) => a.inner_ty(),
532 Instance::Vec(v) => v.inner_ty(),
533 Instance::Mat(m) => m.inner_ty(),
534 Instance::Ptr(p) => p.inner_ty(),
535 Instance::Ref(r) => r.inner_ty(),
536 Instance::Atomic(a) => a.inner_ty(),
537 Instance::Deferred(t) => t.inner_ty(),
538 }
539 }
540}
541
542impl Ty for LiteralInstance {
543 fn ty(&self) -> Type {
544 match self {
545 LiteralInstance::Bool(_) => Type::Bool,
546 LiteralInstance::AbstractInt(_) => Type::AbstractInt,
547 LiteralInstance::AbstractFloat(_) => Type::AbstractFloat,
548 LiteralInstance::I32(_) => Type::I32,
549 LiteralInstance::U32(_) => Type::U32,
550 LiteralInstance::F32(_) => Type::F32,
551 LiteralInstance::F16(_) => Type::F16,
552 #[cfg(feature = "naga-ext")]
553 LiteralInstance::I64(_) => Type::I64,
554 #[cfg(feature = "naga-ext")]
555 LiteralInstance::U64(_) => Type::U64,
556 #[cfg(feature = "naga-ext")]
557 LiteralInstance::F64(_) => Type::F64,
558 }
559 }
560}
561
562impl Ty for StructInstance {
563 fn ty(&self) -> Type {
564 self.ty.clone().into()
565 }
566}
567
568impl Ty for ArrayInstance {
569 fn ty(&self) -> Type {
570 Type::Array(
571 Box::new(self.inner_ty().clone()),
572 (!self.runtime_sized).then_some(self.n()),
573 )
574 }
575 fn inner_ty(&self) -> Type {
576 self.get(0).unwrap().ty()
577 }
578}
579
580impl Ty for VecInstance {
581 fn ty(&self) -> Type {
582 Type::Vec(self.n() as u8, Box::new(self.inner_ty()))
583 }
584 fn inner_ty(&self) -> Type {
585 self.get(0).unwrap().ty()
586 }
587}
588
589impl Ty for MatInstance {
590 fn ty(&self) -> Type {
591 Type::Mat(self.c() as u8, self.r() as u8, Box::new(self.inner_ty()))
592 }
593 fn inner_ty(&self) -> Type {
594 self.get(0, 0).unwrap().ty()
595 }
596}
597
598impl Ty for PtrInstance {
599 fn ty(&self) -> Type {
600 Type::Ptr(
601 self.ptr.space,
602 Box::new(self.ptr.ty.clone()),
603 self.ptr.access,
604 )
605 }
606}
607
608impl Ty for RefInstance {
609 fn ty(&self) -> Type {
610 Type::Ref(self.space, Box::new(self.ty.clone()), self.access)
611 }
612}
613
614impl Ty for AtomicInstance {
615 fn ty(&self) -> Type {
616 Type::Atomic(self.inner_ty().into())
617 }
618 fn inner_ty(&self) -> Type {
619 self.inner().ty()
620 }
621}