diff --git a/src/back/spv/helpers.rs b/src/back/spv/helpers.rs index acde9504d9..60f86c691d 100644 --- a/src/back/spv/helpers.rs +++ b/src/back/spv/helpers.rs @@ -62,7 +62,21 @@ impl crate::AddressSpace { } } -/// Return true if the global requires a type decorated with "Block". +/// Return true if the global requires a type decorated with `Block`. +/// +/// Vulkan spec v1.3 §15.6.2, "Descriptor Set Interface", says: +/// +/// > Variables identified with the `Uniform` storage class are used to +/// > access transparent buffer backed resources. Such variables must +/// > be: +/// > +/// > - typed as `OpTypeStruct`, or an array of this type, +/// > +/// > - identified with a `Block` or `BufferBlock` decoration, and +/// > +/// > - laid out explicitly using the `Offset`, `ArrayStride`, and +/// > `MatrixStride` decorations as specified in §15.6.4, "Offset +/// > and Stride Assignment." // See `back::spv::GlobalVariable::access_id` for details. pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariable) -> bool { match var.space { diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index cf60933705..cc0c470859 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -844,50 +844,7 @@ impl Writer { } => { let mut member_ids = Vec::with_capacity(members.len()); for (index, member) in members.iter().enumerate() { - self.annotations.push(Instruction::member_decorate( - id, - index as u32, - Decoration::Offset, - &[member.offset], - )); - - if self.flags.contains(WriterFlags::DEBUG) { - if let Some(ref name) = member.name { - self.debugs - .push(Instruction::member_name(id, index as u32, name)); - } - } - - // The matrix decorations also go on arrays of matrices, - // so lets check this first. - let member_array_subty_inner = match arena[member.ty].inner { - crate::TypeInner::Array { base, .. } => &arena[base].inner, - ref other => other, - }; - if let crate::TypeInner::Matrix { - columns: _, - rows, - width, - } = *member_array_subty_inner - { - let byte_stride = match rows { - crate::VectorSize::Bi => 2 * width, - crate::VectorSize::Tri | crate::VectorSize::Quad => 4 * width, - }; - self.annotations.push(Instruction::member_decorate( - id, - index as u32, - Decoration::ColMajor, - &[], - )); - self.annotations.push(Instruction::member_decorate( - id, - index as u32, - Decoration::MatrixStride, - &[byte_stride as u32], - )); - } - + self.decorate_struct_member(id, index, member, arena)?; let member_id = self.get_type_id(LookupType::Handle(member.ty)); member_ids.push(member_id); } @@ -1281,12 +1238,14 @@ impl Writer { let wrapper_type_id = self.id_gen.next(); self.decorate(wrapper_type_id, Decoration::Block, &[]); - self.annotations.push(Instruction::member_decorate( - wrapper_type_id, - 0, - Decoration::Offset, - &[0], - )); + let member = crate::StructMember { + name: None, + ty: global_variable.ty, + binding: None, + offset: 0, + }; + self.decorate_struct_member(wrapper_type_id, 0, &member, &ir_module.types)?; + Instruction::type_struct(wrapper_type_id, &[inner_type_id]) .to_words(&mut self.logical_layout.declarations); @@ -1311,6 +1270,66 @@ impl Writer { Ok(id) } + /// Write the necessary decorations for a struct member. + /// + /// Emit decorations for the `index`'th member of the struct type + /// designated by `struct_id`, described by `member`. + fn decorate_struct_member( + &mut self, + struct_id: Word, + index: usize, + member: &crate::StructMember, + arena: &UniqueArena, + ) -> Result<(), Error> { + use spirv::Decoration; + + self.annotations.push(Instruction::member_decorate( + struct_id, + index as u32, + Decoration::Offset, + &[member.offset], + )); + + if self.flags.contains(WriterFlags::DEBUG) { + if let Some(ref name) = member.name { + self.debugs + .push(Instruction::member_name(struct_id, index as u32, name)); + } + } + + // Matrices and arrays of matrices both require decorations, + // so "see through" an array to determine if they're needed. + let member_array_subty_inner = match arena[member.ty].inner { + crate::TypeInner::Array { base, .. } => &arena[base].inner, + ref other => other, + }; + if let crate::TypeInner::Matrix { + columns: _, + rows, + width, + } = *member_array_subty_inner + { + let byte_stride = match rows { + crate::VectorSize::Bi => 2 * width, + crate::VectorSize::Tri | crate::VectorSize::Quad => 4 * width, + }; + self.annotations.push(Instruction::member_decorate( + struct_id, + index as u32, + Decoration::ColMajor, + &[], + )); + self.annotations.push(Instruction::member_decorate( + struct_id, + index as u32, + Decoration::MatrixStride, + &[byte_stride as u32], + )); + } + + Ok(()) + } + fn get_function_type(&mut self, lookup_function_type: LookupFunctionType) -> Word { match self .lookup_function_type