1use crate::error;
2use crate::Compiler;
3use spirv::StorageClass;
4use spirv_cross_sys::{BaseType, SpvId, VariableId};
5
6use crate::error::{SpirvCrossError, ToContextError};
7use crate::handle::Handle;
8use crate::handle::{ConstantId, TypeId};
9use crate::sealed::Sealed;
10use crate::string::CompilerStr;
11use spirv_cross_sys as sys;
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq)]
15#[repr(u8)]
16pub enum ScalarKind {
17 Int = 0,
19 Uint = 1,
21 Float = 2,
23 Bool = 3,
25}
26
27#[derive(Debug, Copy, Clone, Eq, PartialEq)]
29#[repr(u8)]
30pub enum BitWidth {
31 Bit = 1,
33 Byte = 8,
35 HalfWord = 16,
37 Word = 32,
39 DoubleWord = 64,
41}
42
43impl BitWidth {
44 pub const fn byte_size(&self) -> usize {
48 match self {
49 BitWidth::Bit => 1,
50 BitWidth::Byte => 1,
51 BitWidth::HalfWord => 2,
52 BitWidth::Word => 4,
53 BitWidth::DoubleWord => 8,
54 }
55 }
56}
57
58#[derive(Debug, Clone, Eq, PartialEq)]
60pub struct Scalar {
61 pub kind: ScalarKind,
63 pub size: BitWidth,
65}
66
67impl TryFrom<BaseType> for Scalar {
68 type Error = SpirvCrossError;
69
70 fn try_from(value: BaseType) -> Result<Self, Self::Error> {
71 Ok(match value {
72 BaseType::Boolean => Scalar {
73 kind: ScalarKind::Bool,
74 size: BitWidth::Bit,
75 },
76 BaseType::Int8 => Scalar {
77 kind: ScalarKind::Int,
78 size: BitWidth::Byte,
79 },
80 BaseType::Int16 => Scalar {
81 kind: ScalarKind::Int,
82 size: BitWidth::HalfWord,
83 },
84 BaseType::Int32 => Scalar {
85 kind: ScalarKind::Int,
86 size: BitWidth::Word,
87 },
88 BaseType::Int64 => Scalar {
89 kind: ScalarKind::Int,
90 size: BitWidth::DoubleWord,
91 },
92 BaseType::Uint8 => Scalar {
93 kind: ScalarKind::Uint,
94 size: BitWidth::Byte,
95 },
96 BaseType::Uint16 => Scalar {
97 kind: ScalarKind::Uint,
98 size: BitWidth::HalfWord,
99 },
100 BaseType::Uint32 => Scalar {
101 kind: ScalarKind::Uint,
102 size: BitWidth::Word,
103 },
104 BaseType::Uint64 => Scalar {
105 kind: ScalarKind::Uint,
106 size: BitWidth::DoubleWord,
107 },
108 BaseType::Fp16 => Scalar {
109 kind: ScalarKind::Float,
110 size: BitWidth::HalfWord,
111 },
112 BaseType::Fp32 => Scalar {
113 kind: ScalarKind::Float,
114 size: BitWidth::Word,
115 },
116 BaseType::Fp64 => Scalar {
117 kind: ScalarKind::Float,
118 size: BitWidth::DoubleWord,
119 },
120
121 _ => {
122 return Err(SpirvCrossError::InvalidArgument(String::from(
123 "Invalid base type used to instantiate a scalar",
124 )))
125 }
126 })
127 }
128}
129
130#[derive(Debug, Clone)]
132pub struct Type<'a> {
133 pub id: Handle<TypeId>,
135 pub name: Option<CompilerStr<'a>>,
137 pub inner: TypeInner<'a>,
139 pub size_hint: TypeSizeHint,
142}
143
144#[derive(Debug, Clone, Eq, PartialEq)]
146pub struct StructMember<'a> {
147 pub id: Handle<TypeId>,
149 pub struct_type: Handle<TypeId>,
151 pub name: Option<CompilerStr<'a>>,
153 pub index: usize,
155 pub offset: u32,
157 pub size: usize,
159 pub matrix_stride: Option<u32>,
163 pub array_stride: Option<u32>,
167}
168
169#[derive(Debug, Clone, Eq, PartialEq)]
171pub struct StructType<'a> {
172 pub id: Handle<TypeId>,
174 pub size: usize,
176 pub members: Vec<StructMember<'a>>,
178}
179
180#[derive(Debug, Clone, Eq, PartialEq)]
186pub enum ArrayDimension {
187 Literal(u32),
189 Constant(Handle<ConstantId>),
198}
199
200#[derive(Debug, Clone, Eq, PartialEq)]
202pub enum ImageClass {
203 Sampled {
205 depth: bool,
207 multisampled: bool,
209 arrayed: bool,
211 },
212 Texture {
214 multisampled: bool,
216 arrayed: bool,
218 },
219 Storage {
221 format: spirv::ImageFormat,
223 },
224}
225
226#[derive(Debug, Clone, Eq, PartialEq)]
228pub struct ImageType {
229 pub id: Handle<TypeId>,
231 pub sampled_type: Handle<TypeId>,
233 pub dimension: spirv::Dim,
235 pub class: ImageClass,
237}
238
239#[derive(Debug, Clone, Eq, PartialEq)]
244pub enum TypeInner<'a> {
245 Unknown,
247 Void,
249 Pointer {
254 base: Handle<TypeId>,
256 storage: StorageClass,
261 forward: bool,
263 },
264 Struct(StructType<'a>),
266 Scalar(Scalar),
268 Vector {
273 width: u32,
275 scalar: Scalar,
277 },
278 Matrix {
283 columns: u32,
285 rows: u32,
287 scalar: Scalar,
289 },
290 Array {
292 base: Handle<TypeId>,
294 storage: StorageClass,
296 dimensions: Vec<ArrayDimension>,
307 stride: Option<u32>,
310 },
311 Image(ImageType),
313 AccelerationStructure,
315 Sampler,
317}
318
319#[derive(Debug, Clone)]
327pub struct MatrixStrideHole {
328 columns: usize,
329 rows: usize,
330 declared: usize,
331}
332
333impl Sealed for MatrixStrideHole {}
334impl ResolveSize for MatrixStrideHole {
335 type Hole = (usize, bool);
336
337 fn declared(&self) -> usize {
338 self.declared
339 }
340
341 fn resolve(&self, hole: Self::Hole) -> usize {
342 let (stride, is_row_major) = hole;
343 if is_row_major {
344 stride * self.rows
345 } else {
346 stride * self.columns
347 }
348 }
349}
350
351#[derive(Debug, Clone)]
355pub struct ArraySizeHole {
356 stride: usize,
357 declared: usize,
358}
359
360#[derive(Debug, Clone)]
368pub struct UnknownStrideHole {
369 hint: Box<TypeSizeHint>,
370 count: usize,
371}
372
373impl Sealed for UnknownStrideHole {}
374impl ResolveSize for UnknownStrideHole {
375 type Hole = Box<dyn FnOnce(&TypeSizeHint) -> usize>;
376
377 fn declared(&self) -> usize {
378 self.count * self.hint.declared()
379 }
380
381 fn resolve(&self, hole: Self::Hole) -> usize {
382 self.count * hole(&self.hint)
383 }
384}
385
386impl ResolveSize for usize {
387 type Hole = core::convert::Infallible;
388
389 fn declared(&self) -> usize {
390 *self
391 }
392
393 fn resolve(&self, _hole: Self::Hole) -> usize {
394 self.declared()
395 }
396}
397
398impl ResolveSize for ArraySizeHole {
399 type Hole = usize;
400
401 fn declared(&self) -> usize {
402 self.declared
403 }
404
405 fn resolve(&self, count: Self::Hole) -> usize {
406 count * self.stride
407 }
408}
409
410impl Sealed for ArraySizeHole {}
411impl Sealed for usize {}
412
413#[derive(Debug, Clone)]
421pub enum TypeSizeHint {
422 Static(usize),
424 RuntimeArray(ArraySizeHole),
426 Matrix(MatrixStrideHole),
428 UnknownArrayStride(UnknownStrideHole),
430}
431
432impl TypeSizeHint {
433 pub fn declared(&self) -> usize {
436 match &self {
437 TypeSizeHint::Static(sz) => *sz,
438 TypeSizeHint::RuntimeArray(hole) => hole.declared(),
439 TypeSizeHint::UnknownArrayStride(hole) => hole.declared(),
440 TypeSizeHint::Matrix(hole) => hole.declared(),
441 }
442 }
443
444 pub fn is_static(&self) -> bool {
446 matches!(self, TypeSizeHint::Static(_))
447 }
448}
449
450pub trait ResolveSize: Sealed {
452 type Hole;
454
455 fn declared(&self) -> usize;
457
458 fn resolve(&self, hole: Self::Hole) -> usize;
460}
461
462impl<T> Compiler<T> {
464 fn process_struct(&self, struct_ty_id: TypeId) -> error::Result<StructType> {
468 unsafe {
469 let ty = sys::spvc_compiler_get_type_handle(self.ptr.as_ptr(), struct_ty_id);
470 let base_ty = sys::spvc_type_get_basetype(ty);
471 assert_eq!(base_ty, BaseType::Struct);
472
473 let mut struct_size = 0;
474 sys::spvc_compiler_get_declared_struct_size(self.ptr.as_ptr(), ty, &mut struct_size)
475 .ok(self)?;
476
477 let member_type_len = sys::spvc_type_get_num_member_types(ty);
478 let mut members = Vec::with_capacity(member_type_len as usize);
479 for i in 0..member_type_len {
480 let id = sys::spvc_type_get_member_type(ty, i);
481 let name = CompilerStr::from_ptr(
482 sys::spvc_compiler_get_member_name(self.ptr.as_ptr(), struct_ty_id, i),
483 self.ctx.drop_guard(),
484 );
485
486 let name = if name.as_ref().is_empty() {
487 None
488 } else {
489 Some(name)
490 };
491
492 let mut size = 0;
493 sys::spvc_compiler_get_declared_struct_member_size(
494 self.ptr.as_ptr(),
495 ty,
496 i,
497 &mut size,
498 )
499 .ok(self)?;
500
501 let mut offset = 0;
502 sys::spvc_compiler_type_struct_member_offset(self.ptr.as_ptr(), ty, i, &mut offset)
503 .ok(self)?;
504
505 let mut matrix_stride = 0;
506 let matrix_stride = sys::spvc_compiler_type_struct_member_matrix_stride(
507 self.ptr.as_ptr(),
508 ty,
509 i,
510 &mut matrix_stride,
511 )
512 .ok(self)
513 .ok()
514 .map(|_| matrix_stride);
515
516 let mut array_stride = 0;
517 let array_stride = sys::spvc_compiler_type_struct_member_array_stride(
518 self.ptr.as_ptr(),
519 ty,
520 i,
521 &mut array_stride,
522 )
523 .ok(self)
524 .ok()
525 .map(|_| array_stride);
526
527 members.push(StructMember {
528 name,
529 id: self.create_handle(id),
530 struct_type: self.create_handle(struct_ty_id),
531 offset,
532 size,
533 index: i as usize,
534 matrix_stride,
535 array_stride,
536 })
537 }
538
539 Ok(StructType {
540 id: self.create_handle(struct_ty_id),
541 size: struct_size,
542 members,
543 })
544 }
545 }
546
547 fn process_vector(&self, id: TypeId, vec_width: u32) -> error::Result<TypeInner> {
548 unsafe {
549 let ty = sys::spvc_compiler_get_type_handle(self.ptr.as_ptr(), id);
550 let base_ty = sys::spvc_type_get_basetype(ty);
551 Ok(TypeInner::Vector {
552 width: vec_width,
553 scalar: base_ty.try_into()?,
554 })
555 }
556 }
557
558 fn process_matrix(&self, id: TypeId, rows: u32, columns: u32) -> error::Result<TypeInner> {
559 unsafe {
560 let ty = sys::spvc_compiler_get_type_handle(self.ptr.as_ptr(), id);
561 let base_ty = sys::spvc_type_get_basetype(ty);
562 Ok(TypeInner::Matrix {
563 rows,
564 columns,
565 scalar: base_ty.try_into()?,
566 })
567 }
568 }
569
570 fn process_array<'a>(
571 &self,
572 id: TypeId,
573 name: Option<CompilerStr<'a>>,
574 ) -> error::Result<Type<'a>> {
575 unsafe {
576 let ty = sys::spvc_compiler_get_type_handle(self.ptr.as_ptr(), id);
577 let base_type_id = sys::spvc_type_get_base_type_id(ty);
578
579 let array_dim_len = sys::spvc_type_get_num_array_dimensions(ty);
580
581 let mut array_dims = Vec::with_capacity(array_dim_len as usize);
582 for i in 0..array_dim_len {
583 array_dims.push(sys::spvc_type_get_array_dimension(ty, i))
584 }
585
586 let mut array_is_literal = Vec::with_capacity(array_dim_len as usize);
587 for i in 0..array_dim_len {
588 array_is_literal.push(sys::spvc_type_array_dimension_is_literal(ty, i))
589 }
590
591 let storage_class = sys::spvc_type_get_storage_class(ty);
592
593 let Some(storage_class) = spirv::StorageClass::from_u32(storage_class.0 as u32) else {
594 return Err(SpirvCrossError::InvalidSpirv(format!(
595 "Unknown StorageClass found: {}",
596 storage_class.0
597 )));
598 };
599
600 let array_dims = array_dims
601 .into_iter()
602 .enumerate()
603 .map(|(index, dim)| {
604 if array_is_literal[index] {
605 ArrayDimension::Literal(dim.0)
606 } else {
607 ArrayDimension::Constant(self.create_handle(ConstantId(dim)))
608 }
609 })
610 .collect();
611
612 let id = self.create_handle(id);
613 let stride = self
614 .decoration(id, spirv::Decoration::ArrayStride)?
615 .and_then(|s| s.as_literal());
616
617 let inner = TypeInner::Array {
618 base: self.create_handle(base_type_id),
619 storage: storage_class,
620 dimensions: array_dims,
621 stride,
622 };
623
624 let size_hint = self.type_size_hint(&inner)?;
625
626 Ok(Type {
627 name,
628 id,
629 inner,
630 size_hint,
631 })
632 }
633 }
634
635 fn process_image(&self, id: TypeId) -> error::Result<ImageType> {
636 unsafe {
637 let ty = sys::spvc_compiler_get_type_handle(self.ptr.as_ptr(), id);
638 let base_ty = sys::spvc_type_get_basetype(ty);
639 let sampled_id = sys::spvc_type_get_image_sampled_type(ty);
640 let dimension = sys::spvc_type_get_image_dimension(ty);
641 let depth = sys::spvc_type_get_image_is_depth(ty);
642 let arrayed = sys::spvc_type_get_image_arrayed(ty);
643 let storage = sys::spvc_type_get_image_is_storage(ty);
644 let multisampled = sys::spvc_type_get_image_multisampled(ty);
645 let format = sys::spvc_type_get_image_storage_format(ty);
646
647 let Some(format) = spirv::ImageFormat::from_u32(format.0 as u32) else {
648 return Err(SpirvCrossError::InvalidSpirv(format!(
649 "Unknown image format found: {}",
650 format.0
651 )));
652 };
653
654 let Some(dimension) = spirv::Dim::from_u32(dimension.0 as u32) else {
655 return Err(SpirvCrossError::InvalidSpirv(format!(
656 "Unknown image dimension found: {}",
657 dimension.0
658 )));
659 };
660
661 let class = if storage {
662 ImageClass::Storage { format }
663 } else if base_ty == BaseType::SampledImage {
664 ImageClass::Sampled {
665 depth,
666 multisampled,
667 arrayed,
668 }
669 } else {
670 ImageClass::Texture {
671 multisampled,
672 arrayed,
673 }
674 };
675
676 Ok(ImageType {
677 id: self.create_handle(id),
678 sampled_type: self.create_handle(sampled_id),
679 dimension,
680 class,
681 })
682 }
683 }
684
685 pub fn type_description(&self, id: Handle<TypeId>) -> error::Result<Type> {
693 let id = self.yield_id(id)?;
694
695 unsafe {
696 let ty = sys::spvc_compiler_get_type_handle(self.ptr.as_ptr(), id);
697 let base_type_id = sys::spvc_type_get_base_type_id(ty);
698
699 let base_ty = sys::spvc_type_get_basetype(ty);
700 let name = CompilerStr::from_ptr(
701 sys::spvc_compiler_get_name(self.ptr.as_ptr(), id.0),
702 self.ctx.drop_guard(),
703 );
704
705 let name = if name.as_ref().is_empty() {
706 None
707 } else {
708 Some(name)
709 };
710
711 let array_dim_len = sys::spvc_type_get_num_array_dimensions(ty);
712 if array_dim_len != 0 {
713 return self.process_array(id, name);
714 }
715
716 if sys::spvc_rs_type_is_pointer(ty) {
718 let storage_class = sys::spvc_type_get_storage_class(ty);
719 let Some(storage_class) = spirv::StorageClass::from_u32(storage_class.0 as u32)
720 else {
721 return Err(SpirvCrossError::InvalidSpirv(format!(
722 "Unknown StorageClass found: {}",
723 storage_class.0
724 )));
725 };
726
727 let forward = sys::spvc_rs_type_is_forward_pointer(ty);
728
729 let inner = TypeInner::Pointer {
730 base: self.create_handle(base_type_id),
731 storage: storage_class,
732 forward,
733 };
734
735 let size_hint = self.type_size_hint(&inner)?;
736
737 return Ok(Type {
738 name,
739 id: self.create_handle(id),
740 inner,
741 size_hint,
742 });
743 }
744
745 let vec_size = sys::spvc_type_get_vector_size(ty);
746 let columns = sys::spvc_type_get_columns(ty);
747
748 let mut maybe_non_scalar = None;
750 if vec_size > 1 && columns == 1 {
751 maybe_non_scalar = Some(self.process_vector(id, vec_size)?);
752 }
753
754 if vec_size > 1 && columns > 1 {
755 maybe_non_scalar = Some(self.process_matrix(id, vec_size, columns)?);
756 }
757
758 let inner = match base_ty {
759 BaseType::Struct => {
760 let ty = self.process_struct(id)?;
761 TypeInner::Struct(ty)
762 }
763 BaseType::Image | BaseType::SampledImage => {
764 TypeInner::Image(self.process_image(id)?)
765 }
766 BaseType::Sampler => TypeInner::Sampler,
767 BaseType::Boolean
768 | BaseType::Int8
769 | BaseType::Uint8
770 | BaseType::Int16
771 | BaseType::Uint16
772 | BaseType::Int32
773 | BaseType::Uint32
774 | BaseType::Int64
775 | BaseType::Uint64
776 | BaseType::Fp16
777 | BaseType::Fp32
778 | BaseType::Fp64 => {
779 if let Some(prep) = maybe_non_scalar {
780 prep
781 } else {
782 TypeInner::Scalar(base_ty.try_into()?)
783 }
784 }
785
786 BaseType::Unknown => TypeInner::Unknown,
787 BaseType::Void => TypeInner::Void,
788
789 BaseType::AtomicCounter => {
790 let storage_class = sys::spvc_type_get_storage_class(ty);
792 let Some(storage_class) = spirv::StorageClass::from_u32(storage_class.0 as u32)
793 else {
794 return Err(SpirvCrossError::InvalidSpirv(format!(
795 "Unknown StorageClass found: {}",
796 storage_class.0
797 )));
798 };
799
800 let forward = sys::spvc_rs_type_is_forward_pointer(ty);
801
802 TypeInner::Pointer {
803 base: self.create_handle(base_type_id),
804 storage: storage_class,
805 forward,
806 }
807 }
808
809 BaseType::AccelerationStructure => TypeInner::AccelerationStructure,
810 };
811
812 let size_hint = self.type_size_hint(&inner)?;
813 let ty = Type {
814 name,
815 id: self.create_handle(id),
816 inner,
817 size_hint,
818 };
819 Ok(ty)
820 }
821 }
822
823 fn type_size_hint(&self, ty: &TypeInner) -> error::Result<TypeSizeHint> {
828 Ok(match ty {
829 TypeInner::Pointer { .. } => TypeSizeHint::Static(BitWidth::Word.byte_size()),
830 TypeInner::Struct(s) => {
831 if let Some(stride) = self.struct_has_runtime_array(s)? {
832 TypeSizeHint::RuntimeArray(ArraySizeHole {
833 stride: stride as usize,
834 declared: s.size,
835 })
836 } else {
837 TypeSizeHint::Static(s.size)
838 }
839 }
840 TypeInner::Scalar(s) => TypeSizeHint::Static(s.size.byte_size()),
841 TypeInner::Vector { width, scalar } => {
842 TypeSizeHint::Static((*width as usize) * scalar.size.byte_size())
843 }
844
845 TypeInner::Matrix {
846 columns,
847 rows,
848 scalar,
849 } => {
850 let rows_aligned = (rows + 3 & !0x3) as usize;
852
853 let scalar_width = scalar.size.byte_size();
854 let columns = *columns as usize;
855 let declared = rows_aligned * scalar_width * columns;
856 TypeSizeHint::Matrix(MatrixStrideHole {
857 columns,
858 rows: *rows as usize,
859 declared,
860 })
861 }
862 TypeInner::Array {
863 dimensions,
864 stride,
865 base,
866 ..
867 } => {
868 let mut count = 1usize;
869 for dim in dimensions.iter() {
870 match dim {
871 ArrayDimension::Literal(a) => count = count * (*a as usize),
872 ArrayDimension::Constant(c) => {
873 let value = self.specialization_constant_value::<u32>(*c)?;
874 count = count * value as usize;
875 } }
877 }
878
879 if let Some(stride) = stride {
880 TypeSizeHint::Static(count * (*stride as usize))
881 } else {
882 let base_stride = self.type_description(*base)?.size_hint;
884 if base_stride.is_static() {
885 TypeSizeHint::Static(count * base_stride.declared())
886 } else {
887 TypeSizeHint::UnknownArrayStride(UnknownStrideHole {
888 hint: Box::new(base_stride),
889 count,
890 })
891 }
892 }
893 }
894 TypeInner::Image(_)
895 | TypeInner::AccelerationStructure
896 | TypeInner::Sampler
897 | TypeInner::Unknown
898 | TypeInner::Void => TypeSizeHint::Static(0),
899 })
900 }
901
902 fn struct_has_runtime_array(&self, struct_type: &StructType) -> error::Result<Option<u32>> {
905 if let Some(last) = struct_type.members.last() {
906 let Some(array_stride) = last.array_stride else {
907 return Ok(None);
908 };
909
910 let inner = self.type_description(last.id)?.inner;
911 if let TypeInner::Array { dimensions, .. } = inner {
912 if let Some(ArrayDimension::Literal(0)) = dimensions.first() {
913 return Ok(Some(array_stride));
914 }
915 }
916 }
917
918 Ok(None)
919 }
920
921 pub fn variable_type(
923 &self,
924 variable: impl Into<Handle<VariableId>>,
925 ) -> error::Result<Handle<TypeId>> {
926 let variable = variable.into();
927 let variable_id = self.yield_id(variable)?;
928
929 unsafe {
930 let mut type_id = TypeId(SpvId(0));
931 sys::spvc_rs_compiler_variable_get_type(self.ptr.as_ptr(), variable_id, &mut type_id)
932 .ok(self)?;
933
934 Ok(self.create_handle(type_id))
935 }
936 }
937}
938
939#[cfg(test)]
940mod test {
941 use crate::error::SpirvCrossError;
942 use crate::Compiler;
943 use crate::{targets, Module};
944
945 static BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");
946
947 #[test]
948 pub fn get_stage_outputs() -> Result<(), SpirvCrossError> {
949 let vec = Vec::from(BASIC_SPV);
950 let words = Module::from_words(bytemuck::cast_slice(&vec));
951
952 let compiler: Compiler<targets::None> = Compiler::new(words)?;
953 let resources = compiler.shader_resources()?.all_resources()?;
954
955 let ty = compiler.type_description(resources.uniform_buffers[0].base_type_id)?;
958 eprintln!("{ty:?}");
959
960 drop(compiler);
961 eprintln!("{resources:?}");
962 eprintln!("{resources:?}");
963 Ok(())
971 }
972
973 #[test]
974 pub fn set_member_name_validity_test() -> Result<(), SpirvCrossError> {
975 let vec = Vec::from(BASIC_SPV);
976 let words = Module::from_words(bytemuck::cast_slice(&vec));
977
978 let mut compiler: Compiler<targets::None> = Compiler::new(words)?;
979 let resources = compiler.shader_resources()?.all_resources()?;
980
981 let ty = compiler.type_description(resources.uniform_buffers[0].base_type_id)?;
984 let id = ty.id;
985
986 let name = compiler.member_name(id, 0)?;
987 assert_eq!(Some("MVP"), name.as_deref());
988
989 compiler.set_member_name(ty.id, 0, "NotMVP")?;
990 let name = compiler.member_name(id, 0)?;
993 assert_eq!(Some("NotMVP"), name.as_deref());
994 let resources = compiler.shader_resources()?.all_resources()?;
995
996 let ty = compiler.type_description(resources.uniform_buffers[0].base_type_id)?;
997
998 Ok(())
999 }
1000
1001 #[test]
1002 pub fn get_variable_type_test() -> Result<(), SpirvCrossError> {
1003 let vec = Vec::from(BASIC_SPV);
1004 let words = Module::from_words(bytemuck::cast_slice(&vec));
1005
1006 let mut compiler: Compiler<targets::None> = Compiler::new(words)?;
1007 let resources = compiler.shader_resources()?.all_resources()?;
1008
1009 let variable = resources.uniform_buffers[0].id;
1010 assert_eq!(
1011 resources.uniform_buffers[0].type_id.id(),
1012 compiler.variable_type(variable)?.id()
1013 );
1014
1015 eprintln!("{:?}", resources);
1016 Ok(())
1017 }
1018}