diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index ef2f149336..a9fe8ce043 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -663,7 +663,7 @@ impl<'a, W: Write> Writer<'a, W> { // glsl has no pointer types so just write types as normal and loads are skipped TypeInner::Pointer { base, .. } => self.write_type(base), TypeInner::Struct { - level: crate::StructLevel::Root, + top_level: true, ref members, span: _, } => self.write_struct(true, ty, members), @@ -743,8 +743,7 @@ impl<'a, W: Write> Writer<'a, W> { if let Some(storage_class) = glsl_storage_class(global.class) { write!(self.out, "{} ", storage_class)?; } else if let TypeInner::Struct { - level: crate::StructLevel::Root, - .. + top_level: true, .. } = self.module.types[global.ty].inner { write!(self.out, "struct ")?; diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index 8944666585..763cd0a6a0 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -916,11 +916,11 @@ impl Writer { } } crate::TypeInner::Struct { - ref level, + top_level, ref members, span: _, } => { - if let crate::StructLevel::Root = *level { + if top_level { self.decorate(id, Decoration::Block, &[]); } diff --git a/src/back/wgsl/writer.rs b/src/back/wgsl/writer.rs index 4d7701d652..19ba6df225 100644 --- a/src/back/wgsl/writer.rs +++ b/src/back/wgsl/writer.rs @@ -7,7 +7,7 @@ use crate::{ valid::{FunctionInfo, ModuleInfo}, Arena, ArraySize, Binding, Constant, Expression, FastHashMap, Function, GlobalVariable, Handle, ImageClass, ImageDimension, Interpolation, Module, SampleLevel, Sampling, ScalarKind, - ScalarValue, ShaderStage, Statement, StorageFormat, StructLevel, StructMember, Type, TypeInner, + ScalarValue, ShaderStage, Statement, StorageFormat, StructMember, Type, TypeInner, }; use bit_set::BitSet; use std::fmt::Write; @@ -94,11 +94,12 @@ impl Writer { // Write all structs for (handle, ty) in module.types.iter() { if let TypeInner::Struct { - level, ref members, .. + top_level, + ref members, + .. } = ty.inner { - let block = level == StructLevel::Root; - self.write_struct(module, handle, block, members)?; + self.write_struct(module, handle, top_level, members)?; writeln!(self.out)?; } } diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index 3f26863abc..8b46b7c669 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -521,46 +521,34 @@ pomelo! { if i.1 == "gl_PerVertex" { None } else { - let level = if t.is_empty() { - //TODO - crate::StructLevel::Normal { alignment: crate::Alignment::new(1).unwrap() } - } else { - crate::StructLevel::Root - }; Some(VarDeclaration { - type_qualifiers: t, ids_initializers: vec![(None, None)], ty: extra.module.types.fetch_or_append(Type{ name: Some(i.1), inner: TypeInner::Struct { - level, + top_level: !t.is_empty(), members: sdl, span: 0, //TODO }, }), + type_qualifiers: t, }) } } declaration ::= type_qualifier(t) Identifier(i1) LeftBrace struct_declaration_list(sdl) RightBrace Identifier(i2) Semicolon { - let level = if t.is_empty() { - //TODO - crate::StructLevel::Normal { alignment: crate::Alignment::new(1).unwrap() } - } else { - crate::StructLevel::Root - }; Some(VarDeclaration { - type_qualifiers: t, ids_initializers: vec![(Some(i2.1), None)], ty: extra.module.types.fetch_or_append(Type{ name: Some(i1.1), inner: TypeInner::Struct { - level, + top_level: !t.is_empty(), members: sdl, span: 0, //TODO }, }), + type_qualifiers: t, }) } @@ -761,7 +749,7 @@ pomelo! { Type{ name: Some(i.1), inner: TypeInner::Struct { - level: crate::StructLevel::Normal { alignment: crate::Alignment::new(1).unwrap() }, + top_level: false, members: vec![], span: 0, } diff --git a/src/front/spv/function.rs b/src/front/spv/function.rs index 449146e487..47dd75b195 100644 --- a/src/front/spv/function.rs +++ b/src/front/spv/function.rs @@ -353,9 +353,7 @@ impl> super::Parser { let ty = module.types.append(crate::Type { name: None, inner: crate::TypeInner::Struct { - level: crate::StructLevel::Normal { - alignment: crate::Alignment::new(1).unwrap(), - }, + top_level: false, members, span: 0xFFFF, // shouldn't matter }, diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index 7b62bce561..0a1e3113d8 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -40,6 +40,7 @@ use function::*; use crate::{ arena::{Arena, Handle}, + proc::{Alignment, Layouter}, FastHashMap, }; @@ -192,28 +193,6 @@ impl crate::ImageDimension { } } -//TODO: should this be shared with `crate::proc::wgsl::layout` logic? -fn get_alignment(ty: Handle, arena: &Arena) -> crate::Alignment { - use crate::TypeInner as Ti; - match arena[ty].inner { - Ti::Scalar { width, .. } => crate::Alignment::new(width as u32).unwrap(), - Ti::Vector { size, width, .. } - | Ti::Matrix { - rows: size, width, .. - } => { - let count = if size >= crate::VectorSize::Tri { 4 } else { 2 }; - crate::Alignment::new((count * width) as u32).unwrap() - } - Ti::Pointer { .. } | Ti::ValuePointer { .. } => crate::Alignment::new(1).unwrap(), - Ti::Array { stride, .. } => crate::Alignment::new(stride).unwrap(), - Ti::Struct { ref level, .. } => match *level { - crate::StructLevel::Root => crate::Alignment::new(1).unwrap(), - crate::StructLevel::Normal { alignment } => alignment, - }, - Ti::Image { .. } | Ti::Sampler { .. } => crate::Alignment::new(1).unwrap(), - } -} - type MemberIndex = u32; #[derive(Clone, Debug, Default, PartialEq)] @@ -395,6 +374,7 @@ impl Default for Options { pub struct Parser { data: I, state: ModuleState, + layouter: Layouter, temp_bytes: Vec, ext_glsl_id: Option, future_decor: FastHashMap, @@ -432,6 +412,7 @@ impl> Parser { Parser { data, state: ModuleState::Empty, + layouter: Layouter::default(), temp_bytes: Vec::new(), ext_glsl_id: None, future_decor: FastHashMap::default(), @@ -2319,6 +2300,7 @@ impl> Parser { self.index_constants.push(handle); } + self.layouter.clear(); self.dummy_functions = Arena::new(); self.lookup_function.clear(); self.function_call_graph.clear(); @@ -2946,7 +2928,11 @@ impl> Parser { let parent_decor = self.future_decor.remove(&id); let block_decor = parent_decor.as_ref().and_then(|decor| decor.block.clone()); - let mut struct_alignment = crate::Alignment::new(1).unwrap(); + self.layouter + .update(&module.types, &module.constants) + .unwrap(); + + let mut struct_alignment = Alignment::new(1).unwrap(); let mut members = Vec::::with_capacity(inst.wc as usize - 2); let mut member_lookups = Vec::with_capacity(members.capacity()); let mut storage_access = crate::StorageAccess::empty(); @@ -2989,8 +2975,7 @@ impl> Parser { } } - let alignment = get_alignment(ty, &module.types); - struct_alignment = struct_alignment.max(alignment); + struct_alignment = struct_alignment.max(self.layouter[ty].alignment); members.push(crate::StructMember { name: decor.name, @@ -3001,12 +2986,7 @@ impl> Parser { } let inner = crate::TypeInner::Struct { - level: match block_decor { - Some(_) => crate::StructLevel::Root, - None => crate::StructLevel::Normal { - alignment: struct_alignment, - }, - }, + top_level: block_decor.is_some(), span: match members.last() { Some(member) => { let end = member.offset + module.types[member.ty].inner.span(&module.constants); diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index 51ebde4174..0235cb962b 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -3,14 +3,15 @@ //! [wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html mod conv; -mod layout; mod lexer; #[cfg(test)] mod tests; use crate::{ arena::{Arena, Handle}, - proc::{ensure_block_returns, ResolveContext, ResolveError, TypeResolution}, + proc::{ + ensure_block_returns, Alignment, Layouter, ResolveContext, ResolveError, TypeResolution, + }, FastHashMap, }; @@ -607,7 +608,7 @@ impl std::error::Error for ParseError { pub struct Parser { scopes: Vec, lookup_type: FastHashMap>, - layouter: layout::Layouter, + layouter: Layouter, } impl Parser { @@ -1557,9 +1558,9 @@ impl Parser { lexer: &mut Lexer<'a>, type_arena: &mut Arena, const_arena: &mut Arena, - ) -> Result<(Vec, u32, crate::Alignment), Error<'a>> { + ) -> Result<(Vec, u32), Error<'a>> { let mut offset = 0; - let mut alignment = crate::Alignment::new(1).unwrap(); + let mut alignment = Alignment::new(1).unwrap(); let mut members = Vec::new(); lexer.expect(Token::Paren('{'))?; @@ -1606,8 +1607,8 @@ impl Parser { let name = match lexer.next() { (Token::Word(word), _) => word, (Token::Paren('}'), _) => { - let span = layout::Layouter::round_up(alignment, offset); - return Ok((members, span, alignment)); + let span = Layouter::round_up(alignment, offset); + return Ok((members, span)); } other => return Err(Error::Unexpected(other, "field name")), }; @@ -1615,7 +1616,8 @@ impl Parser { let (ty, _access) = self.parse_type_decl(lexer, None, type_arena, const_arena)?; lexer.expect(Token::Separator(';'))?; - self.layouter.update(type_arena, const_arena); + self.layouter.update(type_arena, const_arena).unwrap(); + let (range, align) = self.layouter.member_placement(offset, ty, align, size); alignment = alignment.max(align); offset = range.end; @@ -2603,16 +2605,12 @@ impl Parser { (Token::Separator(';'), _) => {} (Token::Word("struct"), _) => { let name = lexer.next_ident()?; - let (members, span, alignment) = + let (members, span) = self.parse_struct_body(lexer, &mut module.types, &mut module.constants)?; let ty = module.types.fetch_or_append(crate::Type { name: Some(name.to_string()), inner: crate::TypeInner::Struct { - level: if is_block { - crate::StructLevel::Root - } else { - crate::StructLevel::Normal { alignment } - }, + top_level: is_block, members, span, }, diff --git a/src/lib.rs b/src/lib.rs index 058a5a9e8e..8a5ab20b79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,6 @@ pub use crate::arena::{Arena, Handle, Range}; use std::{ collections::{HashMap, HashSet}, hash::BuildHasherDefault, - num::NonZeroU32, }; #[cfg(feature = "deserialize")] @@ -169,7 +168,6 @@ pub enum BuiltIn { /// Number of bytes per scalar. pub type Bytes = u8; -pub type Alignment = NonZeroU32; /// Number of components in a vector. #[repr(u8)] @@ -358,18 +356,6 @@ pub enum ImageClass { Storage(StorageFormat), } -/// Qualifier of the type level, at which a struct can be used. -#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serialize", derive(Serialize))] -#[cfg_attr(feature = "deserialize", derive(Deserialize))] -pub enum StructLevel { - /// This is a root level struct, it can't be nested inside - /// other composite types. - Root, - /// This is a normal struct, and it has to be aligned for nesting. - Normal { alignment: Alignment }, -} - /// A data type declared in the module. #[derive(Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] @@ -420,8 +406,9 @@ pub enum TypeInner { }, /// User-defined structure. Struct { - level: StructLevel, + top_level: bool, members: Vec, + //TODO: should this be unaligned? span: u32, }, /// Possibly multidimensional array of texels. diff --git a/src/front/wgsl/layout.rs b/src/proc/layouter.rs similarity index 58% rename from src/front/wgsl/layout.rs rename to src/proc/layouter.rs index e17d5548e1..d6c67e0aa4 100644 --- a/src/front/wgsl/layout.rs +++ b/src/proc/layouter.rs @@ -1,13 +1,15 @@ use crate::arena::{Arena, Handle}; use std::{num::NonZeroU32, ops}; +pub type Alignment = NonZeroU32; + /// Alignment information for a type. #[derive(Clone, Copy, Debug, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct TypeLayout { pub size: u32, - pub alignment: crate::Alignment, + pub alignment: Alignment, } /// Helper processor that derives the sizes of all types. @@ -20,12 +22,23 @@ pub struct Layouter { layouts: Vec, } +impl ops::Index> for Layouter { + type Output = TypeLayout; + fn index(&self, handle: Handle) -> &TypeLayout { + &self.layouts[handle.index()] + } +} + +#[derive(Clone, Copy, Debug, PartialEq, thiserror::Error)] +#[error("Base type {0:?} is out of bounds")] +pub struct InvalidBaseType(pub Handle); + impl Layouter { pub fn clear(&mut self) { self.layouts.clear(); } - pub fn round_up(alignment: crate::Alignment, offset: u32) -> u32 { + pub fn round_up(alignment: Alignment, offset: u32) -> u32 { match offset & (alignment.get() - 1) { 0 => offset, other => offset + alignment.get() - other, @@ -36,9 +49,9 @@ impl Layouter { &self, offset: u32, ty: Handle, - align: Option, + align: Option, size: Option, - ) -> (ops::Range, crate::Alignment) { + ) -> (ops::Range, Alignment) { let layout = self.layouts[ty.index()]; let alignment = align.unwrap_or(layout.alignment); let start = Self::round_up(alignment, offset); @@ -49,14 +62,19 @@ impl Layouter { (start..start + span, alignment) } - pub fn update(&mut self, types: &Arena, constants: &Arena) { + pub fn update( + &mut self, + types: &Arena, + constants: &Arena, + ) -> Result<(), InvalidBaseType> { use crate::TypeInner as Ti; - for (_, ty) in types.iter().skip(self.layouts.len()) { + + for (ty_handle, ty) in types.iter().skip(self.layouts.len()) { let size = ty.inner.span(constants); let layout = match ty.inner { Ti::Scalar { width, .. } => TypeLayout { size, - alignment: crate::Alignment::new(width as u32).unwrap(), + alignment: Alignment::new(width as u32).unwrap(), }, Ti::Vector { size: vec_size, @@ -70,7 +88,7 @@ impl Layouter { } else { 2 }; - crate::Alignment::new((count * width) as u32).unwrap() + Alignment::new((count * width) as u32).unwrap() }, }, Ti::Matrix { @@ -81,35 +99,52 @@ impl Layouter { size, alignment: { let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 }; - crate::Alignment::new((count * width) as u32).unwrap() + Alignment::new((count * width) as u32).unwrap() }, }, Ti::Pointer { .. } | Ti::ValuePointer { .. } => TypeLayout { size, - alignment: crate::Alignment::new(1).unwrap(), + alignment: Alignment::new(1).unwrap(), }, - Ti::Array { stride, .. } => TypeLayout { - size, - alignment: crate::Alignment::new(stride).unwrap(), - }, - Ti::Struct { - ref level, - members: _, - span, + Ti::Array { + base, + stride: _, + size: _, } => TypeLayout { - size: span, - alignment: match *level { - crate::StructLevel::Root => crate::Alignment::new(1).unwrap(), - crate::StructLevel::Normal { alignment } => alignment, + size, + alignment: if base < ty_handle { + self[base].alignment + } else { + return Err(InvalidBaseType(base)); }, }, + Ti::Struct { + top_level: _, + span, + ref members, + } => { + let mut alignment = Alignment::new(1).unwrap(); + for member in members { + alignment = if member.ty < ty_handle { + alignment.max(self[member.ty].alignment) + } else { + return Err(InvalidBaseType(member.ty)); + }; + } + TypeLayout { + size: span, + alignment, + } + } Ti::Image { .. } | Ti::Sampler { .. } => TypeLayout { size, - alignment: crate::Alignment::new(1).unwrap(), + alignment: Alignment::new(1).unwrap(), }, }; debug_assert!(ty.inner.span(constants) <= layout.size); self.layouts.push(layout); } + + Ok(()) } } diff --git a/src/proc/mod.rs b/src/proc/mod.rs index 49bab5528d..58926c1d83 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -1,10 +1,12 @@ //! Module processing functionality. mod interpolator; +mod layouter; mod namer; mod terminator; mod typifier; +pub use layouter::{Alignment, InvalidBaseType, Layouter, TypeLayout}; pub use namer::{EntryPointIndex, NameKey, Namer}; pub use terminator::ensure_block_returns; pub use typifier::{ResolveContext, ResolveError, TypeResolution}; diff --git a/src/valid/interface.rs b/src/valid/interface.rs index 6a9949a652..3d7830b8ac 100644 --- a/src/valid/interface.rs +++ b/src/valid/interface.rs @@ -262,7 +262,7 @@ impl VaryingContext<'_> { match self.types[self.ty].inner { //TODO: check the member types crate::TypeInner::Struct { - level: crate::StructLevel::Normal { .. }, + top_level: false, ref members, .. } => { @@ -303,7 +303,7 @@ impl super::Validator { } ( crate::StorageAccess::all(), - TypeFlags::DATA | TypeFlags::HOST_SHARED | TypeFlags::BLOCK, + TypeFlags::DATA | TypeFlags::HOST_SHARED | TypeFlags::TOP_LEVEL, true, ) } @@ -315,7 +315,10 @@ impl super::Validator { } ( crate::StorageAccess::empty(), - TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::HOST_SHARED | TypeFlags::BLOCK, + TypeFlags::DATA + | TypeFlags::SIZED + | TypeFlags::HOST_SHARED + | TypeFlags::TOP_LEVEL, true, ) } diff --git a/src/valid/mod.rs b/src/valid/mod.rs index c34eeebd2c..3d22cb34eb 100644 --- a/src/valid/mod.rs +++ b/src/valid/mod.rs @@ -7,6 +7,7 @@ mod r#type; use crate::{ arena::{Arena, Handle}, + proc::{InvalidBaseType, Layouter}, FastHashSet, }; use bit_set::BitSet; @@ -91,6 +92,7 @@ pub struct Validator { flags: ValidationFlags, capabilities: Capabilities, types: Vec, + layouter: Layouter, location_mask: BitSet, bind_group_masks: Vec, select_cases: FastHashSet, @@ -112,6 +114,8 @@ pub enum ConstantError { #[derive(Clone, Debug, thiserror::Error)] pub enum ValidationError { + #[error(transparent)] + Layouter(#[from] InvalidBaseType), #[error("Type {handle:?} '{name}' is invalid")] Type { handle: Handle, @@ -196,6 +200,7 @@ impl Validator { flags, capabilities, types: Vec::new(), + layouter: Layouter::default(), location_mask: BitSet::new(), bind_group_masks: Vec::new(), select_cases: FastHashSet::default(), @@ -246,6 +251,7 @@ impl Validator { /// Check the given module to be valid. pub fn validate(&mut self, module: &crate::Module) -> Result { self.reset_types(module.types.len()); + self.layouter.update(&module.types, &module.constants)?; if self.flags.contains(ValidationFlags::CONSTANTS) { for (handle, constant) in module.constants.iter() { diff --git a/src/valid/type.rs b/src/valid/type.rs index 056af0508d..df0a401c01 100644 --- a/src/valid/type.rs +++ b/src/valid/type.rs @@ -1,5 +1,8 @@ use super::Capabilities; -use crate::arena::{Arena, Handle}; +use crate::{ + arena::{Arena, Handle}, + proc::Alignment, +}; bitflags::bitflags! { #[repr(transparent)] @@ -13,7 +16,7 @@ bitflags::bitflags! { /// Can be used for host-shareable structures. const HOST_SHARED = 0x8; /// This is a top-level host-shareable type. - const BLOCK = 0x10; + const TOP_LEVEL = 0x10; } } @@ -23,12 +26,6 @@ pub enum Disalignment { ArrayStride { stride: u32, alignment: u32 }, #[error("The struct span {span}, is not a multiple of the required alignment {alignment}")] StructSpan { span: u32, alignment: u32 }, - #[error("The struct span {alignment}, is not a multiple of the member[{member_index}] alignment {member_alignment}")] - StructAlignment { - alignment: u32, - member_index: u32, - member_alignment: u32, - }, #[error("The struct member[{index}] offset {offset} is not a multiple of the required alignment {alignment}")] MemberOffset { index: u32, @@ -63,27 +60,26 @@ pub enum TypeError { "Structure member[{index}] at {offset} and size {size} crosses the structure boundary" )] MemberOutOfBounds { index: u32, offset: u32, size: u32 }, - #[error("The composite type contains a block structure")] - NestedBlock, + #[error("The composite type contains a top-level structure")] + NestedTopLevel, } // Only makes sense if `flags.contains(HOST_SHARED)` -type LayoutCompatibility = Result, (Handle, Disalignment)>; +type LayoutCompatibility = Result, (Handle, Disalignment)>; fn check_member_layout( accum: &mut LayoutCompatibility, member: &crate::StructMember, member_index: u32, member_layout: LayoutCompatibility, - struct_level: crate::StructLevel, - ty_handle: Handle, + parent_handle: Handle, ) { *accum = match (*accum, member_layout) { (Ok(cur_alignment), Ok(align)) => { let align = align.unwrap().get(); if member.offset % align != 0 { Err(( - ty_handle, + parent_handle, Disalignment::MemberOffset { index: member_index, offset: member.offset, @@ -91,32 +87,14 @@ fn check_member_layout( }, )) } else { - match struct_level { - crate::StructLevel::Normal { alignment } if alignment.get() % align != 0 => { - Err(( - ty_handle, - Disalignment::StructAlignment { - alignment: alignment.get(), - member_index, - member_alignment: align, - }, - )) - } - _ => { - let combined_alignment = - ((cur_alignment.unwrap().get() - 1) | (align - 1)) + 1; - Ok(crate::Alignment::new(combined_alignment)) - } - } + let combined_alignment = ((cur_alignment.unwrap().get() - 1) | (align - 1)) + 1; + Ok(Alignment::new(combined_alignment)) } } (Err(e), _) | (_, Err(e)) => Err(e), }; } -// For the uniform buffer alignment, array strides and struct sizes must be multiples of 16. -const UNIFORM_LAYOUT_ALIGNMENT_MASK: u32 = 0xF; - #[derive(Clone, Debug)] pub(super) struct TypeInfo { pub flags: TypeFlags, @@ -134,7 +112,7 @@ impl TypeInfo { } fn new(flags: TypeFlags, align: u32) -> Self { - let alignment = crate::Alignment::new(align); + let alignment = Alignment::new(align); TypeInfo { flags, uniform_layout: Ok(alignment), @@ -157,6 +135,7 @@ impl super::Validator { pub(super) fn reset_types(&mut self, size: usize) { self.types.clear(); self.types.resize(size, TypeInfo::dummy()); + self.layouter.clear(); } pub(super) fn validate_type( @@ -234,8 +213,8 @@ impl super::Validator { if !base_info.flags.contains(TypeFlags::DATA | TypeFlags::SIZED) { return Err(TypeError::InvalidArrayBaseType(base)); } - if base_info.flags.contains(TypeFlags::BLOCK) { - return Err(TypeError::NestedBlock); + if base_info.flags.contains(TypeFlags::TOP_LEVEL) { + return Err(TypeError::NestedTopLevel); } let base_size = types[base].inner.span(constants); @@ -243,11 +222,12 @@ impl super::Validator { return Err(TypeError::InsufficientArrayStride { stride, base_size }); } + let general_alignment = self.layouter[base].alignment; let uniform_layout = match base_info.uniform_layout { Ok(base_alignment) => { // combine the alignment requirements let align = ((base_alignment.unwrap().get() - 1) - | UNIFORM_LAYOUT_ALIGNMENT_MASK) + | (general_alignment.get() - 1)) + 1; if stride % align != 0 { Err(( @@ -258,14 +238,16 @@ impl super::Validator { }, )) } else { - Ok(crate::Alignment::new(align)) + Ok(Alignment::new(align)) } } Err(e) => Err(e), }; let storage_layout = match base_info.storage_layout { Ok(base_alignment) => { - let align = base_alignment.unwrap().get(); + let align = ((base_alignment.unwrap().get() - 1) + | (general_alignment.get() - 1)) + + 1; if stride % align != 0 { Err(( handle, @@ -275,7 +257,7 @@ impl super::Validator { }, )) } else { - Ok(base_alignment) + Ok(Alignment::new(align)) } } Err(e) => Err(e), @@ -324,7 +306,7 @@ impl super::Validator { } } Ti::Struct { - level, + top_level, ref members, span, } => { @@ -336,6 +318,7 @@ impl super::Validator { 1, ); let mut min_offset = 0; + for (i, member) in members.iter().enumerate() { if member.ty >= handle { return Err(TypeError::UnresolvedBase(member.ty)); @@ -344,13 +327,11 @@ impl super::Validator { if !base_info.flags.contains(TypeFlags::DATA) { return Err(TypeError::InvalidData(member.ty)); } - if level == crate::StructLevel::Root - && !base_info.flags.contains(TypeFlags::INTERFACE) - { + if top_level && !base_info.flags.contains(TypeFlags::INTERFACE) { return Err(TypeError::InvalidBlockType(member.ty)); } - if base_info.flags.contains(TypeFlags::BLOCK) { - return Err(TypeError::NestedBlock); + if base_info.flags.contains(TypeFlags::TOP_LEVEL) { + return Err(TypeError::NestedTopLevel); } ti.flags &= base_info.flags; @@ -382,7 +363,6 @@ impl super::Validator { member, i as u32, base_info.uniform_layout, - level, handle, ); check_member_layout( @@ -390,7 +370,6 @@ impl super::Validator { member, i as u32, base_info.storage_layout, - level, handle, ); @@ -406,24 +385,16 @@ impl super::Validator { } } } - if let crate::StructLevel::Root = level { - ti.flags |= TypeFlags::BLOCK; + if top_level { + ti.flags |= TypeFlags::TOP_LEVEL; } - // disabled temporarily, see https://github.com/gpuweb/gpuweb/issues/1558 - const CHECK_STRUCT_SIZE: bool = false; - if CHECK_STRUCT_SIZE - && ti.uniform_layout.is_ok() - && span & UNIFORM_LAYOUT_ALIGNMENT_MASK != 0 - { - ti.uniform_layout = Err(( - handle, - Disalignment::StructSpan { - span, - alignment: UNIFORM_LAYOUT_ALIGNMENT_MASK + 1, - }, - )); + let alignment = self.layouter[handle].alignment.get(); + if span % alignment != 0 { + ti.uniform_layout = Err((handle, Disalignment::StructSpan { span, alignment })); + ti.storage_layout = Err((handle, Disalignment::StructSpan { span, alignment })); } + ti } Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::new(TypeFlags::empty(), 0), diff --git a/tests/out/collatz.ron b/tests/out/collatz.ron index 65f98a6e8f..7fe6a38eff 100644 --- a/tests/out/collatz.ron +++ b/tests/out/collatz.ron @@ -18,7 +18,7 @@ ( name: Some("PrimeIndices"), inner: Struct( - level: Root, + top_level: true, members: [ ( name: Some("data"), diff --git a/tests/out/shadow.ron b/tests/out/shadow.ron index 6d55e1bd7c..fd91f99af8 100644 --- a/tests/out/shadow.ron +++ b/tests/out/shadow.ron @@ -102,7 +102,7 @@ ( name: Some("Globals"), inner: Struct( - level: Root, + top_level: true, members: [ ( name: Some("num_lights"), @@ -146,9 +146,7 @@ ( name: Some("Light"), inner: Struct( - level: Normal( - alignment: 16, - ), + top_level: false, members: [ ( name: Some("proj"), @@ -183,7 +181,7 @@ ( name: Some("Lights"), inner: Struct( - level: Root, + top_level: true, members: [ ( name: Some("data"), diff --git a/tests/wgsl-errors.rs b/tests/wgsl-errors.rs index 5a03f47857..cf4a91d817 100644 --- a/tests/wgsl-errors.rs +++ b/tests/wgsl-errors.rs @@ -120,7 +120,7 @@ fn invalid_arrays() { type Bad = array; "#: Err(naga::valid::ValidationError::Type { - error: naga::valid::TypeError::NestedBlock, + error: naga::valid::TypeError::NestedTopLevel, .. }) }