spq_core/ty/
mod.rs

1//! Structured representations of SPIR-V types.
2use std::fmt;
3use std::hash::Hash;
4use std::rc::Rc;
5
6pub mod reg;
7pub mod walk;
8
9pub use self::{reg::TypeRegistry, walk::Walk};
10pub use crate::spirv::{Dim, ImageFormat, StorageClass};
11
12pub trait SpirvType {
13    /// Minimum size of the type in bytes if it can be represented in-memory.
14    /// It's the size of all static members and plus one element if it's an array.
15    /// Same as [`wgpu::BindingType::Buffer::min_binding_size`](https://docs.rs/wgpu/latest/wgpu/enum.BindingType.html).
16    fn min_nbyte(&self) -> Option<usize>;
17    /// Size of the type in bytes if it can be represented in-memory.
18    fn nbyte(&self) -> Option<usize> {
19        self.min_nbyte()
20    }
21    /// Returns true if the type is sized. A sized type can be represented
22    /// in-memory. Otherwise the type can only be used as a descriptor resource.
23    fn is_sized(&self) -> bool {
24        self.nbyte().is_some()
25    }
26    /// Returns the offset of the i-th member in bytes if it's a composite type.
27    fn member_offset(&self, _member_index: usize) -> Option<usize> {
28        None
29    }
30    /// Returns how the type can be accessed: `ReadOnly`, `WriteOnly` or
31    /// `ReadWrite`.
32    fn access_ty(&self) -> Option<AccessType> {
33        None
34    }
35}
36
37#[derive(PartialEq, Eq, Hash, Clone, Debug)]
38pub enum ScalarType {
39    /// Pseudo-type representing no data. It's sometimes used to represent data
40    /// without a type hint at compile-time in SPIR-V. You shouldn't see this in
41    /// your reflection results.
42    Void,
43    /// Boolean value of either true or false. Be careful with booleans.
44    /// Booleans is NOT allowed to be exposed to the host according to the
45    /// SPIR-V specification. You shouldn't see this in your reflection results.
46    Boolean,
47    /// Two's complement integer.
48    Integer {
49        /// Number of bytes the integer takes.
50        bits: u32,
51        /// Whether the integer is signed.
52        is_signed: bool,
53    },
54    /// IEEE 754 floating-point number.
55    Float {
56        /// Number of bytes the float takes.
57        bits: u32,
58    },
59}
60impl ScalarType {
61    /// Create a signed integer type with the given number of bits.
62    pub fn int(bits: u32) -> Self {
63        Self::Integer {
64            bits,
65            is_signed: true,
66        }
67    }
68    /// Create an unsigned integer type with the given number of bits.
69    pub fn uint(bits: u32) -> Self {
70        Self::Integer {
71            bits,
72            is_signed: false,
73        }
74    }
75    /// Create a floating point type with the given number of bits.
76    pub fn float(bits: u32) -> Self {
77        Self::Float { bits }
78    }
79    /// Create a 32-bit signed integer type.
80    pub fn i32() -> Self {
81        Self::int(32)
82    }
83    /// Create a 32-bit unsigned integer type.
84    pub fn u32() -> Self {
85        Self::uint(32)
86    }
87    /// Create a 32-bit floating-point type.
88    pub fn f32() -> Self {
89        Self::float(32)
90    }
91}
92impl SpirvType for ScalarType {
93    fn min_nbyte(&self) -> Option<usize> {
94        match self {
95            Self::Void => None,
96            Self::Boolean => None,
97            Self::Integer { bits, .. } => Some((*bits / 8) as usize),
98            Self::Float { bits } => Some((*bits / 8) as usize),
99        }
100    }
101}
102impl fmt::Display for ScalarType {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        match self {
105            Self::Void => f.write_str("void"),
106            Self::Boolean => f.write_str("bool"),
107            Self::Integer { bits, is_signed } => match is_signed {
108                true => write!(f, "i{}", bits),
109                false => write!(f, "u{}", bits),
110            },
111            Self::Float { bits } => write!(f, "f{}", bits),
112        }
113    }
114}
115
116#[derive(PartialEq, Eq, Hash, Clone, Debug)]
117pub struct VectorType {
118    /// Vector scalar type.
119    pub scalar_ty: ScalarType,
120    /// Number of scalar components in the vector.
121    pub nscalar: u32,
122}
123impl SpirvType for VectorType {
124    fn min_nbyte(&self) -> Option<usize> {
125        Some(self.scalar_ty.min_nbyte()? * self.nscalar as usize)
126    }
127}
128impl fmt::Display for VectorType {
129    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130        write!(f, "vec{}<{}>", self.nscalar, self.scalar_ty)
131    }
132}
133
134#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
135pub enum MatrixAxisOrder {
136    ColumnMajor,
137    RowMajor,
138}
139impl Default for MatrixAxisOrder {
140    fn default() -> MatrixAxisOrder {
141        MatrixAxisOrder::ColumnMajor
142    }
143}
144
145#[derive(PartialEq, Eq, Hash, Clone, Debug)]
146pub struct MatrixType {
147    /// Matrix vector type.
148    pub vector_ty: VectorType,
149    /// Number of vectors in the matrix.
150    pub nvector: u32,
151    /// Axis order of the matrix. Valid SPIR-V never gives a `None` major.
152    pub axis_order: Option<MatrixAxisOrder>,
153    /// Stride between vectors in the matrix. Valid SPIR-V never gives a `None`
154    /// stride.
155    pub stride: Option<usize>,
156}
157impl SpirvType for MatrixType {
158    fn min_nbyte(&self) -> Option<usize> {
159        Some(self.stride? * self.nvector as usize)
160    }
161}
162impl fmt::Display for MatrixType {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        let major = match self.axis_order {
165            Some(MatrixAxisOrder::ColumnMajor) => "ColumnMajor",
166            Some(MatrixAxisOrder::RowMajor) => "RowMajor",
167            None => "AxisOrder?",
168        };
169        let nrow = self.vector_ty.nscalar;
170        let ncol = self.nvector;
171        let scalar_ty = &self.vector_ty.scalar_ty;
172        let stride = match self.stride {
173            Some(x) => x.to_string(),
174            None => "?".to_owned(),
175        };
176        write!(f, "mat{nrow}x{ncol}<{scalar_ty},{major},{stride}>")
177    }
178}
179
180#[derive(PartialEq, Eq, Hash, Clone, Debug)]
181pub struct ImageType {
182    /// Scalar type of image access result.
183    pub scalar_ty: ScalarType,
184    /// Dimension of the image.
185    pub dim: Dim,
186    /// Whether the image is a depth image, or `None` if it's unknown at compile
187    /// time.
188    pub is_depth: Option<bool>,
189    /// Whether the image is an array of images. In Vulkan, it means that the
190    /// image can have multiple layers. In Vulkan, only `Dim1D`, `Dim2D`, and
191    /// `DimCube` can be arrayed.
192    pub is_array: bool,
193    /// Whether the image is multisampled. In Vulkan, only 2D images and 2D
194    /// image arrays can be multi sampled.
195    pub is_multisampled: bool,
196    /// Whether the image is sampled, or `None` if it's unknown at compile time.
197    pub is_sampled: Option<bool>,
198    /// Matches `VkImageCreateInfo::format`. Can be `ImageFormat::Unknown` in
199    /// case of a sampled image.
200    pub fmt: ImageFormat,
201}
202impl SpirvType for ImageType {
203    fn min_nbyte(&self) -> Option<usize> {
204        None
205    }
206}
207impl fmt::Display for ImageType {
208    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209        let scalar_ty = &self.scalar_ty;
210        let is_sampled = match self.is_sampled {
211            Some(true) => "Sampled",
212            Some(false) => "Storage",
213            None => "Sampled?",
214        };
215        let depth = match self.is_depth {
216            Some(true) => "Depth",
217            Some(false) => "Color",
218            None => "Depth?",
219        };
220        let dim = format!("{:?}", self.dim)[3..].to_owned();
221        let is_array = match self.is_array {
222            true => "Array",
223            false => "",
224        };
225        let is_multisampled = match self.is_multisampled {
226            true => "MS",
227            false => "",
228        };
229        write!(
230            f,
231            "Image{dim}{is_array}{is_multisampled}<{scalar_ty},{is_sampled},{depth},{:?}>",
232            self.fmt
233        )
234    }
235}
236
237#[derive(PartialEq, Eq, Hash, Clone, Debug)]
238pub struct SamplerType {}
239impl SpirvType for SamplerType {
240    fn min_nbyte(&self) -> Option<usize> {
241        None
242    }
243}
244impl fmt::Display for SamplerType {
245    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246        f.write_str("Sampler")
247    }
248}
249
250#[derive(PartialEq, Eq, Hash, Clone, Debug)]
251pub struct CombinedImageSamplerType {
252    pub sampled_image_ty: SampledImageType,
253}
254impl SpirvType for CombinedImageSamplerType {
255    fn min_nbyte(&self) -> Option<usize> {
256        None
257    }
258}
259impl fmt::Display for CombinedImageSamplerType {
260    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
261        write!(f, "CombinedImageSampler<{}>", self.sampled_image_ty)
262    }
263}
264
265#[derive(PartialEq, Eq, Hash, Clone, Debug)]
266pub struct SampledImageType {
267    /// Scalar type of image access result.
268    pub scalar_ty: ScalarType,
269    /// Dimension of the image.
270    pub dim: Dim,
271    /// Whether the image is a depth image, or `None` if it's unknown at compile
272    /// time.
273    pub is_depth: Option<bool>,
274    /// Whether  the image is an array of images. In Vulkan, it means that the
275    /// image can have multiple layers. In Vulkan, only `Dim1D`, `Dim2D`, and
276    /// `DimCube` can be arrayed.
277    pub is_array: bool,
278    /// Whether the image is multisampled. In Vulkan, only 2D images and 2D
279    /// image arrays can be multi sampled.
280    pub is_multisampled: bool,
281}
282impl SpirvType for SampledImageType {
283    fn min_nbyte(&self) -> Option<usize> {
284        None
285    }
286}
287impl fmt::Display for SampledImageType {
288    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289        let scalar_ty = &self.scalar_ty;
290        let dim = format!("{:?}", self.dim)[3..].to_owned();
291        let depth = match self.is_depth {
292            Some(true) => "Depth",
293            Some(false) => "Color",
294            None => "Depth?",
295        };
296        let is_array = match self.is_array {
297            true => "Array",
298            false => "",
299        };
300        let is_multisampled = match self.is_multisampled {
301            true => "MS",
302            false => "",
303        };
304        write!(
305            f,
306            "SampledImage{dim}{is_array}{is_multisampled}<{scalar_ty},{depth}>"
307        )
308    }
309}
310
311#[derive(PartialEq, Eq, Hash, Clone, Debug)]
312pub struct StorageImageType {
313    /// Dimension of the image.
314    pub dim: Dim,
315    /// Whether  the image is an array of images. In Vulkan, it means that the
316    /// image can have multiple layers. In Vulkan, only `Dim1D`, `Dim2D`, and
317    /// `DimCube` can be arrayed.
318    pub is_array: bool,
319    /// Whether the image is multisampled. In Vulkan, only 2D images and 2D
320    /// image arrays can be multi sampled.
321    pub is_multisampled: bool,
322    /// Matches `VkImageCreateInfo::format`. Can be `ImageFormat::Unknown` in
323    /// case of a sampled image.
324    pub fmt: ImageFormat,
325}
326impl SpirvType for StorageImageType {
327    fn min_nbyte(&self) -> Option<usize> {
328        None
329    }
330}
331impl fmt::Display for StorageImageType {
332    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
333        let dim = format!("{:?}", self.dim)[3..].to_owned();
334        let is_array = match self.is_array {
335            true => "Array",
336            false => "",
337        };
338        let is_multisampled = match self.is_multisampled {
339            true => "MS",
340            false => "",
341        };
342        write!(
343            f,
344            "StorageImage{dim}{is_array}{is_multisampled}<{:?}>",
345            self.fmt
346        )
347    }
348}
349
350#[derive(PartialEq, Eq, Hash, Clone, Debug)]
351pub struct SubpassDataType {
352    /// Scalar type of subpass data access result.
353    pub scalar_ty: ScalarType,
354    /// Image arrangement which encodes multisampling state.
355    pub is_multisampled: bool,
356}
357impl SpirvType for SubpassDataType {
358    fn min_nbyte(&self) -> Option<usize> {
359        None
360    }
361}
362impl fmt::Display for SubpassDataType {
363    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
364        let scalar_ty = &self.scalar_ty;
365        let is_multisampled = match self.is_multisampled {
366            true => "MS",
367            false => "",
368        };
369        write!(f, "SubpassData{is_multisampled}<{scalar_ty}>")
370    }
371}
372
373#[derive(PartialEq, Eq, Hash, Clone, Debug)]
374pub struct ArrayType {
375    /// Type of the array element.
376    pub element_ty: Box<Type>,
377    /// Number of elements in the array. None if the array length is only known
378    /// at runtime.
379    pub nelement: Option<u32>,
380    /// Stride between elements in the array. None if the array doesn't have
381    /// a explicitly specified layout. For example, an array of descriptor
382    /// resources doesn't have a physical layout.
383    pub stride: Option<usize>,
384}
385impl SpirvType for ArrayType {
386    fn min_nbyte(&self) -> Option<usize> {
387        Some(self.stride? * self.nelement.unwrap_or(0).max(1) as usize)
388    }
389    fn nbyte(&self) -> Option<usize> {
390        Some(self.stride? * self.nelement.unwrap_or(0) as usize)
391    }
392    fn member_offset(&self, member_index: usize) -> Option<usize> {
393        Some(self.stride? * member_index)
394    }
395    fn access_ty(&self) -> Option<AccessType> {
396        self.element_ty.access_ty()
397    }
398}
399impl fmt::Display for ArrayType {
400    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
401        if let Some(nrepeat) = self.nelement {
402            write!(f, "[{}; {}]", self.element_ty, nrepeat)
403        } else {
404            write!(f, "[{}]", self.element_ty)
405        }
406    }
407}
408
409/// Access type of a variable.
410#[repr(u32)]
411#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
412pub enum AccessType {
413    /// The variable can be accessed by read.
414    ReadOnly = 1,
415    /// The variable can be accessed by write.
416    WriteOnly = 2,
417    /// The variable can be accessed by read or by write.
418    ReadWrite = 3,
419}
420impl std::ops::BitOr<AccessType> for AccessType {
421    type Output = AccessType;
422    fn bitor(self, rhs: AccessType) -> AccessType {
423        return match (self, rhs) {
424            (Self::ReadOnly, Self::ReadOnly) => Self::ReadOnly,
425            (Self::WriteOnly, Self::WriteOnly) => Self::WriteOnly,
426            _ => Self::ReadWrite,
427        };
428    }
429}
430impl std::ops::BitAnd<AccessType> for AccessType {
431    type Output = Option<AccessType>;
432    fn bitand(self, rhs: AccessType) -> Option<AccessType> {
433        return match (self, rhs) {
434            (Self::ReadOnly, Self::ReadWrite)
435            | (Self::ReadWrite, Self::ReadOnly)
436            | (Self::ReadOnly, Self::ReadOnly) => Some(Self::ReadOnly),
437            (Self::WriteOnly, Self::ReadWrite)
438            | (Self::ReadWrite, Self::WriteOnly)
439            | (Self::WriteOnly, Self::WriteOnly) => Some(Self::WriteOnly),
440            (Self::ReadWrite, Self::ReadWrite) => Some(Self::ReadWrite),
441            (_, _) => None,
442        };
443    }
444}
445
446#[derive(PartialEq, Eq, Clone, Hash, Debug)]
447pub struct StructMember {
448    pub name: Option<String>,
449    /// Offset of this member from the beginning of the struct. None if the
450    /// struct doesn't have a explicitly specified layout. For example,
451    /// `gl_PerVertex` doesn't have a physical layout. You won't see a `None` in
452    /// reflected result.
453    pub offset: Option<usize>,
454    pub ty: Type,
455    pub access_ty: AccessType,
456}
457#[derive(PartialEq, Eq, Default, Clone, Hash, Debug)]
458pub struct StructType {
459    pub name: Option<String>,
460    pub members: Vec<StructMember>, // Offset and type.
461}
462impl StructType {
463    pub fn name(&self) -> Option<&str> {
464        self.name.as_ref().map(AsRef::as_ref)
465    }
466}
467impl SpirvType for StructType {
468    fn min_nbyte(&self) -> Option<usize> {
469        let last_member = &self.members.last()?;
470        Some(last_member.offset? + last_member.ty.min_nbyte()?)
471    }
472    fn nbyte(&self) -> Option<usize> {
473        let last_member = &self.members.last()?;
474        Some(last_member.offset? + last_member.ty.nbyte()?)
475    }
476    fn member_offset(&self, member_index: usize) -> Option<usize> {
477        self.members.get(member_index).and_then(|x| x.offset)
478    }
479    fn access_ty(&self) -> Option<AccessType> {
480        self.members.iter().fold(None, |seed, x| match seed {
481            None => Some(x.access_ty),
482            Some(AccessType::ReadOnly) => match x.access_ty {
483                AccessType::ReadOnly => Some(AccessType::ReadOnly),
484                _ => Some(AccessType::ReadWrite),
485            },
486            Some(AccessType::WriteOnly) => match x.access_ty {
487                AccessType::WriteOnly => Some(AccessType::WriteOnly),
488                _ => Some(AccessType::ReadWrite),
489            },
490            Some(AccessType::ReadWrite) => Some(AccessType::ReadWrite),
491        })
492    }
493}
494impl fmt::Display for StructType {
495    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
496        if let Some(name) = &self.name {
497            write!(f, "{} {{ ", name)?;
498        } else {
499            f.write_str("{ ")?;
500        }
501        for (i, member) in self.members.iter().enumerate() {
502            if i != 0 {
503                f.write_str(", ")?;
504            }
505            if let Some(name) = &member.name {
506                write!(f, "{}: {}", name, member.ty)?;
507            } else {
508                write!(f, "{}: {}", i, member.ty)?;
509            }
510        }
511        f.write_str(" }")
512    }
513}
514
515#[derive(PartialEq, Eq, Hash, Clone, Debug)]
516pub struct AccelStructType {}
517impl SpirvType for AccelStructType {
518    fn min_nbyte(&self) -> Option<usize> {
519        None
520    }
521}
522impl fmt::Display for AccelStructType {
523    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
524        f.write_str("AccelStruct")
525    }
526}
527
528#[derive(PartialEq, Eq, Hash, Clone, Debug)]
529pub struct DeviceAddressType {}
530impl SpirvType for DeviceAddressType {
531    fn min_nbyte(&self) -> Option<usize> {
532        Some(std::mem::size_of::<u64>())
533    }
534}
535impl fmt::Display for DeviceAddressType {
536    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
537        f.write_str("Address")
538    }
539}
540
541#[derive(PartialEq, Eq, Hash, Clone, Debug)]
542pub struct PointerType {
543    pub pointee_ty: Box<Type>,
544    pub store_cls: StorageClass,
545}
546impl SpirvType for PointerType {
547    fn min_nbyte(&self) -> Option<usize> {
548        Some(std::mem::size_of::<u64>())
549    }
550    fn access_ty(&self) -> Option<AccessType> {
551        self.pointee_ty.access_ty()
552    }
553}
554impl fmt::Display for PointerType {
555    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
556        f.write_str("Pointer { ")?;
557        write!(f, "{}", *self.pointee_ty)?;
558        f.write_str(" }")
559    }
560}
561
562#[derive(PartialEq, Eq, Hash, Clone, Debug)]
563pub struct RayQueryType {}
564impl SpirvType for RayQueryType {
565    fn min_nbyte(&self) -> Option<usize> {
566        None
567    }
568}
569impl fmt::Display for RayQueryType {
570    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571        f.write_str("RayQuery")
572    }
573}
574
575macro_rules! declr_ty_accessor {
576    ([$e:ident] $($name:ident -> $ty:ident,)+) => {
577        $(
578            pub fn $name(&self) -> bool {
579                match self {
580                    $e::$ty(..) => true,
581                    _ => false
582                }
583            }
584        )+
585    }
586}
587macro_rules! declr_ty_downcast {
588    ([$e:ident] $($name:ident -> $ty:ident($inner_ty:ident),)+) => {
589        $(
590            pub fn $name(&self) -> Option<&$inner_ty> {
591                match self {
592                    $e::$ty(x) => Some(x),
593                    _ => None
594                }
595            }
596        )+
597    }
598}
599
600#[derive(PartialEq, Eq, Hash, Clone, Debug)]
601#[non_exhaustive]
602pub enum Type {
603    /// A single value, which can be a signed or unsigned integer, a floating
604    /// point number, or a boolean value.
605    Scalar(ScalarType),
606    /// A collection of scalars.
607    Vector(VectorType),
608    /// A collection of vectors.
609    Matrix(MatrixType),
610    /// An image. In most cases, this variant is elevated to
611    /// `CombinedImageSampler`, `SampledImage`, or `StorageImage` so you
612    /// shouldn't see this in your reflection results.
613    Image(ImageType),
614    /// A sampled image externally combined with a sampler state. Such design is
615    /// preferred in OpenGL and Vulkan.
616    CombinedImageSampler(CombinedImageSamplerType),
617    /// A sampled image yet to be combined with a `Sampler`. Such design is
618    /// preferred in DirectX and Vulkan.
619    SampledImage(SampledImageType),
620    /// A storage image that shaders can read and/or write.
621    StorageImage(StorageImageType),
622    /// Separable sampler state.
623    Sampler(SamplerType),
624    /// Pixel store from input attachments.
625    SubpassData(SubpassDataType),
626    /// Repetition of a single type.
627    Array(ArrayType),
628    /// Aggregation of types.
629    Struct(StructType),
630    /// Acceleration structure for ray-tracing. Only available with
631    /// `RayTracingKHR` capability enabled.
632    AccelStruct(AccelStructType),
633    /// Forward-declared pointer but the type of pointed data is unknown.
634    /// Usually used for GPU linked lists. See `VK_KHR_buffer_device_address`.
635    DeviceAddress(DeviceAddressType),
636    /// Forward-declared pointer. Usually used for bindless resources with the
637    /// `buffer_reference` extension. See `VK_KHR_buffer_device_address`.
638    DevicePointer(PointerType),
639    /// Ray query payload type (`rayQueryEXT`). Only available with `RayQueryKHR`
640    /// capability enabled.
641    RayQuery(RayQueryType),
642}
643impl Type {
644    pub fn min_nbyte(&self) -> Option<usize> {
645        match self {
646            Type::Scalar(x) => x.min_nbyte(),
647            Type::Vector(x) => x.min_nbyte(),
648            Type::Matrix(x) => x.min_nbyte(),
649            Type::Image(x) => x.min_nbyte(),
650            Type::CombinedImageSampler(x) => x.min_nbyte(),
651            Type::SampledImage(x) => x.min_nbyte(),
652            Type::StorageImage(x) => x.min_nbyte(),
653            Type::Sampler(x) => x.min_nbyte(),
654            Type::SubpassData(x) => x.min_nbyte(),
655            Type::Array(x) => x.min_nbyte(),
656            Type::Struct(x) => x.min_nbyte(),
657            Type::AccelStruct(x) => x.min_nbyte(),
658            Type::DeviceAddress(x) => x.min_nbyte(),
659            Type::DevicePointer(x) => x.min_nbyte(),
660            Type::RayQuery(x) => x.min_nbyte(),
661        }
662    }
663    pub fn nbyte(&self) -> Option<usize> {
664        match self {
665            Type::Scalar(x) => x.nbyte(),
666            Type::Vector(x) => x.nbyte(),
667            Type::Matrix(x) => x.nbyte(),
668            Type::Image(x) => x.nbyte(),
669            Type::CombinedImageSampler(x) => x.nbyte(),
670            Type::SampledImage(x) => x.nbyte(),
671            Type::StorageImage(x) => x.nbyte(),
672            Type::Sampler(x) => x.nbyte(),
673            Type::SubpassData(x) => x.nbyte(),
674            Type::Array(x) => x.nbyte(),
675            Type::Struct(x) => x.nbyte(),
676            Type::AccelStruct(x) => x.nbyte(),
677            Type::DeviceAddress(x) => x.nbyte(),
678            Type::DevicePointer(x) => x.nbyte(),
679            Type::RayQuery(x) => x.nbyte(),
680        }
681    }
682    pub fn member_offset(&self, member_index: usize) -> Option<usize> {
683        match self {
684            Type::Scalar(x) => x.member_offset(member_index),
685            Type::Vector(x) => x.member_offset(member_index),
686            Type::Matrix(x) => x.member_offset(member_index),
687            Type::Image(x) => x.member_offset(member_index),
688            Type::CombinedImageSampler(x) => x.member_offset(member_index),
689            Type::SampledImage(x) => x.member_offset(member_index),
690            Type::StorageImage(x) => x.member_offset(member_index),
691            Type::Sampler(x) => x.member_offset(member_index),
692            Type::SubpassData(x) => x.member_offset(member_index),
693            Type::Array(x) => x.member_offset(member_index),
694            Type::Struct(x) => x.member_offset(member_index),
695            Type::AccelStruct(x) => x.member_offset(member_index),
696            Type::DeviceAddress(x) => x.member_offset(member_index),
697            Type::DevicePointer(x) => x.member_offset(member_index),
698            Type::RayQuery(x) => x.member_offset(member_index),
699        }
700    }
701    pub fn access_ty(&self) -> Option<AccessType> {
702        match self {
703            Type::Scalar(x) => x.access_ty(),
704            Type::Vector(x) => x.access_ty(),
705            Type::Matrix(x) => x.access_ty(),
706            Type::Image(x) => x.access_ty(),
707            Type::CombinedImageSampler(x) => x.access_ty(),
708            Type::SampledImage(x) => x.access_ty(),
709            Type::StorageImage(x) => x.access_ty(),
710            Type::Sampler(x) => x.access_ty(),
711            Type::SubpassData(x) => x.access_ty(),
712            Type::Array(x) => x.access_ty(),
713            Type::Struct(x) => x.access_ty(),
714            Type::AccelStruct(x) => x.access_ty(),
715            Type::DeviceAddress(x) => x.access_ty(),
716            Type::DevicePointer(x) => x.access_ty(),
717            Type::RayQuery(x) => x.access_ty(),
718        }
719    }
720
721    // Iterate over all entries in the type tree.
722    pub fn walk<'a>(&'a self) -> Walk<'a> {
723        Walk::new(self)
724    }
725    declr_ty_accessor! {
726        [Type]
727        is_scalar -> Scalar,
728        is_vector -> Vector,
729        is_matrix -> Matrix,
730        is_image -> Image,
731        is_sampler -> Sampler,
732        is_combined_image_sampler -> CombinedImageSampler,
733        is_sampled_image -> SampledImage,
734        is_storage_image -> StorageImage,
735        is_subpass_data -> SubpassData,
736        is_array -> Array,
737        is_struct -> Struct,
738        is_accel_struct -> AccelStruct,
739        is_device_address -> DeviceAddress,
740        is_device_pointer -> DevicePointer,
741    }
742    declr_ty_downcast! {
743        [Type]
744        as_scalar -> Scalar(ScalarType),
745        as_vector -> Vector(VectorType),
746        as_matrix -> Matrix(MatrixType),
747        as_image -> Image(ImageType),
748        as_sampler -> Sampler(SamplerType),
749        as_combined_image_sampler -> CombinedImageSampler(CombinedImageSamplerType),
750        as_sampled_image -> SampledImage(SampledImageType),
751        as_storage_image -> StorageImage(StorageImageType),
752        as_subpass_data -> SubpassData(SubpassDataType),
753        as_array -> Array(ArrayType),
754        as_struct -> Struct(StructType),
755        as_accel_struct -> AccelStruct(AccelStructType),
756        as_device_address -> DeviceAddress(DeviceAddressType),
757        as_device_pointer -> DevicePointer(PointerType),
758    }
759    fn mutate_impl<F: Fn(Type) -> Type>(self, f: Rc<F>) -> Type {
760        use Type::*;
761        let out = match self {
762            Array(src) => {
763                let dst = ArrayType {
764                    element_ty: Box::new(src.element_ty.mutate_impl(f.clone())),
765                    nelement: src.nelement,
766                    stride: src.stride,
767                };
768                Type::Array(dst)
769            }
770            Struct(src) => {
771                let dst = StructType {
772                    name: src.name,
773                    members: src
774                        .members
775                        .into_iter()
776                        .map(|x| StructMember {
777                            name: x.name,
778                            offset: x.offset,
779                            ty: x.ty.mutate_impl(f.clone()),
780                            access_ty: x.access_ty,
781                        })
782                        .collect(),
783                };
784                Type::Struct(dst)
785            }
786            _ => self,
787        };
788        (*f)(out)
789    }
790    pub fn mutate<F: Fn(Type) -> Type>(self, f: F) -> Type {
791        self.mutate_impl(Rc::new(f))
792    }
793}
794impl fmt::Display for Type {
795    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
796        match self {
797            Type::Scalar(x) => x.fmt(f),
798            Type::Vector(x) => x.fmt(f),
799            Type::Matrix(x) => x.fmt(f),
800            Type::Image(x) => x.fmt(f),
801            Type::Sampler(x) => x.fmt(f),
802            Type::CombinedImageSampler(x) => x.fmt(f),
803            Type::SampledImage(x) => x.fmt(f),
804            Type::StorageImage(x) => x.fmt(f),
805            Type::SubpassData(x) => x.fmt(f),
806            Type::Array(x) => x.fmt(f),
807            Type::Struct(x) => x.fmt(f),
808            Type::AccelStruct(x) => x.fmt(f),
809            Type::DeviceAddress(x) => x.fmt(f),
810            Type::DevicePointer(x) => x.fmt(f),
811            Type::RayQuery(x) => x.fmt(f),
812        }
813    }
814}
815
816/// Descriptor type matching `VkDescriptorType`.
817#[derive(Debug, PartialEq, Eq, Hash, Clone)]
818pub enum DescriptorType {
819    /// `VK_DESCRIPTOR_TYPE_SAMPLER`
820    Sampler(),
821    /// `VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER`
822    CombinedImageSampler(),
823    /// `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`
824    SampledImage(),
825    /// `VK_DESCRIPTOR_TYPE_STORAGE_IMAGE`
826    StorageImage(AccessType),
827    /// `VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER`.
828    UniformTexelBuffer(),
829    /// `VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER`.
830    StorageTexelBuffer(AccessType),
831    /// `VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER` or
832    /// `VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC` depending on how you gonna
833    /// use it.
834    UniformBuffer(),
835    /// `VK_DESCRIPTOR_TYPE_STORAGE_BUFFER` or
836    /// `VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC` depending on how you gonna
837    /// use it.
838    StorageBuffer(AccessType),
839    /// `VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT` and its input attachment index.
840    InputAttachment(u32),
841    /// `VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR`
842    AccelStruct(),
843}