New struct layout IR

This commit is contained in:
Dzmitry Malyshau 2021-04-04 10:26:28 -04:00 committed by Dzmitry Malyshau
parent 5a0e3ad5ff
commit 7326ba6ddb
16 changed files with 312 additions and 494 deletions

View File

@ -1389,6 +1389,14 @@ impl<W: Write> Writer<W> {
first_time: false,
};
writeln!(self.out, "{}{} {};", INDENT, base_name, member_name)?;
// quick and dirty way to figure out if we need this...
if member.binding.is_none() {
let pad =
member.span - module.types[member.ty].inner.span(&module.constants);
if pad != 0 {
writeln!(self.out, "{}char _pad{}[{}];", INDENT, index, pad)?;
}
}
}
writeln!(self.out, "}};")?;
}

View File

@ -3,7 +3,7 @@ use super::{
};
use crate::{
arena::{Arena, Handle},
proc::{Layouter, TypeResolution},
proc::TypeResolution,
valid::{FunctionInfo, ModuleInfo},
};
use spirv::Word;
@ -760,10 +760,10 @@ impl Writer {
fn write_type_declaration_arena(
&mut self,
arena: &Arena<crate::Type>,
layouter: &Layouter,
handle: Handle<crate::Type>,
) -> Result<Word, Error> {
let ty = &arena[handle];
let decorate_layout = true; //TODO?
let id = if let Some(local) = self.physical_layout.make_local(&ty.inner) {
match self.lookup_type.entry(LookupType::Local(local)) {
@ -845,11 +845,11 @@ impl Writer {
}
crate::TypeInner::Sampler { comparison: _ } => Instruction::type_sampler(id),
crate::TypeInner::Array { base, size, stride } => {
if let Some(array_stride) = stride {
if decorate_layout {
self.annotations.push(Instruction::decorate(
id,
Decoration::ArrayStride,
&[array_stride.get()],
&[stride],
));
}
@ -871,14 +871,15 @@ impl Writer {
let mut current_offset = 0;
let mut member_ids = Vec::with_capacity(members.len());
for (index, member) in members.iter().enumerate() {
let (placement, _) = layouter.member_placement(current_offset, member);
self.annotations.push(Instruction::member_decorate(
id,
index as u32,
Decoration::Offset,
&[placement.start],
));
current_offset = placement.end;
if decorate_layout {
self.annotations.push(Instruction::member_decorate(
id,
index as u32,
Decoration::Offset,
&[current_offset],
));
current_offset += member.span;
}
if self.flags.contains(WriterFlags::DEBUG) {
if let Some(ref name) = member.name {
@ -1073,11 +1074,8 @@ impl Writer {
match *binding {
crate::Binding::Location(location, interpolation) => {
self.annotations.push(Instruction::decorate(
id,
Decoration::Location,
&[location],
));
self.annotations
.push(Instruction::decorate(id, Decoration::Location, &[location]));
let interp_decoration = match interpolation {
Some(crate::Interpolation::Linear) => Some(Decoration::NoPerspective),
Some(crate::Interpolation::Flat) => Some(Decoration::Flat),
@ -2540,7 +2538,7 @@ impl Writer {
// then all types, some of them may rely on constants and struct type set
for (handle, _) in ir_module.types.iter() {
self.write_type_declaration_arena(&ir_module.types, &mod_info.layouter, handle)?;
self.write_type_declaration_arena(&ir_module.types, handle)?;
}
// the all the composite constants, they rely on types

View File

@ -729,8 +729,7 @@ pomelo! {
binding: None, //TODO
//TODO: if the struct is a uniform struct, these values have to reflect
// std140 layout. Otherwise, std430.
size: None,
align: None,
span: extra.module.types[ty].inner.span(&extra.module.constants),
}).collect()
} else {
return Err(ErrorKind::SemanticError("Struct member can't be void".into()))

View File

@ -248,13 +248,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
// unrecognized binding, skip
continue;
}
members.push(crate::StructMember {
name: sm.name.clone(),
ty: sm.ty,
binding: sm.binding.clone(),
size: None,
align: None,
});
members.push(sm.clone());
components.push(function.expressions.append(
crate::Expression::AccessIndex {
base: expr_handle,
@ -268,8 +262,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
name: None,
ty: result.ty,
binding: result.binding.clone(),
size: None,
align: None,
span: module.types[result.ty].inner.span(&module.constants),
});
// populate just the globals first, then do `Load` in a
// separate step, so that we can get a range.

View File

@ -2419,17 +2419,21 @@ impl<I: Iterator<Item = u32>> Parser<I> {
let length_id = self.next()?;
let length_const = self.lookup_constant.lookup(length_id)?;
let decor = self.future_decor.remove(&id);
let decor = self.future_decor.remove(&id).unwrap_or_default();
let base = self.lookup_type.lookup(type_id)?.handle;
let inner = crate::TypeInner::Array {
base: self.lookup_type.lookup(type_id)?.handle,
base,
size: crate::ArraySize::Constant(length_const.handle),
stride: decor.as_ref().and_then(|dec| dec.array_stride),
stride: match decor.array_stride {
Some(stride) => stride.get(),
None => module.types[base].inner.span(&module.constants),
},
};
self.lookup_type.insert(
id,
LookupType {
handle: module.types.append(crate::Type {
name: decor.and_then(|dec| dec.name),
name: decor.name,
inner,
}),
base_id: Some(type_id),
@ -2448,17 +2452,21 @@ impl<I: Iterator<Item = u32>> Parser<I> {
let id = self.next()?;
let type_id = self.next()?;
let decor = self.future_decor.remove(&id);
let decor = self.future_decor.remove(&id).unwrap_or_default();
let base = self.lookup_type.lookup(type_id)?.handle;
let inner = crate::TypeInner::Array {
base: self.lookup_type.lookup(type_id)?.handle,
size: crate::ArraySize::Dynamic,
stride: decor.as_ref().and_then(|dec| dec.array_stride),
stride: match decor.array_stride {
Some(stride) => stride.get(),
None => module.types[base].inner.span(&module.constants),
},
};
self.lookup_type.insert(
id,
LookupType {
handle: module.types.append(crate::Type {
name: decor.and_then(|dec| dec.name),
name: decor.name,
inner,
}),
base_id: Some(type_id),
@ -2478,8 +2486,9 @@ 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 members = Vec::with_capacity(inst.wc as usize - 2);
let mut members = Vec::<crate::StructMember>::with_capacity(inst.wc as usize - 2);
let mut member_type_ids = Vec::with_capacity(members.capacity());
let mut last_offset = 0;
for i in 0..u32::from(inst.wc) - 2 {
let type_id = self.next()?;
member_type_ids.push(type_id);
@ -2489,12 +2498,24 @@ impl<I: Iterator<Item = u32>> Parser<I> {
.remove(&(id, i))
.unwrap_or_default();
let binding = decor.io_binding().ok();
if let Some(offset) = decor.offset {
if offset != last_offset {
if let Some(member) = members.last_mut() {
// add padding, if necessary
member.span = offset - (last_offset - member.span);
}
last_offset = offset;
}
}
let span = module.types[ty].inner.span(&module.constants);
last_offset += span;
members.push(crate::StructMember {
name: decor.name,
ty,
binding,
size: None, //TODO
align: None,
span,
});
}

View File

@ -1,5 +1,5 @@
use crate::arena::{Arena, Handle};
use std::{num::NonZeroU32, ops};
use std::num::NonZeroU32;
pub type Alignment = NonZeroU32;
@ -22,14 +22,17 @@ pub struct Layouter {
layouts: Vec<TypeLayout>,
}
pub struct Placement {
pub pad: crate::Span,
pub span: crate::Span,
}
impl Layouter {
pub fn new(types: &Arena<crate::Type>, constants: &Arena<crate::Constant>) -> Self {
let mut this = Layouter::default();
this.initialize(types, constants);
this
pub fn clear(&mut self) {
self.layouts.clear();
}
pub fn round_up(alignment: NonZeroU32, offset: u32) -> u32 {
pub fn round_up(alignment: Alignment, offset: u32) -> u32 {
match offset & (alignment.get() - 1) {
0 => offset,
other => offset + alignment.get() - other,
@ -39,78 +42,66 @@ impl Layouter {
pub fn member_placement(
&self,
offset: u32,
member: &crate::StructMember,
) -> (ops::Range<u32>, NonZeroU32) {
let layout = self.layouts[member.ty.index()];
let alignment = member.align.unwrap_or(layout.alignment);
ty: Handle<crate::Type>,
align: Option<Alignment>,
size: Option<NonZeroU32>,
) -> Placement {
let layout = self.layouts[ty.index()];
let alignment = align.unwrap_or(layout.alignment);
let start = Self::round_up(alignment, offset);
let end = start
+ match member.size {
Some(size) => size.get(),
None => layout.size,
};
(start..end, alignment)
let span = match size {
Some(size) => size.get(),
None => layout.size,
};
Placement {
pad: start - offset,
span,
}
}
pub fn initialize(&mut self, types: &Arena<crate::Type>, constants: &Arena<crate::Constant>) {
pub fn update(&mut self, types: &Arena<crate::Type>, constants: &Arena<crate::Constant>) {
use crate::TypeInner as Ti;
self.layouts.clear();
self.layouts.reserve(types.len());
for (_, ty) in types.iter() {
self.layouts.push(match ty.inner {
Ti::Scalar { kind: _, width } => TypeLayout {
size: width as u32,
for (_, 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: Alignment::new(width as u32).unwrap(),
},
Ti::Vector {
size,
kind: _,
size: vec_size,
width,
..
} => TypeLayout {
size: (size as u8 * width) as u32,
size,
alignment: {
let count = if size >= crate::VectorSize::Tri { 4 } else { 2 };
let count = if vec_size >= crate::VectorSize::Tri {
4
} else {
2
};
Alignment::new((count * width) as u32).unwrap()
},
},
Ti::Matrix {
columns,
columns: _,
rows,
width,
} => TypeLayout {
size: (columns as u8 * rows as u8 * width) as u32,
size,
alignment: {
let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 };
Alignment::new((count * width) as u32).unwrap()
},
},
Ti::Pointer { .. } | Ti::ValuePointer { .. } => TypeLayout {
size: 4,
size,
alignment: Alignment::new(1).unwrap(),
},
Ti::Array { base, size, stride } => {
let count = match size {
crate::ArraySize::Constant(handle) => {
constants[handle].to_array_length().unwrap()
}
// A dynamically-sized array has to have at least one element
crate::ArraySize::Dynamic => 1,
};
let stride = match stride {
Some(value) => value,
None => {
let layout = &self.layouts[base.index()];
let stride = Self::round_up(layout.alignment, layout.size);
Alignment::new(stride).unwrap()
}
};
TypeLayout {
size: count * stride.get(),
alignment: stride,
}
}
Ti::Array { stride, .. } => TypeLayout {
size,
alignment: Alignment::new(stride).unwrap(),
},
Ti::Struct {
block: _,
ref members,
@ -118,9 +109,9 @@ impl Layouter {
let mut total = 0;
let mut biggest_alignment = Alignment::new(1).unwrap();
for member in members {
let (placement, alignment) = self.member_placement(total, member);
biggest_alignment = biggest_alignment.max(alignment);
total = placement.end;
let layout = self.layouts[member.ty.index()];
biggest_alignment = biggest_alignment.max(layout.alignment);
total += member.span;
}
TypeLayout {
size: Self::round_up(biggest_alignment, total),
@ -128,17 +119,12 @@ impl Layouter {
}
}
Ti::Image { .. } | Ti::Sampler { .. } => TypeLayout {
size: 0,
size,
alignment: Alignment::new(1).unwrap(),
},
});
};
debug_assert!(ty.inner.span(constants) <= layout.size);
self.layouts.push(layout);
}
}
}
impl ops::Index<Handle<crate::Type>> for Layouter {
type Output = TypeLayout;
fn index(&self, handle: Handle<crate::Type>) -> &TypeLayout {
&self.layouts[handle.index()]
}
}

View File

@ -3,6 +3,7 @@
//! [wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html
mod conv;
mod layout;
mod lexer;
#[cfg(test)]
mod tests;
@ -560,6 +561,7 @@ impl<'a> std::error::Error for ParseError<'a> {
pub struct Parser {
scopes: Vec<Scope>,
lookup_type: FastHashMap<String, Handle<crate::Type>>,
layouter: layout::Layouter,
}
impl Parser {
@ -567,6 +569,7 @@ impl Parser {
Parser {
scopes: Vec::new(),
lookup_type: FastHashMap::default(),
layouter: Default::default(),
}
}
@ -1507,7 +1510,9 @@ impl Parser {
type_arena: &mut Arena<crate::Type>,
const_arena: &mut Arena<crate::Constant>,
) -> Result<Vec<crate::StructMember>, Error<'a>> {
let mut offset = 0;
let mut members = Vec::new();
lexer.expect(Token::Paren('{'))?;
loop {
let (mut size, mut align) = (None, None);
@ -1558,12 +1563,18 @@ 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);
let placement = self.layouter.member_placement(offset, ty, align, size);
if placement.pad != 0 {
members.last_mut().unwrap().span += placement.pad;
}
offset += placement.pad + placement.span;
members.push(crate::StructMember {
name: Some(name.to_owned()),
ty,
binding: bind_parser.finish()?,
size,
align,
span: placement.span,
});
}
}
@ -1708,12 +1719,12 @@ impl Parser {
crate::ArraySize::Dynamic
};
lexer.expect_generic_paren('>')?;
let stride = match attribute.stride {
Some(stride) => stride.get(),
None => type_arena[base].inner.span(const_arena),
};
crate::TypeInner::Array {
base,
size,
stride: attribute.stride,
}
crate::TypeInner::Array { base, size, stride }
}
"sampler" => crate::TypeInner::Sampler { comparison: false },
"sampler_comparison" => crate::TypeInner::Sampler { comparison: true },
@ -1916,14 +1927,8 @@ impl Parser {
let storage_access = attribute.access;
let name = lexer.next_ident()?;
let handle = self.parse_type_decl_name(
lexer,
name,
debug_name,
attribute,
type_arena,
const_arena,
)?;
let handle =
self.parse_type_decl_name(lexer, name, debug_name, attribute, type_arena, const_arena)?;
self.scopes.pop();
Ok((handle, storage_access))
}
@ -2671,6 +2676,7 @@ impl Parser {
pub fn parse<'a>(&mut self, source: &'a str) -> Result<crate::Module, ParseError<'a>> {
self.scopes.clear();
self.lookup_type.clear();
self.layouter.clear();
let mut module = crate::Module::default();
let mut lexer = Lexer::new(source);

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")]
@ -166,8 +165,10 @@ pub enum BuiltIn {
WorkGroupSize,
}
/// Number of bytes.
/// Number of bytes per scalar.
pub type Bytes = u8;
/// Number of bytes per complex type.
pub type Span = u32;
/// Number of components in a vector.
#[repr(u8)]
@ -244,10 +245,8 @@ pub struct StructMember {
pub ty: Handle<Type>,
/// For I/O structs, defines the binding.
pub binding: Option<Binding>,
/// Overrides the size computed off the type.
pub size: Option<NonZeroU32>,
/// Overrides the alignment computed off the type.
pub align: Option<NonZeroU32>,
/// Size occupied by the member.
pub span: Span,
}
/// The number of dimensions an image has.
@ -392,7 +391,7 @@ pub enum TypeInner {
Array {
base: Handle<Type>,
size: ArraySize,
stride: Option<NonZeroU32>,
stride: Span,
},
/// User-defined structure.
Struct {

View File

@ -1,11 +1,9 @@
//! Module processing functionality.
mod layouter;
mod namer;
mod terminator;
mod typifier;
pub use layouter::{Alignment, Layouter, TypeLayout};
pub use namer::{EntryPointIndex, NameKey, Namer};
pub use terminator::ensure_block_returns;
pub use typifier::{ResolveContext, ResolveError, TypeResolution};
@ -61,6 +59,8 @@ impl super::ScalarValue {
}
}
pub const POINTER_SPAN: u32 = 4;
impl super::TypeInner {
pub fn scalar_kind(&self) -> Option<super::ScalarKind> {
match *self {
@ -71,6 +71,50 @@ impl super::TypeInner {
_ => None,
}
}
pub fn span(&self, constants: &super::Arena<super::Constant>) -> u32 {
match *self {
Self::Scalar { kind: _, width } => width as u32,
Self::Vector {
size,
kind: _,
width,
} => {
//let count = if size >= super::VectorSize::Tri { 4 } else { 2 };
let count = size as u8; //TEMP
(count * width) as u32
}
Self::Matrix {
columns,
rows,
width,
} => {
//let count = if rows >= super::VectorSize::Tri { 4 } else { 2 };
let count = rows as u8; //TEMP
(columns as u8 * count * width) as u32
}
Self::Pointer { .. } | Self::ValuePointer { .. } => POINTER_SPAN,
Self::Array {
base: _,
size,
stride,
} => {
let count = match size {
super::ArraySize::Constant(handle) => {
constants[handle].to_array_length().unwrap()
}
// A dynamically-sized array has to have at least one element
super::ArraySize::Dynamic => 1,
};
count * stride
}
Self::Struct {
block: _,
ref members,
} => members.iter().map(|m| m.span).sum(),
Self::Image { .. } | Self::Sampler { .. } => 0,
}
}
}
impl super::MathFunction {

View File

@ -272,12 +272,9 @@ impl super::Validator {
let (allowed_storage_access, required_type_flags, is_resource) = match var.class {
crate::StorageClass::Function => return Err(GlobalVariableError::InvalidUsage),
crate::StorageClass::Storage => {
if let Err((ty_handle, ref disalignment)) = type_info.storage_layout {
if let Err((ty_handle, disalignment)) = type_info.storage_layout {
if self.flags.contains(ValidationFlags::STRUCT_LAYOUTS) {
return Err(GlobalVariableError::Alignment(
ty_handle,
disalignment.clone(),
));
return Err(GlobalVariableError::Alignment(ty_handle, disalignment));
}
}
(
@ -287,12 +284,9 @@ impl super::Validator {
)
}
crate::StorageClass::Uniform => {
if let Err((ty_handle, ref disalignment)) = type_info.uniform_layout {
if let Err((ty_handle, disalignment)) = type_info.uniform_layout {
if self.flags.contains(ValidationFlags::STRUCT_LAYOUTS) {
return Err(GlobalVariableError::Alignment(
ty_handle,
disalignment.clone(),
));
return Err(GlobalVariableError::Alignment(ty_handle, disalignment));
}
}
(

View File

@ -6,7 +6,6 @@ mod r#type;
use crate::{
arena::{Arena, Handle},
proc::Layouter,
FastHashSet,
};
use bit_set::BitSet;
@ -54,7 +53,6 @@ bitflags::bitflags! {
pub struct ModuleInfo {
functions: Vec<FunctionInfo>,
entry_points: Vec<FunctionInfo>,
pub layouter: Layouter,
}
impl ops::Index<Handle<crate::Function>> for ModuleInfo {
@ -221,8 +219,6 @@ impl Validator {
pub fn validate(&mut self, module: &crate::Module) -> Result<ModuleInfo, ValidationError> {
self.reset_types(module.types.len());
let layouter = Layouter::new(&module.types, &module.constants);
for (handle, constant) in module.constants.iter() {
self.validate_constant(handle, &module.constants, &module.types)
.map_err(|error| ValidationError::Constant {
@ -235,7 +231,7 @@ impl Validator {
// doing after the globals, so that `type_flags` is ready
for (handle, ty) in module.types.iter() {
let ty_info = self
.validate_type(ty, handle, &module.constants, &layouter)
.validate_type(handle, &module.types, &module.constants)
.map_err(|error| ValidationError::Type {
handle,
name: ty.name.clone().unwrap_or_default(),
@ -256,7 +252,6 @@ impl Validator {
let mut mod_info = ModuleInfo {
functions: Vec::with_capacity(module.functions.len()),
entry_points: Vec::with_capacity(module.entry_points.len()),
layouter,
};
for (handle, fun) in module.functions.iter() {

View File

@ -1,7 +1,6 @@
use crate::{
arena::{Arena, Handle},
proc::Layouter,
};
use crate::arena::{Arena, Handle};
pub type Alignment = u32;
bitflags::bitflags! {
#[repr(transparent)]
@ -19,7 +18,7 @@ bitflags::bitflags! {
}
}
#[derive(Clone, Debug, thiserror::Error)]
#[derive(Clone, Copy, Debug, thiserror::Error)]
pub enum Disalignment {
#[error("The array stride {stride} is not a multiple of the required alignment {alignment}")]
ArrayStride { stride: u32, alignment: u32 },
@ -49,10 +48,6 @@ pub enum TypeError {
InvalidArrayBaseType(Handle<crate::Type>),
#[error("The constant {0:?} can not be used for an array size")]
InvalidArraySizeConstant(Handle<crate::Constant>),
#[error(
"Array stride {stride} is not a multiple of the base element alignment {base_alignment}"
)]
UnalignedArrayStride { stride: u32, base_alignment: u32 },
#[error("Array stride {stride} is smaller than the base element size {base_size}")]
InsufficientArrayStride { stride: u32, base_size: u32 },
#[error("Field '{0}' can't be dynamically-sized, has type {1:?}")]
@ -68,7 +63,7 @@ pub enum TypeError {
}
// Only makes sense if `flags.contains(HOST_SHARED)`
type LayoutCompatibility = Result<(), (Handle<crate::Type>, Disalignment)>;
type LayoutCompatibility = Result<Alignment, (Handle<crate::Type>, Disalignment)>;
// For the uniform buffer alignment, array strides and struct sizes must be multiples of 16.
const UNIFORM_LAYOUT_ALIGNMENT_MASK: u32 = 0xF;
@ -81,19 +76,19 @@ pub(super) struct TypeInfo {
}
impl TypeInfo {
fn new() -> Self {
fn dummy() -> Self {
TypeInfo {
flags: TypeFlags::empty(),
uniform_layout: Ok(()),
storage_layout: Ok(()),
uniform_layout: Ok(0),
storage_layout: Ok(0),
}
}
fn from_flags(flags: TypeFlags) -> Self {
fn new(flags: TypeFlags, alignment: crate::Span) -> Self {
TypeInfo {
flags,
uniform_layout: Ok(()),
storage_layout: Ok(()),
uniform_layout: Ok(alignment),
storage_layout: Ok(alignment),
}
}
}
@ -108,45 +103,64 @@ impl super::Validator {
pub(super) fn reset_types(&mut self, size: usize) {
self.types.clear();
self.types.resize(size, TypeInfo::new());
self.types.resize(size, TypeInfo::dummy());
}
pub(super) fn validate_type(
&self,
ty: &crate::Type,
handle: Handle<crate::Type>,
types: &Arena<crate::Type>,
constants: &Arena<crate::Constant>,
layouter: &Layouter,
) -> Result<TypeInfo, TypeError> {
use crate::TypeInner as Ti;
Ok(match ty.inner {
Ti::Scalar { kind, width } | Ti::Vector { kind, width, .. } => {
Ok(match types[handle].inner {
Ti::Scalar { kind, width } => {
if !Self::check_width(kind, width) {
return Err(TypeError::InvalidWidth(kind, width));
}
TypeInfo::from_flags(
TypeInfo::new(
TypeFlags::DATA
| TypeFlags::SIZED
| TypeFlags::INTERFACE
| TypeFlags::HOST_SHARED,
width as u32,
)
}
Ti::Matrix { width, .. } => {
Ti::Vector { size, kind, width } => {
if !Self::check_width(kind, width) {
return Err(TypeError::InvalidWidth(kind, width));
}
let count = if size >= crate::VectorSize::Tri { 4 } else { 2 };
TypeInfo::new(
TypeFlags::DATA
| TypeFlags::SIZED
| TypeFlags::INTERFACE
| TypeFlags::HOST_SHARED,
count * (width as u32),
)
}
Ti::Matrix {
columns: _,
rows,
width,
} => {
if !Self::check_width(crate::ScalarKind::Float, width) {
return Err(TypeError::InvalidWidth(crate::ScalarKind::Float, width));
}
TypeInfo::from_flags(
let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 };
TypeInfo::new(
TypeFlags::DATA
| TypeFlags::SIZED
| TypeFlags::INTERFACE
| TypeFlags::HOST_SHARED,
count * (width as u32),
)
}
Ti::Pointer { base, class: _ } => {
if base >= handle {
return Err(TypeError::UnresolvedBase(base));
}
TypeInfo::from_flags(TypeFlags::DATA | TypeFlags::SIZED)
TypeInfo::new(TypeFlags::DATA | TypeFlags::SIZED, 0)
}
Ti::ValuePointer {
size: _,
@ -157,7 +171,7 @@ impl super::Validator {
if !Self::check_width(kind, width) {
return Err(TypeError::InvalidWidth(kind, width));
}
TypeInfo::from_flags(TypeFlags::SIZED)
TypeInfo::new(TypeFlags::SIZED, 0)
}
Ti::Array { base, size, stride } => {
if base >= handle {
@ -171,23 +185,35 @@ impl super::Validator {
return Err(TypeError::NestedBlock);
}
let base_layout = &layouter[base];
if let Some(stride) = stride {
if stride.get() % base_layout.alignment.get() != 0 {
return Err(TypeError::UnalignedArrayStride {
stride: stride.get(),
base_alignment: base_layout.alignment.get(),
});
}
if stride.get() < base_layout.size {
return Err(TypeError::InsufficientArrayStride {
stride: stride.get(),
base_size: base_layout.size,
});
}
let base_size = types[base].inner.span(constants);
if stride < base_size {
return Err(TypeError::InsufficientArrayStride { stride, base_size });
}
let (sized_flag, uniform_layout) = match size {
let uniform_layout = match base_info.uniform_layout {
Ok(base_alignment) => {
// combine the alignment requirements
let alignment = ((base_alignment - 1) | UNIFORM_LAYOUT_ALIGNMENT_MASK) + 1;
if stride % alignment != 0 {
Err((handle, Disalignment::ArrayStride { stride, alignment }))
} else {
Ok(alignment)
}
}
Err(e) => Err(e),
};
let storage_layout = match base_info.storage_layout {
Ok(alignment) => {
if stride % alignment != 0 {
Err((handle, Disalignment::ArrayStride { stride, alignment }))
} else {
Ok(alignment)
}
}
Err(e) => Err(e),
};
let sized_flag = match size {
crate::ArraySize::Constant(const_handle) => {
match constants.try_get(const_handle) {
Some(&crate::Constant {
@ -216,33 +242,17 @@ impl super::Validator {
}
}
let effective_stride = match stride {
Some(stride) => stride.get(),
None => base_layout.size,
};
let uniform_layout =
if effective_stride & UNIFORM_LAYOUT_ALIGNMENT_MASK == 0 {
base_info.uniform_layout.clone()
} else {
Err((
handle,
Disalignment::ArrayStride {
stride: effective_stride,
alignment: UNIFORM_LAYOUT_ALIGNMENT_MASK + 1,
},
))
};
(TypeFlags::SIZED, uniform_layout)
TypeFlags::SIZED
}
//Note: this will be detected at the struct level
crate::ArraySize::Dynamic => (TypeFlags::empty(), Ok(())),
crate::ArraySize::Dynamic => TypeFlags::empty(),
};
let base_mask = TypeFlags::HOST_SHARED | TypeFlags::INTERFACE;
TypeInfo {
flags: TypeFlags::DATA | (base_info.flags & base_mask) | sized_flag,
uniform_layout,
storage_layout: base_info.storage_layout.clone(),
storage_layout,
}
}
Ti::Struct { block, ref members } => {
@ -250,8 +260,8 @@ impl super::Validator {
| TypeFlags::SIZED
| TypeFlags::HOST_SHARED
| TypeFlags::INTERFACE;
let mut uniform_layout = Ok(());
let mut storage_layout = Ok(());
let mut uniform_layout = Ok(1);
let mut storage_layout = Ok(1);
let mut offset = 0;
for (i, member) in members.iter().enumerate() {
if member.ty >= handle {
@ -269,28 +279,54 @@ impl super::Validator {
}
flags &= base_info.flags;
let base_layout = &layouter[member.ty];
let (range, _alignment) = layouter.member_placement(offset, member);
if range.end - range.start < base_layout.size {
let base_size = types[member.ty].inner.span(constants);
if member.span < base_size {
return Err(TypeError::InsufficientMemberSize {
index: i as u32,
size: range.end - range.start,
base_size: base_layout.size,
size: member.span,
base_size,
});
}
if range.start % base_layout.alignment.get() != 0 {
let result = Err((
handle,
Disalignment::Member {
index: i as u32,
offset: range.start,
alignment: base_layout.alignment.get(),
},
));
uniform_layout = uniform_layout.or_else(|_| result.clone());
storage_layout = storage_layout.or(result);
}
offset = range.end;
uniform_layout = match (uniform_layout, base_info.uniform_layout) {
(Ok(cur_alignment), Ok(alignment)) => {
if offset % alignment != 0 {
Err((
handle,
Disalignment::Member {
index: i as u32,
offset,
alignment,
},
))
} else {
let combined_alignment =
((cur_alignment - 1) | (alignment - 1)) + 1;
Ok(combined_alignment)
}
}
(Err(e), _) | (_, Err(e)) => Err(e),
};
storage_layout = match (storage_layout, base_info.storage_layout) {
(Ok(cur_alignment), Ok(alignment)) => {
if offset % alignment != 0 {
Err((
handle,
Disalignment::Member {
index: i as u32,
offset,
alignment,
},
))
} else {
let combined_alignment =
((cur_alignment - 1) | (alignment - 1)) + 1;
Ok(combined_alignment)
}
}
(Err(e), _) | (_, Err(e)) => Err(e),
};
offset += member.span;
// only the last field can be unsized
if !base_info.flags.contains(TypeFlags::SIZED) {
@ -303,9 +339,6 @@ impl super::Validator {
Err((handle, Disalignment::UnsizedMember { index: i as u32 }));
}
}
uniform_layout = uniform_layout.or_else(|_| base_info.uniform_layout.clone());
storage_layout = storage_layout.or_else(|_| base_info.storage_layout.clone());
}
if block {
flags |= TypeFlags::BLOCK;
@ -331,7 +364,7 @@ impl super::Validator {
storage_layout,
}
}
Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::from_flags(TypeFlags::empty()),
Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::new(TypeFlags::empty(), 0),
})
}
}

View File

@ -498,24 +498,4 @@ expression: output
],
),
],
layouter: (
layouts: [
(
size: 4,
alignment: 4,
),
(
size: 4,
alignment: 4,
),
(
size: 4,
alignment: 4,
),
(
size: 12,
alignment: 16,
),
],
),
)

View File

@ -16,7 +16,7 @@ expression: output
inner: Array(
base: 1,
size: Dynamic,
stride: Some(4),
stride: 4,
),
),
(
@ -28,8 +28,7 @@ expression: output
name: Some("data"),
ty: 2,
binding: None,
size: None,
align: None,
span: 4,
),
],
),

View File

@ -2873,236 +2873,4 @@ expression: output
],
),
],
layouter: (
layouts: [
(
size: 4,
alignment: 4,
),
(
size: 12,
alignment: 16,
),
(
size: 4,
alignment: 4,
),
(
size: 16,
alignment: 16,
),
(
size: 1,
alignment: 1,
),
(
size: 8,
alignment: 8,
),
(
size: 0,
alignment: 1,
),
(
size: 0,
alignment: 1,
),
(
size: 8,
alignment: 8,
),
(
size: 4,
alignment: 4,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 16,
alignment: 16,
),
(
size: 16,
alignment: 16,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 64,
alignment: 16,
),
(
size: 96,
alignment: 16,
),
(
size: 96,
alignment: 96,
),
(
size: 128,
alignment: 96,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 4,
alignment: 1,
),
(
size: 0,
alignment: 1,
),
(
size: 0,
alignment: 1,
),
],
),
)

View File

@ -112,8 +112,7 @@ expression: output
name: Some("num_lights"),
ty: 13,
binding: None,
size: None,
align: None,
span: 16,
),
],
),
@ -156,22 +155,19 @@ expression: output
name: Some("proj"),
ty: 18,
binding: None,
size: None,
align: None,
span: 64,
),
(
name: Some("pos"),
ty: 4,
binding: None,
size: None,
align: None,
span: 16,
),
(
name: Some("color"),
ty: 4,
binding: None,
size: None,
align: None,
span: 16,
),
],
),
@ -181,7 +177,7 @@ expression: output
inner: Array(
base: 19,
size: Dynamic,
stride: Some(96),
stride: 96,
),
),
(
@ -193,8 +189,7 @@ expression: output
name: Some("data"),
ty: 20,
binding: None,
size: None,
align: None,
span: 96,
),
],
),