Skip to content

Commit

Permalink
Remove top_level property of structs
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Dec 15, 2021
1 parent 3867ef4 commit 8ffd6ba
Show file tree
Hide file tree
Showing 78 changed files with 882 additions and 980 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Change Log

## v0.7.1 (2021-10-12)
## v0.8 (TBD)
- WGSL-in:
- remove `[[block]]` attribute

### v0.7.1 (2021-10-12)
- implement casts from and to booleans in the backends

## v0.7 (2021-10-07)
Expand Down
146 changes: 83 additions & 63 deletions src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,33 @@ impl crate::AtomicFunction {
}
}

impl crate::StorageClass {
fn is_buffer(&self) -> bool {
match *self {
crate::StorageClass::Uniform | crate::StorageClass::Storage { .. } => true,
_ => false,
}
}
}

//Note: similar to `back/spv/helpers.rs`
fn global_needs_wrapper(ir_module: &crate::Module, global_ty: Handle<crate::Type>) -> bool {
match ir_module.types[global_ty].inner {
crate::TypeInner::Struct {
ref members,
span: _,
} => match ir_module.types[members.last().unwrap().ty].inner {
// Structs with dynamically sized arrays can't be copied and can't be wrapped.
crate::TypeInner::Array {
size: crate::ArraySize::Dynamic,
..
} => false,
_ => true,
},
_ => false,
}
}

/// glsl version
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
Expand Down Expand Up @@ -340,8 +367,6 @@ pub struct Writer<'a, W> {
/// A map with all the names needed for writing the module
/// (generated by a [`Namer`](crate::proc::Namer))
names: crate::FastHashMap<NameKey, String>,
/// A map with all the names needed for reflections
reflection_names_uniforms: crate::FastHashMap<Handle<crate::Type>, String>,
/// A map with the names of global variables needed for reflections
reflection_names_globals: crate::FastHashMap<Handle<crate::GlobalVariable>, String>,
/// The selected entry point
Expand Down Expand Up @@ -397,7 +422,6 @@ impl<'a, W: Write> Writer<'a, W> {
namer,
features: FeaturesManager::new(),
names,
reflection_names_uniforms: crate::FastHashMap::default(),
reflection_names_globals: crate::FastHashMap::default(),
entry_point: &module.entry_points[ep_idx],
entry_point_idx: ep_idx as u16,
Expand Down Expand Up @@ -489,27 +513,30 @@ impl<'a, W: Write> Writer<'a, W> {
}
}

let ep_info = self.info.get_entry_point(self.entry_point_idx as usize);

// Write all structs
//
// 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
for (handle, ty) in self.module.types.iter() {
if let TypeInner::Struct { ref members, .. } = ty.inner {
// No needed to write a struct that also should be written as a global variable
let is_global_struct = self
.module
.global_variables
.iter()
.any(|e| e.1.ty == handle);

if !is_global_struct {
self.write_struct(false, handle, members)?
let used_by_global = self.module.global_variables.iter().any(|(vh, var)| {
!ep_info[vh].is_empty() && var.class.is_buffer() && var.ty == handle
});

let is_wrapped = global_needs_wrapper(self.module, handle);
// If it's a global non-wrapped struct, it will be printed
// with the corresponding global variable.
if !used_by_global || is_wrapped {
let name = &self.names[&NameKey::Type(handle)];
write!(self.out, "struct {} ", name)?;
self.write_struct_body(handle, members)?;
writeln!(self.out, ";")?;
}
}
}

let ep_info = self.info.get_entry_point(self.entry_point_idx as usize);

// Write the globals
//
// We filter all globals that aren't used by the selected entry point as they might be
Expand Down Expand Up @@ -748,12 +775,7 @@ impl<'a, W: Write> Writer<'a, W> {
match self.module.types[ty].inner {
// glsl has no pointer types so just write types as normal and loads are skipped
TypeInner::Pointer { base, .. } => self.write_type(base),
TypeInner::Struct {
top_level: true,
ref members,
span: _,
} => self.write_struct(true, ty, members),
// glsl structs are written as just the struct name if it isn't a block
// glsl structs are written as just the struct name
TypeInner::Struct { .. } => {
// Get the struct name
let name = &self.names[&NameKey::Type(ty)];
Expand Down Expand Up @@ -861,21 +883,46 @@ impl<'a, W: Write> Writer<'a, W> {
// Trailing space is important
if let Some(storage_class) = glsl_storage_class(global.class) {
write!(self.out, "{} ", storage_class)?;
} else if let TypeInner::Struct {
top_level: true, ..
} = self.module.types[global.ty].inner
{
write!(self.out, "struct ")?;
}

// Write the type
// `write_type` adds no leading or trailing spaces
self.write_type(global.ty)?;
// 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.class.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);

let needs_wrapper = global_needs_wrapper(self.module, global.ty);
if needs_wrapper {
write!(self.out, "{{ ")?;
// Write the type
// `write_type` adds no leading or trailing spaces
self.write_type(global.ty)?;
} else if let crate::TypeInner::Struct { ref members, .. } =
self.module.types[global.ty].inner
{
self.write_struct_body(global.ty, members)?;
}
needs_wrapper
} else {
self.write_type(global.ty)?;
false
};

// Finally write the global name and end the global with a `;` and a newline
// Leading space is important
write!(self.out, " ")?;
self.write_global_name(handle, global)?;

if let TypeInner::Array { size, .. } = self.module.types[global.ty].inner {
self.write_array_size(size)?;
}
Expand All @@ -888,8 +935,12 @@ impl<'a, W: Write> Writer<'a, W> {
self.write_zero_init_value(global.ty)?;
}
}
writeln!(self.out, ";")?;

if needs_wrapper {
write!(self.out, "; }}")?;
}

writeln!(self.out, ";")?;
Ok(())
}

Expand Down Expand Up @@ -1283,9 +1334,8 @@ impl<'a, W: Write> Writer<'a, W> {
///
/// # Notes
/// Ends in a newline
fn write_struct(
fn write_struct_body(
&mut self,
block: bool,
handle: Handle<crate::Type>,
members: &[crate::StructMember],
) -> BackendResult {
Expand All @@ -1296,30 +1346,7 @@ impl<'a, W: Write> Writer<'a, W> {
// | `members` is a semicolon separated list of `type name`
// | `type` is the member type
// | `name` is the member name
let name = &self.names[&NameKey::Type(handle)];

// 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
if block {
// Write the block name, it's just the struct name appended with `_block_ID`
let stage_postfix = match self.entry_point.stage {
ShaderStage::Vertex => "Vs",
ShaderStage::Fragment => "Fs",
ShaderStage::Compute => "Cs",
};
let block_name = format!(
"{}_block_{}{}",
name,
self.block_id.generate(),
stage_postfix
);
writeln!(self.out, "{} {{", block_name)?;

self.reflection_names_uniforms.insert(handle, block_name);
} else {
writeln!(self.out, "struct {} {{", name)?;
}
writeln!(self.out, "{{")?;

for (idx, member) in members.iter().enumerate() {
// The indentation is only for readability
Expand Down Expand Up @@ -1360,13 +1387,6 @@ impl<'a, W: Write> Writer<'a, W> {
}

write!(self.out, "}}")?;

if !block {
writeln!(self.out, ";")?;
// Add a newline for readability
writeln!(self.out)?;
}

Ok(())
}

Expand Down Expand Up @@ -2747,7 +2767,7 @@ impl<'a, W: Write> Writer<'a, W> {
match self.module.types[var.ty].inner {
crate::TypeInner::Struct { .. } => match var.class {
crate::StorageClass::Uniform | crate::StorageClass::Storage { .. } => {
let name = self.reflection_names_uniforms[&var.ty].clone();
let name = self.reflection_names_globals[&handle].clone();
uniforms.insert(handle, name);
}
_ => (),
Expand Down
15 changes: 2 additions & 13 deletions src/back/hlsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {

// Write all structs
for (handle, ty) in module.types.iter() {
if let TypeInner::Struct {
top_level,
ref members,
..
} = ty.inner
{
if let TypeInner::Struct { ref members, .. } = ty.inner {
if let Some(member) = members.last() {
if let TypeInner::Array {
size: crate::ArraySize::Dynamic,
Expand All @@ -180,7 +175,6 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
self.write_struct(
module,
handle,
top_level,
members,
ep_result.map(|r| (r.0, Io::Output)),
)?;
Expand Down Expand Up @@ -703,7 +697,6 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
&mut self,
module: &Module,
handle: Handle<crate::Type>,
_block: bool,
members: &[crate::StructMember],
shader_stage: Option<(ShaderStage, Io)>,
) -> BackendResult {
Expand Down Expand Up @@ -1941,11 +1934,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
let var = &module.global_variables[var_handle];
let (offset, stride) = match module.types[var.ty].inner {
TypeInner::Array { stride, .. } => (0, stride),
TypeInner::Struct {
top_level: true,
ref members,
..
} => {
TypeInner::Struct { ref members, .. } => {
let last = members.last().unwrap();
let stride = match module.types[last.ty].inner {
TypeInner::Array { stride, .. } => stride,
Expand Down
4 changes: 1 addition & 3 deletions src/back/msl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2652,9 +2652,7 @@ impl<W: Write> Writer<W> {
if let Some(ref br) = var.binding {
let good = match options.per_stage_map[ep.stage].resources.get(br) {
Some(target) => match module.types[var.ty].inner {
crate::TypeInner::Struct {
top_level: true, ..
} => target.buffer.is_some(),
crate::TypeInner::Struct { .. } => target.buffer.is_some(),
crate::TypeInner::Image { .. } => target.texture.is_some(),
crate::TypeInner::Sampler { .. } => target.sampler.is_some(),
_ => false,
Expand Down
4 changes: 2 additions & 2 deletions src/back/spv/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ impl<'w> BlockContext<'w> {
}
}
crate::Expression::GlobalVariable(handle) => {
self.writer.global_variables[handle.index()].id
self.writer.global_variables[handle.index()].access_id
}
crate::Expression::Constant(handle) => self.writer.constant_ids[handle.index()],
crate::Expression::Splat { size, value } => {
Expand Down Expand Up @@ -1065,7 +1065,7 @@ impl<'w> BlockContext<'w> {
}
crate::Expression::GlobalVariable(handle) => {
let gv = &self.writer.global_variables[handle.index()];
break gv.id;
break gv.access_id;
}
crate::Expression::LocalVariable(variable) => {
let local_var = &self.function.variables[&variable];
Expand Down
26 changes: 26 additions & 0 deletions src/back/spv/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,29 @@ impl crate::StorageClass {
}
}
}

/// Return true if the global requires a type decorated with "Block".
// See `back::spv::GlobalVariable::access_id` for details.
pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariable) -> bool {
match var.class {
crate::StorageClass::Uniform | crate::StorageClass::Storage { .. } => {}
_ => return false,
};
match ir_module.types[var.ty].inner {
crate::TypeInner::Struct {
ref members,
span: _,
} => match members.last() {
Some(member) => match ir_module.types[member.ty].inner {
// Structs with dynamically sized arrays can't be copied and can't be wrapped.
crate::TypeInner::Array {
size: crate::ArraySize::Dynamic,
..
} => false,
_ => true,
},
None => false,
},
_ => false,
}
}
7 changes: 4 additions & 3 deletions src/back/spv/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ impl<'w> BlockContext<'w> {
let (structure_id, last_member_index) = match self.ir_function.expressions[array] {
crate::Expression::AccessIndex { base, index } => {
match self.ir_function.expressions[base] {
crate::Expression::GlobalVariable(handle) => {
(self.writer.global_variables[handle.index()].id, index)
}
crate::Expression::GlobalVariable(handle) => (
self.writer.global_variables[handle.index()].access_id,
index,
),
_ => return Err(Error::Validation("array length expression")),
}
}
Expand Down
Loading

0 comments on commit 8ffd6ba

Please sign in to comment.