mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-23 15:23:33 +00:00
New struct layout IR
This commit is contained in:
parent
5a0e3ad5ff
commit
7326ba6ddb
@ -1389,6 +1389,14 @@ impl<W: Write> Writer<W> {
|
|||||||
first_time: false,
|
first_time: false,
|
||||||
};
|
};
|
||||||
writeln!(self.out, "{}{} {};", INDENT, base_name, member_name)?;
|
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, "}};")?;
|
writeln!(self.out, "}};")?;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
arena::{Arena, Handle},
|
arena::{Arena, Handle},
|
||||||
proc::{Layouter, TypeResolution},
|
proc::TypeResolution,
|
||||||
valid::{FunctionInfo, ModuleInfo},
|
valid::{FunctionInfo, ModuleInfo},
|
||||||
};
|
};
|
||||||
use spirv::Word;
|
use spirv::Word;
|
||||||
@ -760,10 +760,10 @@ impl Writer {
|
|||||||
fn write_type_declaration_arena(
|
fn write_type_declaration_arena(
|
||||||
&mut self,
|
&mut self,
|
||||||
arena: &Arena<crate::Type>,
|
arena: &Arena<crate::Type>,
|
||||||
layouter: &Layouter,
|
|
||||||
handle: Handle<crate::Type>,
|
handle: Handle<crate::Type>,
|
||||||
) -> Result<Word, Error> {
|
) -> Result<Word, Error> {
|
||||||
let ty = &arena[handle];
|
let ty = &arena[handle];
|
||||||
|
let decorate_layout = true; //TODO?
|
||||||
|
|
||||||
let id = if let Some(local) = self.physical_layout.make_local(&ty.inner) {
|
let id = if let Some(local) = self.physical_layout.make_local(&ty.inner) {
|
||||||
match self.lookup_type.entry(LookupType::Local(local)) {
|
match self.lookup_type.entry(LookupType::Local(local)) {
|
||||||
@ -845,11 +845,11 @@ impl Writer {
|
|||||||
}
|
}
|
||||||
crate::TypeInner::Sampler { comparison: _ } => Instruction::type_sampler(id),
|
crate::TypeInner::Sampler { comparison: _ } => Instruction::type_sampler(id),
|
||||||
crate::TypeInner::Array { base, size, stride } => {
|
crate::TypeInner::Array { base, size, stride } => {
|
||||||
if let Some(array_stride) = stride {
|
if decorate_layout {
|
||||||
self.annotations.push(Instruction::decorate(
|
self.annotations.push(Instruction::decorate(
|
||||||
id,
|
id,
|
||||||
Decoration::ArrayStride,
|
Decoration::ArrayStride,
|
||||||
&[array_stride.get()],
|
&[stride],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,14 +871,15 @@ impl Writer {
|
|||||||
let mut current_offset = 0;
|
let mut current_offset = 0;
|
||||||
let mut member_ids = Vec::with_capacity(members.len());
|
let mut member_ids = Vec::with_capacity(members.len());
|
||||||
for (index, member) in members.iter().enumerate() {
|
for (index, member) in members.iter().enumerate() {
|
||||||
let (placement, _) = layouter.member_placement(current_offset, member);
|
if decorate_layout {
|
||||||
self.annotations.push(Instruction::member_decorate(
|
self.annotations.push(Instruction::member_decorate(
|
||||||
id,
|
id,
|
||||||
index as u32,
|
index as u32,
|
||||||
Decoration::Offset,
|
Decoration::Offset,
|
||||||
&[placement.start],
|
&[current_offset],
|
||||||
));
|
));
|
||||||
current_offset = placement.end;
|
current_offset += member.span;
|
||||||
|
}
|
||||||
|
|
||||||
if self.flags.contains(WriterFlags::DEBUG) {
|
if self.flags.contains(WriterFlags::DEBUG) {
|
||||||
if let Some(ref name) = member.name {
|
if let Some(ref name) = member.name {
|
||||||
@ -1073,11 +1074,8 @@ impl Writer {
|
|||||||
|
|
||||||
match *binding {
|
match *binding {
|
||||||
crate::Binding::Location(location, interpolation) => {
|
crate::Binding::Location(location, interpolation) => {
|
||||||
self.annotations.push(Instruction::decorate(
|
self.annotations
|
||||||
id,
|
.push(Instruction::decorate(id, Decoration::Location, &[location]));
|
||||||
Decoration::Location,
|
|
||||||
&[location],
|
|
||||||
));
|
|
||||||
let interp_decoration = match interpolation {
|
let interp_decoration = match interpolation {
|
||||||
Some(crate::Interpolation::Linear) => Some(Decoration::NoPerspective),
|
Some(crate::Interpolation::Linear) => Some(Decoration::NoPerspective),
|
||||||
Some(crate::Interpolation::Flat) => Some(Decoration::Flat),
|
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
|
// then all types, some of them may rely on constants and struct type set
|
||||||
for (handle, _) in ir_module.types.iter() {
|
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
|
// the all the composite constants, they rely on types
|
||||||
|
@ -729,8 +729,7 @@ pomelo! {
|
|||||||
binding: None, //TODO
|
binding: None, //TODO
|
||||||
//TODO: if the struct is a uniform struct, these values have to reflect
|
//TODO: if the struct is a uniform struct, these values have to reflect
|
||||||
// std140 layout. Otherwise, std430.
|
// std140 layout. Otherwise, std430.
|
||||||
size: None,
|
span: extra.module.types[ty].inner.span(&extra.module.constants),
|
||||||
align: None,
|
|
||||||
}).collect()
|
}).collect()
|
||||||
} else {
|
} else {
|
||||||
return Err(ErrorKind::SemanticError("Struct member can't be void".into()))
|
return Err(ErrorKind::SemanticError("Struct member can't be void".into()))
|
||||||
|
@ -248,13 +248,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
|||||||
// unrecognized binding, skip
|
// unrecognized binding, skip
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
members.push(crate::StructMember {
|
members.push(sm.clone());
|
||||||
name: sm.name.clone(),
|
|
||||||
ty: sm.ty,
|
|
||||||
binding: sm.binding.clone(),
|
|
||||||
size: None,
|
|
||||||
align: None,
|
|
||||||
});
|
|
||||||
components.push(function.expressions.append(
|
components.push(function.expressions.append(
|
||||||
crate::Expression::AccessIndex {
|
crate::Expression::AccessIndex {
|
||||||
base: expr_handle,
|
base: expr_handle,
|
||||||
@ -268,8 +262,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
|||||||
name: None,
|
name: None,
|
||||||
ty: result.ty,
|
ty: result.ty,
|
||||||
binding: result.binding.clone(),
|
binding: result.binding.clone(),
|
||||||
size: None,
|
span: module.types[result.ty].inner.span(&module.constants),
|
||||||
align: None,
|
|
||||||
});
|
});
|
||||||
// populate just the globals first, then do `Load` in a
|
// populate just the globals first, then do `Load` in a
|
||||||
// separate step, so that we can get a range.
|
// separate step, so that we can get a range.
|
||||||
|
@ -2419,17 +2419,21 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
|||||||
let length_id = self.next()?;
|
let length_id = self.next()?;
|
||||||
let length_const = self.lookup_constant.lookup(length_id)?;
|
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 {
|
let inner = crate::TypeInner::Array {
|
||||||
base: self.lookup_type.lookup(type_id)?.handle,
|
base,
|
||||||
size: crate::ArraySize::Constant(length_const.handle),
|
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(
|
self.lookup_type.insert(
|
||||||
id,
|
id,
|
||||||
LookupType {
|
LookupType {
|
||||||
handle: module.types.append(crate::Type {
|
handle: module.types.append(crate::Type {
|
||||||
name: decor.and_then(|dec| dec.name),
|
name: decor.name,
|
||||||
inner,
|
inner,
|
||||||
}),
|
}),
|
||||||
base_id: Some(type_id),
|
base_id: Some(type_id),
|
||||||
@ -2448,17 +2452,21 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
|||||||
let id = self.next()?;
|
let id = self.next()?;
|
||||||
let type_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 {
|
let inner = crate::TypeInner::Array {
|
||||||
base: self.lookup_type.lookup(type_id)?.handle,
|
base: self.lookup_type.lookup(type_id)?.handle,
|
||||||
size: crate::ArraySize::Dynamic,
|
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(
|
self.lookup_type.insert(
|
||||||
id,
|
id,
|
||||||
LookupType {
|
LookupType {
|
||||||
handle: module.types.append(crate::Type {
|
handle: module.types.append(crate::Type {
|
||||||
name: decor.and_then(|dec| dec.name),
|
name: decor.name,
|
||||||
inner,
|
inner,
|
||||||
}),
|
}),
|
||||||
base_id: Some(type_id),
|
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 parent_decor = self.future_decor.remove(&id);
|
||||||
let block_decor = parent_decor.as_ref().and_then(|decor| decor.block.clone());
|
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 member_type_ids = Vec::with_capacity(members.capacity());
|
||||||
|
let mut last_offset = 0;
|
||||||
for i in 0..u32::from(inst.wc) - 2 {
|
for i in 0..u32::from(inst.wc) - 2 {
|
||||||
let type_id = self.next()?;
|
let type_id = self.next()?;
|
||||||
member_type_ids.push(type_id);
|
member_type_ids.push(type_id);
|
||||||
@ -2489,12 +2498,24 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
|||||||
.remove(&(id, i))
|
.remove(&(id, i))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let binding = decor.io_binding().ok();
|
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 {
|
members.push(crate::StructMember {
|
||||||
name: decor.name,
|
name: decor.name,
|
||||||
ty,
|
ty,
|
||||||
binding,
|
binding,
|
||||||
size: None, //TODO
|
span,
|
||||||
align: None,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::arena::{Arena, Handle};
|
use crate::arena::{Arena, Handle};
|
||||||
use std::{num::NonZeroU32, ops};
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
pub type Alignment = NonZeroU32;
|
pub type Alignment = NonZeroU32;
|
||||||
|
|
||||||
@ -22,14 +22,17 @@ pub struct Layouter {
|
|||||||
layouts: Vec<TypeLayout>,
|
layouts: Vec<TypeLayout>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Placement {
|
||||||
|
pub pad: crate::Span,
|
||||||
|
pub span: crate::Span,
|
||||||
|
}
|
||||||
|
|
||||||
impl Layouter {
|
impl Layouter {
|
||||||
pub fn new(types: &Arena<crate::Type>, constants: &Arena<crate::Constant>) -> Self {
|
pub fn clear(&mut self) {
|
||||||
let mut this = Layouter::default();
|
self.layouts.clear();
|
||||||
this.initialize(types, constants);
|
|
||||||
this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round_up(alignment: NonZeroU32, offset: u32) -> u32 {
|
pub fn round_up(alignment: Alignment, offset: u32) -> u32 {
|
||||||
match offset & (alignment.get() - 1) {
|
match offset & (alignment.get() - 1) {
|
||||||
0 => offset,
|
0 => offset,
|
||||||
other => offset + alignment.get() - other,
|
other => offset + alignment.get() - other,
|
||||||
@ -39,78 +42,66 @@ impl Layouter {
|
|||||||
pub fn member_placement(
|
pub fn member_placement(
|
||||||
&self,
|
&self,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
member: &crate::StructMember,
|
ty: Handle<crate::Type>,
|
||||||
) -> (ops::Range<u32>, NonZeroU32) {
|
align: Option<Alignment>,
|
||||||
let layout = self.layouts[member.ty.index()];
|
size: Option<NonZeroU32>,
|
||||||
let alignment = member.align.unwrap_or(layout.alignment);
|
) -> Placement {
|
||||||
|
let layout = self.layouts[ty.index()];
|
||||||
|
let alignment = align.unwrap_or(layout.alignment);
|
||||||
let start = Self::round_up(alignment, offset);
|
let start = Self::round_up(alignment, offset);
|
||||||
let end = start
|
let span = match size {
|
||||||
+ match member.size {
|
Some(size) => size.get(),
|
||||||
Some(size) => size.get(),
|
None => layout.size,
|
||||||
None => layout.size,
|
};
|
||||||
};
|
Placement {
|
||||||
(start..end, alignment)
|
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;
|
use crate::TypeInner as Ti;
|
||||||
|
for (_, ty) in types.iter().skip(self.layouts.len()) {
|
||||||
self.layouts.clear();
|
let size = ty.inner.span(constants);
|
||||||
self.layouts.reserve(types.len());
|
let layout = match ty.inner {
|
||||||
|
Ti::Scalar { width, .. } => TypeLayout {
|
||||||
for (_, ty) in types.iter() {
|
size,
|
||||||
self.layouts.push(match ty.inner {
|
|
||||||
Ti::Scalar { kind: _, width } => TypeLayout {
|
|
||||||
size: width as u32,
|
|
||||||
alignment: Alignment::new(width as u32).unwrap(),
|
alignment: Alignment::new(width as u32).unwrap(),
|
||||||
},
|
},
|
||||||
Ti::Vector {
|
Ti::Vector {
|
||||||
size,
|
size: vec_size,
|
||||||
kind: _,
|
|
||||||
width,
|
width,
|
||||||
|
..
|
||||||
} => TypeLayout {
|
} => TypeLayout {
|
||||||
size: (size as u8 * width) as u32,
|
size,
|
||||||
alignment: {
|
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()
|
Alignment::new((count * width) as u32).unwrap()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ti::Matrix {
|
Ti::Matrix {
|
||||||
columns,
|
columns: _,
|
||||||
rows,
|
rows,
|
||||||
width,
|
width,
|
||||||
} => TypeLayout {
|
} => TypeLayout {
|
||||||
size: (columns as u8 * rows as u8 * width) as u32,
|
size,
|
||||||
alignment: {
|
alignment: {
|
||||||
let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 };
|
let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 };
|
||||||
Alignment::new((count * width) as u32).unwrap()
|
Alignment::new((count * width) as u32).unwrap()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ti::Pointer { .. } | Ti::ValuePointer { .. } => TypeLayout {
|
Ti::Pointer { .. } | Ti::ValuePointer { .. } => TypeLayout {
|
||||||
size: 4,
|
size,
|
||||||
alignment: Alignment::new(1).unwrap(),
|
alignment: Alignment::new(1).unwrap(),
|
||||||
},
|
},
|
||||||
Ti::Array { base, size, stride } => {
|
Ti::Array { stride, .. } => TypeLayout {
|
||||||
let count = match size {
|
size,
|
||||||
crate::ArraySize::Constant(handle) => {
|
alignment: Alignment::new(stride).unwrap(),
|
||||||
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::Struct {
|
Ti::Struct {
|
||||||
block: _,
|
block: _,
|
||||||
ref members,
|
ref members,
|
||||||
@ -118,9 +109,9 @@ impl Layouter {
|
|||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut biggest_alignment = Alignment::new(1).unwrap();
|
let mut biggest_alignment = Alignment::new(1).unwrap();
|
||||||
for member in members {
|
for member in members {
|
||||||
let (placement, alignment) = self.member_placement(total, member);
|
let layout = self.layouts[member.ty.index()];
|
||||||
biggest_alignment = biggest_alignment.max(alignment);
|
biggest_alignment = biggest_alignment.max(layout.alignment);
|
||||||
total = placement.end;
|
total += member.span;
|
||||||
}
|
}
|
||||||
TypeLayout {
|
TypeLayout {
|
||||||
size: Self::round_up(biggest_alignment, total),
|
size: Self::round_up(biggest_alignment, total),
|
||||||
@ -128,17 +119,12 @@ impl Layouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ti::Image { .. } | Ti::Sampler { .. } => TypeLayout {
|
Ti::Image { .. } | Ti::Sampler { .. } => TypeLayout {
|
||||||
size: 0,
|
size,
|
||||||
alignment: Alignment::new(1).unwrap(),
|
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()]
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@
|
|||||||
//! [wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html
|
//! [wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html
|
||||||
|
|
||||||
mod conv;
|
mod conv;
|
||||||
|
mod layout;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -560,6 +561,7 @@ impl<'a> std::error::Error for ParseError<'a> {
|
|||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
scopes: Vec<Scope>,
|
scopes: Vec<Scope>,
|
||||||
lookup_type: FastHashMap<String, Handle<crate::Type>>,
|
lookup_type: FastHashMap<String, Handle<crate::Type>>,
|
||||||
|
layouter: layout::Layouter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
@ -567,6 +569,7 @@ impl Parser {
|
|||||||
Parser {
|
Parser {
|
||||||
scopes: Vec::new(),
|
scopes: Vec::new(),
|
||||||
lookup_type: FastHashMap::default(),
|
lookup_type: FastHashMap::default(),
|
||||||
|
layouter: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1507,7 +1510,9 @@ impl Parser {
|
|||||||
type_arena: &mut Arena<crate::Type>,
|
type_arena: &mut Arena<crate::Type>,
|
||||||
const_arena: &mut Arena<crate::Constant>,
|
const_arena: &mut Arena<crate::Constant>,
|
||||||
) -> Result<Vec<crate::StructMember>, Error<'a>> {
|
) -> Result<Vec<crate::StructMember>, Error<'a>> {
|
||||||
|
let mut offset = 0;
|
||||||
let mut members = Vec::new();
|
let mut members = Vec::new();
|
||||||
|
|
||||||
lexer.expect(Token::Paren('{'))?;
|
lexer.expect(Token::Paren('{'))?;
|
||||||
loop {
|
loop {
|
||||||
let (mut size, mut align) = (None, None);
|
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)?;
|
let (ty, _access) = self.parse_type_decl(lexer, None, type_arena, const_arena)?;
|
||||||
lexer.expect(Token::Separator(';'))?;
|
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 {
|
members.push(crate::StructMember {
|
||||||
name: Some(name.to_owned()),
|
name: Some(name.to_owned()),
|
||||||
ty,
|
ty,
|
||||||
binding: bind_parser.finish()?,
|
binding: bind_parser.finish()?,
|
||||||
size,
|
span: placement.span,
|
||||||
align,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1708,12 +1719,12 @@ impl Parser {
|
|||||||
crate::ArraySize::Dynamic
|
crate::ArraySize::Dynamic
|
||||||
};
|
};
|
||||||
lexer.expect_generic_paren('>')?;
|
lexer.expect_generic_paren('>')?;
|
||||||
|
let stride = match attribute.stride {
|
||||||
|
Some(stride) => stride.get(),
|
||||||
|
None => type_arena[base].inner.span(const_arena),
|
||||||
|
};
|
||||||
|
|
||||||
crate::TypeInner::Array {
|
crate::TypeInner::Array { base, size, stride }
|
||||||
base,
|
|
||||||
size,
|
|
||||||
stride: attribute.stride,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"sampler" => crate::TypeInner::Sampler { comparison: false },
|
"sampler" => crate::TypeInner::Sampler { comparison: false },
|
||||||
"sampler_comparison" => crate::TypeInner::Sampler { comparison: true },
|
"sampler_comparison" => crate::TypeInner::Sampler { comparison: true },
|
||||||
@ -1916,14 +1927,8 @@ impl Parser {
|
|||||||
|
|
||||||
let storage_access = attribute.access;
|
let storage_access = attribute.access;
|
||||||
let name = lexer.next_ident()?;
|
let name = lexer.next_ident()?;
|
||||||
let handle = self.parse_type_decl_name(
|
let handle =
|
||||||
lexer,
|
self.parse_type_decl_name(lexer, name, debug_name, attribute, type_arena, const_arena)?;
|
||||||
name,
|
|
||||||
debug_name,
|
|
||||||
attribute,
|
|
||||||
type_arena,
|
|
||||||
const_arena,
|
|
||||||
)?;
|
|
||||||
self.scopes.pop();
|
self.scopes.pop();
|
||||||
Ok((handle, storage_access))
|
Ok((handle, storage_access))
|
||||||
}
|
}
|
||||||
@ -2671,6 +2676,7 @@ impl Parser {
|
|||||||
pub fn parse<'a>(&mut self, source: &'a str) -> Result<crate::Module, ParseError<'a>> {
|
pub fn parse<'a>(&mut self, source: &'a str) -> Result<crate::Module, ParseError<'a>> {
|
||||||
self.scopes.clear();
|
self.scopes.clear();
|
||||||
self.lookup_type.clear();
|
self.lookup_type.clear();
|
||||||
|
self.layouter.clear();
|
||||||
|
|
||||||
let mut module = crate::Module::default();
|
let mut module = crate::Module::default();
|
||||||
let mut lexer = Lexer::new(source);
|
let mut lexer = Lexer::new(source);
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -50,7 +50,6 @@ pub use crate::arena::{Arena, Handle, Range};
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
hash::BuildHasherDefault,
|
hash::BuildHasherDefault,
|
||||||
num::NonZeroU32,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "deserialize")]
|
#[cfg(feature = "deserialize")]
|
||||||
@ -166,8 +165,10 @@ pub enum BuiltIn {
|
|||||||
WorkGroupSize,
|
WorkGroupSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of bytes.
|
/// Number of bytes per scalar.
|
||||||
pub type Bytes = u8;
|
pub type Bytes = u8;
|
||||||
|
/// Number of bytes per complex type.
|
||||||
|
pub type Span = u32;
|
||||||
|
|
||||||
/// Number of components in a vector.
|
/// Number of components in a vector.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -244,10 +245,8 @@ pub struct StructMember {
|
|||||||
pub ty: Handle<Type>,
|
pub ty: Handle<Type>,
|
||||||
/// For I/O structs, defines the binding.
|
/// For I/O structs, defines the binding.
|
||||||
pub binding: Option<Binding>,
|
pub binding: Option<Binding>,
|
||||||
/// Overrides the size computed off the type.
|
/// Size occupied by the member.
|
||||||
pub size: Option<NonZeroU32>,
|
pub span: Span,
|
||||||
/// Overrides the alignment computed off the type.
|
|
||||||
pub align: Option<NonZeroU32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of dimensions an image has.
|
/// The number of dimensions an image has.
|
||||||
@ -392,7 +391,7 @@ pub enum TypeInner {
|
|||||||
Array {
|
Array {
|
||||||
base: Handle<Type>,
|
base: Handle<Type>,
|
||||||
size: ArraySize,
|
size: ArraySize,
|
||||||
stride: Option<NonZeroU32>,
|
stride: Span,
|
||||||
},
|
},
|
||||||
/// User-defined structure.
|
/// User-defined structure.
|
||||||
Struct {
|
Struct {
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
//! Module processing functionality.
|
//! Module processing functionality.
|
||||||
|
|
||||||
mod layouter;
|
|
||||||
mod namer;
|
mod namer;
|
||||||
mod terminator;
|
mod terminator;
|
||||||
mod typifier;
|
mod typifier;
|
||||||
|
|
||||||
pub use layouter::{Alignment, Layouter, TypeLayout};
|
|
||||||
pub use namer::{EntryPointIndex, NameKey, Namer};
|
pub use namer::{EntryPointIndex, NameKey, Namer};
|
||||||
pub use terminator::ensure_block_returns;
|
pub use terminator::ensure_block_returns;
|
||||||
pub use typifier::{ResolveContext, ResolveError, TypeResolution};
|
pub use typifier::{ResolveContext, ResolveError, TypeResolution};
|
||||||
@ -61,6 +59,8 @@ impl super::ScalarValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const POINTER_SPAN: u32 = 4;
|
||||||
|
|
||||||
impl super::TypeInner {
|
impl super::TypeInner {
|
||||||
pub fn scalar_kind(&self) -> Option<super::ScalarKind> {
|
pub fn scalar_kind(&self) -> Option<super::ScalarKind> {
|
||||||
match *self {
|
match *self {
|
||||||
@ -71,6 +71,50 @@ impl super::TypeInner {
|
|||||||
_ => None,
|
_ => 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 {
|
impl super::MathFunction {
|
||||||
|
@ -272,12 +272,9 @@ impl super::Validator {
|
|||||||
let (allowed_storage_access, required_type_flags, is_resource) = match var.class {
|
let (allowed_storage_access, required_type_flags, is_resource) = match var.class {
|
||||||
crate::StorageClass::Function => return Err(GlobalVariableError::InvalidUsage),
|
crate::StorageClass::Function => return Err(GlobalVariableError::InvalidUsage),
|
||||||
crate::StorageClass::Storage => {
|
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) {
|
if self.flags.contains(ValidationFlags::STRUCT_LAYOUTS) {
|
||||||
return Err(GlobalVariableError::Alignment(
|
return Err(GlobalVariableError::Alignment(ty_handle, disalignment));
|
||||||
ty_handle,
|
|
||||||
disalignment.clone(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
@ -287,12 +284,9 @@ impl super::Validator {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
crate::StorageClass::Uniform => {
|
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) {
|
if self.flags.contains(ValidationFlags::STRUCT_LAYOUTS) {
|
||||||
return Err(GlobalVariableError::Alignment(
|
return Err(GlobalVariableError::Alignment(ty_handle, disalignment));
|
||||||
ty_handle,
|
|
||||||
disalignment.clone(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
|
@ -6,7 +6,6 @@ mod r#type;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arena::{Arena, Handle},
|
arena::{Arena, Handle},
|
||||||
proc::Layouter,
|
|
||||||
FastHashSet,
|
FastHashSet,
|
||||||
};
|
};
|
||||||
use bit_set::BitSet;
|
use bit_set::BitSet;
|
||||||
@ -54,7 +53,6 @@ bitflags::bitflags! {
|
|||||||
pub struct ModuleInfo {
|
pub struct ModuleInfo {
|
||||||
functions: Vec<FunctionInfo>,
|
functions: Vec<FunctionInfo>,
|
||||||
entry_points: Vec<FunctionInfo>,
|
entry_points: Vec<FunctionInfo>,
|
||||||
pub layouter: Layouter,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Index<Handle<crate::Function>> for ModuleInfo {
|
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> {
|
pub fn validate(&mut self, module: &crate::Module) -> Result<ModuleInfo, ValidationError> {
|
||||||
self.reset_types(module.types.len());
|
self.reset_types(module.types.len());
|
||||||
|
|
||||||
let layouter = Layouter::new(&module.types, &module.constants);
|
|
||||||
|
|
||||||
for (handle, constant) in module.constants.iter() {
|
for (handle, constant) in module.constants.iter() {
|
||||||
self.validate_constant(handle, &module.constants, &module.types)
|
self.validate_constant(handle, &module.constants, &module.types)
|
||||||
.map_err(|error| ValidationError::Constant {
|
.map_err(|error| ValidationError::Constant {
|
||||||
@ -235,7 +231,7 @@ impl Validator {
|
|||||||
// doing after the globals, so that `type_flags` is ready
|
// doing after the globals, so that `type_flags` is ready
|
||||||
for (handle, ty) in module.types.iter() {
|
for (handle, ty) in module.types.iter() {
|
||||||
let ty_info = self
|
let ty_info = self
|
||||||
.validate_type(ty, handle, &module.constants, &layouter)
|
.validate_type(handle, &module.types, &module.constants)
|
||||||
.map_err(|error| ValidationError::Type {
|
.map_err(|error| ValidationError::Type {
|
||||||
handle,
|
handle,
|
||||||
name: ty.name.clone().unwrap_or_default(),
|
name: ty.name.clone().unwrap_or_default(),
|
||||||
@ -256,7 +252,6 @@ impl Validator {
|
|||||||
let mut mod_info = ModuleInfo {
|
let mut mod_info = ModuleInfo {
|
||||||
functions: Vec::with_capacity(module.functions.len()),
|
functions: Vec::with_capacity(module.functions.len()),
|
||||||
entry_points: Vec::with_capacity(module.entry_points.len()),
|
entry_points: Vec::with_capacity(module.entry_points.len()),
|
||||||
layouter,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (handle, fun) in module.functions.iter() {
|
for (handle, fun) in module.functions.iter() {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::arena::{Arena, Handle};
|
||||||
arena::{Arena, Handle},
|
|
||||||
proc::Layouter,
|
pub type Alignment = u32;
|
||||||
};
|
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@ -19,7 +18,7 @@ bitflags::bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, thiserror::Error)]
|
#[derive(Clone, Copy, Debug, thiserror::Error)]
|
||||||
pub enum Disalignment {
|
pub enum Disalignment {
|
||||||
#[error("The array stride {stride} is not a multiple of the required alignment {alignment}")]
|
#[error("The array stride {stride} is not a multiple of the required alignment {alignment}")]
|
||||||
ArrayStride { stride: u32, alignment: u32 },
|
ArrayStride { stride: u32, alignment: u32 },
|
||||||
@ -49,10 +48,6 @@ pub enum TypeError {
|
|||||||
InvalidArrayBaseType(Handle<crate::Type>),
|
InvalidArrayBaseType(Handle<crate::Type>),
|
||||||
#[error("The constant {0:?} can not be used for an array size")]
|
#[error("The constant {0:?} can not be used for an array size")]
|
||||||
InvalidArraySizeConstant(Handle<crate::Constant>),
|
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}")]
|
#[error("Array stride {stride} is smaller than the base element size {base_size}")]
|
||||||
InsufficientArrayStride { stride: u32, base_size: u32 },
|
InsufficientArrayStride { stride: u32, base_size: u32 },
|
||||||
#[error("Field '{0}' can't be dynamically-sized, has type {1:?}")]
|
#[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)`
|
// 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.
|
// For the uniform buffer alignment, array strides and struct sizes must be multiples of 16.
|
||||||
const UNIFORM_LAYOUT_ALIGNMENT_MASK: u32 = 0xF;
|
const UNIFORM_LAYOUT_ALIGNMENT_MASK: u32 = 0xF;
|
||||||
@ -81,19 +76,19 @@ pub(super) struct TypeInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeInfo {
|
impl TypeInfo {
|
||||||
fn new() -> Self {
|
fn dummy() -> Self {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
flags: TypeFlags::empty(),
|
flags: TypeFlags::empty(),
|
||||||
uniform_layout: Ok(()),
|
uniform_layout: Ok(0),
|
||||||
storage_layout: Ok(()),
|
storage_layout: Ok(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_flags(flags: TypeFlags) -> Self {
|
fn new(flags: TypeFlags, alignment: crate::Span) -> Self {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
flags,
|
flags,
|
||||||
uniform_layout: Ok(()),
|
uniform_layout: Ok(alignment),
|
||||||
storage_layout: Ok(()),
|
storage_layout: Ok(alignment),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,45 +103,64 @@ impl super::Validator {
|
|||||||
|
|
||||||
pub(super) fn reset_types(&mut self, size: usize) {
|
pub(super) fn reset_types(&mut self, size: usize) {
|
||||||
self.types.clear();
|
self.types.clear();
|
||||||
self.types.resize(size, TypeInfo::new());
|
self.types.resize(size, TypeInfo::dummy());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn validate_type(
|
pub(super) fn validate_type(
|
||||||
&self,
|
&self,
|
||||||
ty: &crate::Type,
|
|
||||||
handle: Handle<crate::Type>,
|
handle: Handle<crate::Type>,
|
||||||
|
types: &Arena<crate::Type>,
|
||||||
constants: &Arena<crate::Constant>,
|
constants: &Arena<crate::Constant>,
|
||||||
layouter: &Layouter,
|
|
||||||
) -> Result<TypeInfo, TypeError> {
|
) -> Result<TypeInfo, TypeError> {
|
||||||
use crate::TypeInner as Ti;
|
use crate::TypeInner as Ti;
|
||||||
Ok(match ty.inner {
|
Ok(match types[handle].inner {
|
||||||
Ti::Scalar { kind, width } | Ti::Vector { kind, width, .. } => {
|
Ti::Scalar { kind, width } => {
|
||||||
if !Self::check_width(kind, width) {
|
if !Self::check_width(kind, width) {
|
||||||
return Err(TypeError::InvalidWidth(kind, width));
|
return Err(TypeError::InvalidWidth(kind, width));
|
||||||
}
|
}
|
||||||
TypeInfo::from_flags(
|
TypeInfo::new(
|
||||||
TypeFlags::DATA
|
TypeFlags::DATA
|
||||||
| TypeFlags::SIZED
|
| TypeFlags::SIZED
|
||||||
| TypeFlags::INTERFACE
|
| TypeFlags::INTERFACE
|
||||||
| TypeFlags::HOST_SHARED,
|
| 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) {
|
if !Self::check_width(crate::ScalarKind::Float, width) {
|
||||||
return Err(TypeError::InvalidWidth(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::DATA
|
||||||
| TypeFlags::SIZED
|
| TypeFlags::SIZED
|
||||||
| TypeFlags::INTERFACE
|
| TypeFlags::INTERFACE
|
||||||
| TypeFlags::HOST_SHARED,
|
| TypeFlags::HOST_SHARED,
|
||||||
|
count * (width as u32),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Ti::Pointer { base, class: _ } => {
|
Ti::Pointer { base, class: _ } => {
|
||||||
if base >= handle {
|
if base >= handle {
|
||||||
return Err(TypeError::UnresolvedBase(base));
|
return Err(TypeError::UnresolvedBase(base));
|
||||||
}
|
}
|
||||||
TypeInfo::from_flags(TypeFlags::DATA | TypeFlags::SIZED)
|
TypeInfo::new(TypeFlags::DATA | TypeFlags::SIZED, 0)
|
||||||
}
|
}
|
||||||
Ti::ValuePointer {
|
Ti::ValuePointer {
|
||||||
size: _,
|
size: _,
|
||||||
@ -157,7 +171,7 @@ impl super::Validator {
|
|||||||
if !Self::check_width(kind, width) {
|
if !Self::check_width(kind, width) {
|
||||||
return Err(TypeError::InvalidWidth(kind, width));
|
return Err(TypeError::InvalidWidth(kind, width));
|
||||||
}
|
}
|
||||||
TypeInfo::from_flags(TypeFlags::SIZED)
|
TypeInfo::new(TypeFlags::SIZED, 0)
|
||||||
}
|
}
|
||||||
Ti::Array { base, size, stride } => {
|
Ti::Array { base, size, stride } => {
|
||||||
if base >= handle {
|
if base >= handle {
|
||||||
@ -171,23 +185,35 @@ impl super::Validator {
|
|||||||
return Err(TypeError::NestedBlock);
|
return Err(TypeError::NestedBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_layout = &layouter[base];
|
let base_size = types[base].inner.span(constants);
|
||||||
if let Some(stride) = stride {
|
if stride < base_size {
|
||||||
if stride.get() % base_layout.alignment.get() != 0 {
|
return Err(TypeError::InsufficientArrayStride { stride, base_size });
|
||||||
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 (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) => {
|
crate::ArraySize::Constant(const_handle) => {
|
||||||
match constants.try_get(const_handle) {
|
match constants.try_get(const_handle) {
|
||||||
Some(&crate::Constant {
|
Some(&crate::Constant {
|
||||||
@ -216,33 +242,17 @@ impl super::Validator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let effective_stride = match stride {
|
TypeFlags::SIZED
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
//Note: this will be detected at the struct level
|
//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;
|
let base_mask = TypeFlags::HOST_SHARED | TypeFlags::INTERFACE;
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
flags: TypeFlags::DATA | (base_info.flags & base_mask) | sized_flag,
|
flags: TypeFlags::DATA | (base_info.flags & base_mask) | sized_flag,
|
||||||
uniform_layout,
|
uniform_layout,
|
||||||
storage_layout: base_info.storage_layout.clone(),
|
storage_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ti::Struct { block, ref members } => {
|
Ti::Struct { block, ref members } => {
|
||||||
@ -250,8 +260,8 @@ impl super::Validator {
|
|||||||
| TypeFlags::SIZED
|
| TypeFlags::SIZED
|
||||||
| TypeFlags::HOST_SHARED
|
| TypeFlags::HOST_SHARED
|
||||||
| TypeFlags::INTERFACE;
|
| TypeFlags::INTERFACE;
|
||||||
let mut uniform_layout = Ok(());
|
let mut uniform_layout = Ok(1);
|
||||||
let mut storage_layout = Ok(());
|
let mut storage_layout = Ok(1);
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for (i, member) in members.iter().enumerate() {
|
for (i, member) in members.iter().enumerate() {
|
||||||
if member.ty >= handle {
|
if member.ty >= handle {
|
||||||
@ -269,28 +279,54 @@ impl super::Validator {
|
|||||||
}
|
}
|
||||||
flags &= base_info.flags;
|
flags &= base_info.flags;
|
||||||
|
|
||||||
let base_layout = &layouter[member.ty];
|
let base_size = types[member.ty].inner.span(constants);
|
||||||
let (range, _alignment) = layouter.member_placement(offset, member);
|
if member.span < base_size {
|
||||||
if range.end - range.start < base_layout.size {
|
|
||||||
return Err(TypeError::InsufficientMemberSize {
|
return Err(TypeError::InsufficientMemberSize {
|
||||||
index: i as u32,
|
index: i as u32,
|
||||||
size: range.end - range.start,
|
size: member.span,
|
||||||
base_size: base_layout.size,
|
base_size,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if range.start % base_layout.alignment.get() != 0 {
|
|
||||||
let result = Err((
|
uniform_layout = match (uniform_layout, base_info.uniform_layout) {
|
||||||
handle,
|
(Ok(cur_alignment), Ok(alignment)) => {
|
||||||
Disalignment::Member {
|
if offset % alignment != 0 {
|
||||||
index: i as u32,
|
Err((
|
||||||
offset: range.start,
|
handle,
|
||||||
alignment: base_layout.alignment.get(),
|
Disalignment::Member {
|
||||||
},
|
index: i as u32,
|
||||||
));
|
offset,
|
||||||
uniform_layout = uniform_layout.or_else(|_| result.clone());
|
alignment,
|
||||||
storage_layout = storage_layout.or(result);
|
},
|
||||||
}
|
))
|
||||||
offset = range.end;
|
} 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
|
// only the last field can be unsized
|
||||||
if !base_info.flags.contains(TypeFlags::SIZED) {
|
if !base_info.flags.contains(TypeFlags::SIZED) {
|
||||||
@ -303,9 +339,6 @@ impl super::Validator {
|
|||||||
Err((handle, Disalignment::UnsizedMember { index: i as u32 }));
|
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 {
|
if block {
|
||||||
flags |= TypeFlags::BLOCK;
|
flags |= TypeFlags::BLOCK;
|
||||||
@ -331,7 +364,7 @@ impl super::Validator {
|
|||||||
storage_layout,
|
storage_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::from_flags(TypeFlags::empty()),
|
Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::new(TypeFlags::empty(), 0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,24 +498,4 @@ expression: output
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
layouter: (
|
|
||||||
layouts: [
|
|
||||||
(
|
|
||||||
size: 4,
|
|
||||||
alignment: 4,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
size: 4,
|
|
||||||
alignment: 4,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
size: 4,
|
|
||||||
alignment: 4,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
size: 12,
|
|
||||||
alignment: 16,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ expression: output
|
|||||||
inner: Array(
|
inner: Array(
|
||||||
base: 1,
|
base: 1,
|
||||||
size: Dynamic,
|
size: Dynamic,
|
||||||
stride: Some(4),
|
stride: 4,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -28,8 +28,7 @@ expression: output
|
|||||||
name: Some("data"),
|
name: Some("data"),
|
||||||
ty: 2,
|
ty: 2,
|
||||||
binding: None,
|
binding: None,
|
||||||
size: None,
|
span: 4,
|
||||||
align: None,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -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,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
@ -112,8 +112,7 @@ expression: output
|
|||||||
name: Some("num_lights"),
|
name: Some("num_lights"),
|
||||||
ty: 13,
|
ty: 13,
|
||||||
binding: None,
|
binding: None,
|
||||||
size: None,
|
span: 16,
|
||||||
align: None,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -156,22 +155,19 @@ expression: output
|
|||||||
name: Some("proj"),
|
name: Some("proj"),
|
||||||
ty: 18,
|
ty: 18,
|
||||||
binding: None,
|
binding: None,
|
||||||
size: None,
|
span: 64,
|
||||||
align: None,
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
name: Some("pos"),
|
name: Some("pos"),
|
||||||
ty: 4,
|
ty: 4,
|
||||||
binding: None,
|
binding: None,
|
||||||
size: None,
|
span: 16,
|
||||||
align: None,
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
name: Some("color"),
|
name: Some("color"),
|
||||||
ty: 4,
|
ty: 4,
|
||||||
binding: None,
|
binding: None,
|
||||||
size: None,
|
span: 16,
|
||||||
align: None,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -181,7 +177,7 @@ expression: output
|
|||||||
inner: Array(
|
inner: Array(
|
||||||
base: 19,
|
base: 19,
|
||||||
size: Dynamic,
|
size: Dynamic,
|
||||||
stride: Some(96),
|
stride: 96,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -193,8 +189,7 @@ expression: output
|
|||||||
name: Some("data"),
|
name: Some("data"),
|
||||||
ty: 20,
|
ty: 20,
|
||||||
binding: None,
|
binding: None,
|
||||||
size: None,
|
span: 96,
|
||||||
align: None,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user