Skip to content

Commit

Permalink
[spv-out] Emit required decorations on wrapper struct types, too.
Browse files Browse the repository at this point in the history
Fixes #1810.
  • Loading branch information
jimblandy committed Apr 8, 2022
1 parent 5408242 commit 2c9db98
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 51 deletions.
16 changes: 15 additions & 1 deletion src/back/spv/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
119 changes: 69 additions & 50 deletions src/back/spv/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -1277,12 +1234,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);

Expand All @@ -1307,6 +1266,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<crate::Type>,
) -> 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
Expand Down

0 comments on commit 2c9db98

Please sign in to comment.