mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Implement default layout in the IR and WGSL
This commit is contained in:
@@ -858,18 +858,14 @@ impl Writer {
|
||||
let mut current_offset = 0;
|
||||
let mut member_ids = Vec::with_capacity(members.len());
|
||||
for (index, member) in members.iter().enumerate() {
|
||||
let layout = self.layouter.resolve(member.ty);
|
||||
current_offset += layout.pad(current_offset);
|
||||
let (placement, _) = self.layouter.member_placement(current_offset, member);
|
||||
self.annotations.push(Instruction::member_decorate(
|
||||
id,
|
||||
index as u32,
|
||||
spirv::Decoration::Offset,
|
||||
&[current_offset],
|
||||
&[placement.start],
|
||||
));
|
||||
current_offset += match member.span {
|
||||
Some(span) => span.get(),
|
||||
None => layout.size,
|
||||
};
|
||||
current_offset = placement.end;
|
||||
|
||||
if self.flags.contains(WriterFlags::DEBUG) {
|
||||
if let Some(ref name) = member.name {
|
||||
|
||||
@@ -725,9 +725,12 @@ pomelo! {
|
||||
if let Some(ty) = t {
|
||||
sdl.iter().map(|name| StructMember {
|
||||
name: Some(name.clone()),
|
||||
span: None,
|
||||
ty,
|
||||
binding: None, //TODO
|
||||
//TODO: if the struct is a uniform struct, these values have to reflect
|
||||
// std140 layout. Otherwise, std430.
|
||||
size: None,
|
||||
align: None,
|
||||
}).collect()
|
||||
} else {
|
||||
return Err(ErrorKind::SemanticError("Struct member can't be void".into()))
|
||||
|
||||
@@ -237,9 +237,10 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
|
||||
if let super::Variable::Output(ref result) = lvar.inner {
|
||||
members.push(crate::StructMember {
|
||||
name: None,
|
||||
span: None,
|
||||
ty: result.ty,
|
||||
binding: result.binding.clone(),
|
||||
size: None,
|
||||
align: None,
|
||||
});
|
||||
// populate just the globals first, then do `Load` in a
|
||||
// separate step, so that we can get a range.
|
||||
|
||||
@@ -2369,9 +2369,10 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
host_shared |= decor.offset.is_some();
|
||||
members.push(crate::StructMember {
|
||||
name: decor.name,
|
||||
span: None, //TODO
|
||||
ty,
|
||||
binding: None,
|
||||
size: None, //TODO
|
||||
align: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ pub enum Error<'a> {
|
||||
UnknownConservativeDepth(&'a str),
|
||||
#[error("array stride must not be 0")]
|
||||
ZeroStride,
|
||||
#[error("struct member size or array must not be 0")]
|
||||
ZeroSizeOrAlign,
|
||||
#[error("not a composite type: {0:?}")]
|
||||
NotCompositeType(Handle<crate::Type>),
|
||||
#[error("Input/output binding is not consistent: location {0:?}, built-in {1:?} and interpolation {2:?}")]
|
||||
@@ -1502,7 +1504,7 @@ impl Parser {
|
||||
let mut members = Vec::new();
|
||||
lexer.expect(Token::Paren('{'))?;
|
||||
loop {
|
||||
let mut span = 0;
|
||||
let (mut size, mut align) = (None, None);
|
||||
let mut bind_parser = BindingParser::default();
|
||||
if lexer.skip(Token::DoubleParen('[')) {
|
||||
self.scopes.push(Scope::Decoration);
|
||||
@@ -1517,17 +1519,19 @@ impl Parser {
|
||||
}
|
||||
(Token::Word(word), _) if ready => {
|
||||
match word {
|
||||
"span" => {
|
||||
"size" => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
//Note: 0 is not handled
|
||||
span = lexer.next_uint_literal()?;
|
||||
let value = lexer.next_uint_literal()?;
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
size =
|
||||
Some(NonZeroU32::new(value).ok_or(Error::ZeroSizeOrAlign)?);
|
||||
}
|
||||
"offset" => {
|
||||
// skip - only here for parsing compatibility
|
||||
"align" => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
let _offset = lexer.next_uint_literal()?;
|
||||
let value = lexer.next_uint_literal()?;
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
align =
|
||||
Some(NonZeroU32::new(value).ok_or(Error::ZeroSizeOrAlign)?);
|
||||
}
|
||||
_ => bind_parser.parse(lexer, word)?,
|
||||
}
|
||||
@@ -1550,9 +1554,10 @@ impl Parser {
|
||||
|
||||
members.push(crate::StructMember {
|
||||
name: Some(name.to_owned()),
|
||||
span: NonZeroU32::new(span),
|
||||
ty,
|
||||
binding: bind_parser.finish()?,
|
||||
size,
|
||||
align,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,11 @@ fn parse_struct() {
|
||||
parse_str(
|
||||
"
|
||||
[[block]] struct Foo { x: i32; };
|
||||
struct Bar { [[span(16)]] x: vec2<i32>; };
|
||||
struct Bar {
|
||||
[[size(16)]] x: vec2<i32>;
|
||||
[[align(16)]] y: f32;
|
||||
[[size(32), align(8)]] z: vec3<f32>;
|
||||
};
|
||||
struct Empty {};
|
||||
var s: [[access(read_write)]] Foo;
|
||||
",
|
||||
|
||||
@@ -238,10 +238,14 @@ pub enum Interpolation {
|
||||
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
|
||||
pub struct StructMember {
|
||||
pub name: Option<String>,
|
||||
pub span: Option<NonZeroU32>,
|
||||
/// Type of the field.
|
||||
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>,
|
||||
}
|
||||
|
||||
/// The number of dimensions an image has.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::arena::Arena;
|
||||
use std::num::NonZeroU32;
|
||||
use std::{num::NonZeroU32, ops};
|
||||
|
||||
pub type Alignment = NonZeroU32;
|
||||
|
||||
@@ -10,17 +10,9 @@ pub struct TypeLayout {
|
||||
pub alignment: Alignment,
|
||||
}
|
||||
|
||||
impl TypeLayout {
|
||||
/// Return padding to this type given an offset.
|
||||
pub fn pad(&self, offset: u32) -> u32 {
|
||||
match offset & self.alignment.get() {
|
||||
0 => 0,
|
||||
other => self.alignment.get() - other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper processor that derives the sizes of all types.
|
||||
/// It uses the default layout algorithm/table, described in
|
||||
/// https://github.com/gpuweb/gpuweb/issues/1393
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Layouter {
|
||||
layouts: Vec<TypeLayout>,
|
||||
@@ -33,6 +25,29 @@ impl Layouter {
|
||||
this
|
||||
}
|
||||
|
||||
pub fn round_up(alignment: NonZeroU32, offset: u32) -> u32 {
|
||||
match offset & alignment.get() {
|
||||
0 => offset,
|
||||
other => offset + alignment.get() - other,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
let start = Self::round_up(alignment, offset);
|
||||
let end = start
|
||||
+ match member.size {
|
||||
Some(size) => size.get(),
|
||||
None => layout.size,
|
||||
};
|
||||
(start..end, alignment)
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self, types: &Arena<crate::Type>, constants: &Arena<crate::Constant>) {
|
||||
use crate::TypeInner as Ti;
|
||||
|
||||
@@ -51,8 +66,10 @@ impl Layouter {
|
||||
width,
|
||||
} => TypeLayout {
|
||||
size: (size as u8 * width) as u32,
|
||||
//TODO: reconsider if this needs to match the size
|
||||
alignment: Alignment::new(width as u32).unwrap(),
|
||||
alignment: {
|
||||
let count = if size >= crate::VectorSize::Tri { 4 } else { 2 };
|
||||
Alignment::new((count * width) as u32).unwrap()
|
||||
},
|
||||
},
|
||||
Ti::Matrix {
|
||||
columns,
|
||||
@@ -60,7 +77,10 @@ impl Layouter {
|
||||
width,
|
||||
} => TypeLayout {
|
||||
size: (columns as u8 * rows as u8 * width) as u32,
|
||||
alignment: Alignment::new((columns as u8 * width) as u32).unwrap(),
|
||||
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,
|
||||
@@ -83,11 +103,15 @@ impl Layouter {
|
||||
} => value as u32,
|
||||
ref other => unreachable!("Unexpected array size {:?}", other),
|
||||
},
|
||||
crate::ArraySize::Dynamic => 1,
|
||||
crate::ArraySize::Dynamic => 0,
|
||||
};
|
||||
let stride = match stride {
|
||||
Some(value) => value,
|
||||
None => Alignment::new(self.layouts[base.index()].size.max(1)).unwrap(),
|
||||
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(),
|
||||
@@ -101,18 +125,12 @@ impl Layouter {
|
||||
let mut total = 0;
|
||||
let mut biggest_alignment = Alignment::new(1).unwrap();
|
||||
for member in members {
|
||||
let member_layout = self.layouts[member.ty.index()];
|
||||
biggest_alignment = biggest_alignment.max(member_layout.alignment);
|
||||
// align up first
|
||||
total += member_layout.pad(total);
|
||||
// then add the size
|
||||
total += match member.span {
|
||||
Some(span) => span.get(),
|
||||
None => member_layout.size,
|
||||
};
|
||||
let (placement, alignment) = self.member_placement(total, member);
|
||||
biggest_alignment = biggest_alignment.max(alignment);
|
||||
total = placement.end;
|
||||
}
|
||||
TypeLayout {
|
||||
size: total,
|
||||
size: Self::round_up(biggest_alignment, total),
|
||||
alignment: biggest_alignment,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,7 +555,11 @@ impl Validator {
|
||||
}
|
||||
TypeFlags::SIZED //TODO: `DATA`?
|
||||
}
|
||||
Ti::Array { base, size, stride } => {
|
||||
Ti::Array {
|
||||
base,
|
||||
size,
|
||||
stride: _,
|
||||
} => {
|
||||
if base >= handle {
|
||||
return Err(TypeError::UnresolvedBase(base));
|
||||
}
|
||||
@@ -596,11 +600,7 @@ impl Validator {
|
||||
}
|
||||
crate::ArraySize::Dynamic => TypeFlags::empty(),
|
||||
};
|
||||
let base_mask = if stride.is_none() {
|
||||
TypeFlags::INTERFACE
|
||||
} else {
|
||||
TypeFlags::HOST_SHARED | TypeFlags::INTERFACE
|
||||
};
|
||||
let base_mask = TypeFlags::HOST_SHARED | TypeFlags::INTERFACE;
|
||||
TypeFlags::DATA | (base_flags & base_mask) | sized_flag
|
||||
}
|
||||
Ti::Struct { block, ref members } => {
|
||||
|
||||
@@ -26,9 +26,10 @@ expression: output
|
||||
members: [
|
||||
(
|
||||
name: Some("data"),
|
||||
span: None,
|
||||
ty: 2,
|
||||
binding: None,
|
||||
size: None,
|
||||
align: None,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -110,9 +110,10 @@ expression: output
|
||||
members: [
|
||||
(
|
||||
name: Some("num_lights"),
|
||||
span: None,
|
||||
ty: 13,
|
||||
binding: None,
|
||||
size: None,
|
||||
align: None,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -153,21 +154,24 @@ expression: output
|
||||
members: [
|
||||
(
|
||||
name: Some("proj"),
|
||||
span: None,
|
||||
ty: 18,
|
||||
binding: None,
|
||||
size: None,
|
||||
align: None,
|
||||
),
|
||||
(
|
||||
name: Some("pos"),
|
||||
span: None,
|
||||
ty: 4,
|
||||
binding: None,
|
||||
size: None,
|
||||
align: None,
|
||||
),
|
||||
(
|
||||
name: Some("color"),
|
||||
span: None,
|
||||
ty: 4,
|
||||
binding: None,
|
||||
size: None,
|
||||
align: None,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -187,9 +191,10 @@ expression: output
|
||||
members: [
|
||||
(
|
||||
name: Some("data"),
|
||||
span: None,
|
||||
ty: 20,
|
||||
binding: None,
|
||||
size: None,
|
||||
align: None,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user