diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 5ec9f4f615..6ed11da3be 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -98,11 +98,12 @@ impl crate::AddressSpace { /// Whether a variable with this address space can be initialized fn initializable(&self) -> bool { match *self { + crate::AddressSpace::Function | crate::AddressSpace::Private => true, crate::AddressSpace::WorkGroup | crate::AddressSpace::Uniform - | crate::AddressSpace::PushConstant - | crate::AddressSpace::Storage { .. } => false, - _ => true, + | crate::AddressSpace::Storage { .. } + | crate::AddressSpace::Handle + | crate::AddressSpace::PushConstant => false, } } } @@ -570,27 +571,19 @@ impl<'a, W: Write> Writer<'a, W> { let ep_info = self.info.get_entry_point(self.entry_point_idx as usize); - // Write all structs + // Write struct types. // - // This are always ordered because of the IR is structured in a way that you can't make a - // struct without adding all of it's members first + // This are always ordered because the IR is structured in a way that + // you can't make a struct without adding all of its members first. for (handle, ty) in self.module.types.iter() { if let TypeInner::Struct { ref members, .. } = ty.inner { - let generate_struct = match GlobalTypeKind::new(self.module, handle) { - GlobalTypeKind::WrappedStruct => true, - // If it's a global non-wrapped struct, it will be printed - // with the corresponding global variable. - GlobalTypeKind::Unsized(_) => false, - GlobalTypeKind::Other => { - let used_by_global = - self.module.global_variables.iter().any(|(vh, var)| { - !ep_info[vh].is_empty() && var.space.is_buffer() && var.ty == handle - }); - // If not used by a global, it's safe to just spew it here - !used_by_global - } - }; - if generate_struct { + // Structures ending with runtime-sized arrays can only be + // rendered as shader storage blocks in GLSL, not stand-alone + // struct types. + if !self.module.types[members.last().unwrap().ty] + .inner + .is_dynamically_sized(&self.module.types) + { let name = &self.names[&NameKey::Type(handle)]; write!(self.out, "struct {} ", name)?; self.write_struct_body(handle, members)?; @@ -955,56 +948,38 @@ impl<'a, W: Write> Writer<'a, W> { self.write_storage_access(access)?; } - // Write the storage class - // Trailing space is important - if let Some(storage_class) = glsl_storage_class(global.space) { - write!(self.out, "{} ", storage_class)?; + if let Some(storage_qualifier) = glsl_storage_qualifier(global.space) { + write!(self.out, "{} ", storage_qualifier)?; } - // If struct is a block we need to write `block_name { members }` where `block_name` must be - // unique between blocks and structs so we add `_block_ID` where `ID` is a `IdGenerator` - // generated number so it's unique and `members` are the same as in a struct - - // Write the block name, it's just the struct name appended with `_block_ID` - let needs_wrapper = if global.space.is_buffer() { - let ty_name = &self.names[&NameKey::Type(global.ty)]; - let block_name = format!( - "{}_block_{}{:?}", - ty_name, - self.block_id.generate(), - self.entry_point.stage, - ); - write!(self.out, "{} ", block_name)?; - self.reflection_names_globals.insert(handle, block_name); - - match GlobalTypeKind::new(self.module, global.ty) { - GlobalTypeKind::WrappedStruct => { - write!(self.out, "{{ ")?; - // Write the type - // `write_type` adds no leading or trailing spaces - self.write_type(global.ty)?; - true - } - GlobalTypeKind::Unsized(members) => { - self.write_struct_body(global.ty, members)?; - false - } - GlobalTypeKind::Other => { - return Err(Error::Custom("Non-struct type of a buffer".to_string())); - } + match global.space { + crate::AddressSpace::Private => { + self.write_simple_global(handle, global)?; } - } else { - self.write_type(global.ty)?; - false - }; - - if let crate::AddressSpace::PushConstant = global.space { - let global_name = self.get_global_name(handle, global); - self.reflection_names_globals.insert(handle, global_name); + crate::AddressSpace::WorkGroup => { + self.write_simple_global(handle, global)?; + } + crate::AddressSpace::PushConstant => { + self.write_simple_global(handle, global)?; + } + crate::AddressSpace::Uniform | crate::AddressSpace::Handle => { + self.write_interface_block(handle, global)?; + } + crate::AddressSpace::Storage { .. } => { + self.write_interface_block(handle, global)?; + } + crate::AddressSpace::Function => unreachable!(), } - // Finally write the global name and end the global with a `;` and a newline - // Leading space is important + Ok(()) + } + + fn write_simple_global( + &mut self, + handle: Handle, + global: &crate::GlobalVariable, + ) -> BackendResult { + self.write_type(global.ty)?; write!(self.out, " ")?; self.write_global_name(handle, global)?; @@ -1021,11 +996,68 @@ impl<'a, W: Write> Writer<'a, W> { } } - if needs_wrapper { - write!(self.out, "; }}")?; + writeln!(self.out, ";")?; + + if let crate::AddressSpace::PushConstant = global.space { + let global_name = self.get_global_name(handle, global); + self.reflection_names_globals.insert(handle, global_name); + } + + Ok(()) + } + + /// Write an interface block for a single Naga global. + /// + /// Write `block_name { members }`. Since `block_name` must be unique + /// between blocks and structs, we add `_block_ID` where `ID` is a + /// `IdGenerator` generated number. Write `members` in the same way we write + /// a struct's members. + fn write_interface_block( + &mut self, + handle: Handle, + global: &crate::GlobalVariable, + ) -> BackendResult { + // Write the block name, it's just the struct name appended with `_block_ID` + let ty_name = &self.names[&NameKey::Type(global.ty)]; + let block_name = format!( + "{}_block_{}{:?}", + ty_name, + self.block_id.generate(), + self.entry_point.stage, + ); + write!(self.out, "{} ", block_name)?; + self.reflection_names_globals.insert(handle, block_name); + + match self.module.types[global.ty].inner { + crate::TypeInner::Struct { ref members, .. } + if self.module.types[members.last().unwrap().ty] + .inner + .is_dynamically_sized(&self.module.types) => + { + // Structs with dynamically sized arrays must have their + // members lifted up as members of the interface block. GLSL + // can't write such struct types anyway. + self.write_struct_body(global.ty, members)?; + write!(self.out, " ")?; + self.write_global_name(handle, global)?; + } + _ => { + // A global of any other type is written as the sole member + // of the interface block. Since the interface block is + // anonymous, this becomes visible in the global scope. + write!(self.out, "{{ ")?; + self.write_type(global.ty)?; + write!(self.out, " ")?; + self.write_global_name(handle, global)?; + if let TypeInner::Array { base, size, .. } = self.module.types[global.ty].inner { + self.write_array_size(base, size)?; + } + write!(self.out, "; }}")?; + } } writeln!(self.out, ";")?; + Ok(()) } @@ -3209,7 +3241,7 @@ fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str { } /// Helper function that returns the string corresponding to the address space -fn glsl_storage_class(space: crate::AddressSpace) -> Option<&'static str> { +fn glsl_storage_qualifier(space: crate::AddressSpace) -> Option<&'static str> { use crate::AddressSpace as As; match space { diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index b3e61e7f53..ccf3c1cbad 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -153,15 +153,13 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // Write all structs for (handle, ty) in module.types.iter() { if let TypeInner::Struct { ref members, span } = ty.inner { - if let Some(member) = members.last() { - if let TypeInner::Array { - size: crate::ArraySize::Dynamic, - .. - } = module.types[member.ty].inner - { - // unsized arrays can only be in storage buffers, for which we use `ByteAddressBuffer` anyway. - continue; - } + if module.types[members.last().unwrap().ty] + .inner + .is_dynamically_sized(&module.types) + { + // unsized arrays can only be in storage buffers, + // for which we use `ByteAddressBuffer` anyway. + continue; } let ep_result = ep_results.iter().find(|e| { diff --git a/src/proc/mod.rs b/src/proc/mod.rs index 4e11a24e14..1ac8fff234 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -185,6 +185,18 @@ impl super::TypeInner { let right = rhs.canonical_form(types); left.as_ref().unwrap_or(self) == right.as_ref().unwrap_or(rhs) } + + pub fn is_dynamically_sized(&self, types: &crate::UniqueArena) -> bool { + use crate::TypeInner as Ti; + match *self { + Ti::Array { size, .. } => size == crate::ArraySize::Dynamic, + Ti::Struct { ref members, .. } => members + .last() + .map(|last| types[last.ty].inner.is_dynamically_sized(types)) + .unwrap_or(false), + _ => false, + } + } } impl super::AddressSpace {