[hlsl-out] reorder fields when composing structs

This commit is contained in:
Dzmitry Malyshau 2021-08-13 01:33:25 -04:00 committed by Dzmitry Malyshau
parent 27e4ba59e4
commit 69b70f8cc3
2 changed files with 44 additions and 18 deletions

View File

@ -32,7 +32,7 @@ struct EpStructMember {
index: usize, index: usize,
} }
#[derive(Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
enum InterfaceKey { enum InterfaceKey {
Location(u32), Location(u32),
BuiltIn(crate::BuiltIn), BuiltIn(crate::BuiltIn),
@ -49,6 +49,19 @@ impl InterfaceKey {
} }
} }
// Returns true for structures that need their members permuted,
// so that first come the user-defined varyings
// in ascending locations, and then built-ins. This allows VS and FS
// interfaces to match with regards to order.
fn needs_permutation(members: &[crate::StructMember]) -> bool {
//Note: this is a bit of a hack. We need to re-order the output fields, but we can only do this
// for non-layouted structures. It may be possible for an WGSL program can use the same struct
// for both host sharing and the interface. This case isn't supported here.
let has_layout = members.iter().any(|m| m.offset != 0);
let has_binding = members.iter().any(|m| m.binding.is_some());
has_binding && !has_layout
}
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
enum Io { enum Io {
Input, Input,
@ -563,21 +576,13 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, "struct {}", self.names[&NameKey::Type(handle)])?; write!(self.out, "struct {}", self.names[&NameKey::Type(handle)])?;
writeln!(self.out, " {{")?; writeln!(self.out, " {{")?;
let has_layout = original_members.iter().any(|m| m.offset != 0);
let has_binding = original_members.iter().any(|m| m.binding.is_some());
//TODO: avoid heap allocation //TODO: avoid heap allocation
let mut members = original_members let mut members = original_members
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, m)| (index, m.ty, m.binding.clone())) .map(|(index, m)| (index, m.ty, m.binding.clone()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
//Note: this is a bit of a hack. We need to re-order the output fields, but we can only do this if needs_permutation(original_members) {
// for non-layouted structures. It may be possible for an WGSL program can use the same struct
// for both host sharing and the interface. This case isn't supported here.
if has_binding && !has_layout {
// Sort the members so that first come the user-defined varyings
// in ascending locations, and then built-ins. This allows VS and FS
// interfaces to match with regards to order.
members.sort_by_key(|&(_, _, ref binding)| InterfaceKey::new(binding.as_ref())); members.sort_by_key(|&(_, _, ref binding)| InterfaceKey::new(binding.as_ref()));
} }
@ -1240,24 +1245,45 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
match *expression { match *expression {
Expression::Constant(constant) => self.write_constant(module, constant)?, Expression::Constant(constant) => self.write_constant(module, constant)?,
Expression::Compose { ty, ref components } => { Expression::Compose { ty, ref components } => {
let braces_init = match module.types[ty].inner { let (braces_init, permutation) = match module.types[ty].inner {
TypeInner::Struct { .. } | TypeInner::Array { .. } => true, TypeInner::Struct { ref members, .. } => {
_ => false, let permutation = if needs_permutation(members) {
//TODO: avoid heap allocation. We can pre-compute this at the module leve.
let mut permutation = members
.iter()
.enumerate()
.map(|(index, m)| (index, InterfaceKey::new(m.binding.as_ref())))
.collect::<Vec<_>>();
permutation.sort_by_key(|&(_, ref key)| key.clone());
Some(permutation)
} else {
None
};
(true, permutation)
}
TypeInner::Array { .. } => (true, None),
_ => (false, None),
}; };
if braces_init { if braces_init {
write!(self.out, "{{ ")?; write!(self.out, "{{ ")?;
} else { } else {
self.write_type(module, ty)?; self.write_type(module, ty)?;
write!(self.out, "(")?; write!(self.out, "(")?;
} }
for (index, component) in components.iter().enumerate() {
self.write_expr(module, *component, func_ctx)?; for index in 0..components.len() {
// Only write a comma if isn't the last element if index != 0 {
if index != components.len().saturating_sub(1) {
// The leading space is for readability only // The leading space is for readability only
write!(self.out, ", ")?; write!(self.out, ", ")?;
} }
let comp_index = match permutation {
Some(ref perm) => perm[index].0,
None => index,
};
self.write_expr(module, components[comp_index], func_ctx)?;
} }
if braces_init { if braces_init {
write!(self.out, " }}")? write!(self.out, " }}")?
} else { } else {

View File

@ -43,6 +43,6 @@ type10 main(VertexInput_main vertexinput_main)
float _expr12 = perVertexStruct.gl_PointSize; float _expr12 = perVertexStruct.gl_PointSize;
float _expr13[1] = perVertexStruct.gl_ClipDistance; float _expr13[1] = perVertexStruct.gl_ClipDistance;
float _expr14[1] = perVertexStruct.gl_CullDistance; float _expr14[1] = perVertexStruct.gl_CullDistance;
const type10 type10_ = { _expr10, _expr11, _expr12, _expr13, _expr14 }; const type10 type10_ = { _expr10, _expr11, _expr13, _expr14, _expr12 };
return type10_; return type10_;
} }