Remove alignment from struct IR

This commit is contained in:
Dzmitry Malyshau
2021-05-16 00:46:46 -04:00
committed by Dzmitry Malyshau
parent 6efe347e90
commit b191c982ec
16 changed files with 152 additions and 186 deletions

View File

@@ -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 ")?;

View File

@@ -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, &[]);
}

View File

@@ -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<W: Write> Writer<W> {
// 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)?;
}
}

View File

@@ -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,
}

View File

@@ -353,9 +353,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
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
},

View File

@@ -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<crate::Type>, arena: &Arena<crate::Type>) -> 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<I> {
data: I,
state: ModuleState,
layouter: Layouter,
temp_bytes: Vec<u8>,
ext_glsl_id: Option<spirv::Word>,
future_decor: FastHashMap<spirv::Word, Decoration>,
@@ -432,6 +412,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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::<crate::StructMember>::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<I: Iterator<Item = u32>> Parser<I> {
}
}
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<I: Iterator<Item = u32>> Parser<I> {
}
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);

View File

@@ -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<Scope>,
lookup_type: FastHashMap<String, Handle<crate::Type>>,
layouter: layout::Layouter,
layouter: Layouter,
}
impl Parser {
@@ -1557,9 +1558,9 @@ impl Parser {
lexer: &mut Lexer<'a>,
type_arena: &mut Arena<crate::Type>,
const_arena: &mut Arena<crate::Constant>,
) -> Result<(Vec<crate::StructMember>, u32, crate::Alignment), Error<'a>> {
) -> Result<(Vec<crate::StructMember>, 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,
},

View File

@@ -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<StructMember>,
//TODO: should this be unaligned?
span: u32,
},
/// Possibly multidimensional array of texels.

View File

@@ -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<TypeLayout>,
}
impl ops::Index<Handle<crate::Type>> for Layouter {
type Output = TypeLayout;
fn index(&self, handle: Handle<crate::Type>) -> &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<crate::Type>);
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<crate::Type>,
align: Option<crate::Alignment>,
align: Option<Alignment>,
size: Option<NonZeroU32>,
) -> (ops::Range<u32>, crate::Alignment) {
) -> (ops::Range<u32>, 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<crate::Type>, constants: &Arena<crate::Constant>) {
pub fn update(
&mut self,
types: &Arena<crate::Type>,
constants: &Arena<crate::Constant>,
) -> 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(())
}
}

View File

@@ -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};

View File

@@ -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,
)
}

View File

@@ -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<r#type::TypeInfo>,
layouter: Layouter,
location_mask: BitSet,
bind_group_masks: Vec<BitSet>,
select_cases: FastHashSet<i32>,
@@ -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<crate::Type>,
@@ -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<ModuleInfo, ValidationError> {
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() {

View File

@@ -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<Option<crate::Alignment>, (Handle<crate::Type>, Disalignment)>;
type LayoutCompatibility = Result<Option<Alignment>, (Handle<crate::Type>, Disalignment)>;
fn check_member_layout(
accum: &mut LayoutCompatibility,
member: &crate::StructMember,
member_index: u32,
member_layout: LayoutCompatibility,
struct_level: crate::StructLevel,
ty_handle: Handle<crate::Type>,
parent_handle: Handle<crate::Type>,
) {
*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),

View File

@@ -18,7 +18,7 @@
(
name: Some("PrimeIndices"),
inner: Struct(
level: Root,
top_level: true,
members: [
(
name: Some("data"),

View File

@@ -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"),

View File

@@ -120,7 +120,7 @@ fn invalid_arrays() {
type Bad = array<Block, 4>;
"#:
Err(naga::valid::ValidationError::Type {
error: naga::valid::TypeError::NestedBlock,
error: naga::valid::TypeError::NestedTopLevel,
..
})
}