diff --git a/src/back/msl.rs b/src/back/msl.rs index bb74984a74..ed4a47d7cb 100644 --- a/src/back/msl.rs +++ b/src/back/msl.rs @@ -451,7 +451,11 @@ impl Writer { write!(self.out, ".{}", COMPONENTS[index as usize])?; Ok(MaybeOwned::Owned(crate::TypeInner::Scalar { kind, width })) } - crate::TypeInner::Array { base, size } => { + crate::TypeInner::Array { + base, + size, + stride: _, + } => { if let crate::ArraySize::Static(length) = size { return Err(Error::AccessIndexExceedsStaticLength(index, length)); } @@ -844,7 +848,11 @@ impl Writer { }; write!(self.out, "typedef {} {} *{}", class_name, base_name, name)?; } - crate::TypeInner::Array { base, size } => { + crate::TypeInner::Array { + base, + size, + stride: _, + } => { let base_name = module.types[base].name.or_index(base); let resolved_size = match size { crate::ArraySize::Static(length) => length, diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index 5ed31c344e..4124280d2d 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -335,7 +335,15 @@ impl Writer { self.lookup_type.insert(id, handle); } - crate::TypeInner::Array { base, size } => { + crate::TypeInner::Array { base, size, stride } => { + if let Some(array_stride) = stride { + let mut instruction = Instruction::new(Op::Decorate); + instruction.add_operand(id); + instruction.add_operand(Decoration::ArrayStride as u32); + instruction.add_operand(array_stride.get()); + self.annotations.push(instruction); + } + let type_id = self.get_type_id(arena, handle); instruction = Instruction::new(Op::TypeArray); diff --git a/src/front/glsl/mod.rs b/src/front/glsl/mod.rs index 603e75c36c..1cd44b0c3e 100644 --- a/src/front/glsl/mod.rs +++ b/src/front/glsl/mod.rs @@ -237,11 +237,13 @@ impl<'a> Parser<'a> { unimplemented!() } }, + stride: None, }, }) } else { ty }, + offset: 0, //TODO }); if name.is_none() { @@ -267,6 +269,7 @@ impl<'a> Parser<'a> { ArraySpecifier::Unsized => ArraySize::Dynamic, ArraySpecifier::ExplicitlySized(_expr) => unimplemented!(), }, + stride: None, }, }) } else { @@ -337,6 +340,7 @@ impl<'a> Parser<'a> { inner: TypeInner::Array { base: ty, size: ArraySize::Dynamic, + stride: None, }, }), ArraySpecifier::ExplicitlySized(_) => unimplemented!(), @@ -447,6 +451,7 @@ impl<'a> Parser<'a> { inner: TypeInner::Array { base: ty, size: ArraySize::Dynamic, + stride: None, }, }), ArraySpecifier::ExplicitlySized(_) => unimplemented!(), @@ -1066,6 +1071,7 @@ impl<'a> Parser<'a> { ArraySpecifier::Unsized => TypeInner::Array { base: handle, size: ArraySize::Dynamic, + stride: None, }, ArraySpecifier::ExplicitlySized(_) => unimplemented!(), } @@ -1091,6 +1097,7 @@ impl<'a> Parser<'a> { inner: TypeInner::Array { base: ty, size: ArraySize::Dynamic, + stride: None, }, }), ArraySpecifier::ExplicitlySized(_) => unimplemented!(), diff --git a/src/front/spv.rs b/src/front/spv.rs index 79fdf83308..cdee75660d 100644 --- a/src/front/spv.rs +++ b/src/front/spv.rs @@ -16,7 +16,7 @@ use crate::{ }; use num_traits::cast::FromPrimitive; -use std::convert::TryInto; +use std::{convert::TryInto, num::NonZeroU32}; pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[spirv::Capability::Shader]; pub const SUPPORTED_EXTENSIONS: &[&str] = &[]; @@ -54,6 +54,7 @@ pub enum Error { InvalidBinding(spirv::Word), WrongFunctionResultType(spirv::Word), WrongFunctionParameterType(spirv::Word), + MissingDecoration(spirv::Decoration), BadString, IncompleteData, } @@ -125,6 +126,11 @@ fn map_storage_class(word: spirv::Word) -> Result { type MemberIndex = u32; +#[derive(Debug, Default)] +struct Block { + buffer: bool, +} + #[derive(Debug, Default)] struct Decoration { name: Option, @@ -132,6 +138,9 @@ struct Decoration { location: Option, desc_set: Option, desc_index: Option, + block: Option, + offset: Option, + array_stride: Option, } impl Decoration { @@ -310,6 +319,20 @@ impl> Parser { inst.expect(base_words + 2)?; dec.desc_index = Some(self.next()?); } + spirv::Decoration::Block => { + dec.block = Some(Block { buffer: false }); + } + spirv::Decoration::BufferBlock => { + dec.block = Some(Block { buffer: true }); + } + spirv::Decoration::Offset => { + inst.expect(base_words + 2)?; + dec.offset = Some(self.next()?); + } + spirv::Decoration::ArrayStride => { + inst.expect(base_words + 2)?; + dec.array_stride = NonZeroU32::new(self.next()?); + } other => { log::warn!("Unknown decoration {:?}", other); for _ in base_words + 1..inst.wc { @@ -1143,15 +1166,18 @@ impl> Parser { let id = self.next()?; let type_id = self.next()?; let length = self.next()?; + + let decor = self.future_decor.remove(&id); let inner = crate::TypeInner::Array { base: self.lookup_type.lookup(type_id)?.handle, size: crate::ArraySize::Static(length), + stride: decor.as_ref().and_then(|dec| dec.array_stride), }; self.lookup_type.insert( id, LookupType { handle: module.types.append(crate::Type { - name: self.future_decor.remove(&id).and_then(|dec| dec.name), + name: decor.and_then(|dec| dec.name), inner, }), base_id: Some(type_id), @@ -1169,15 +1195,18 @@ impl> Parser { inst.expect(4)?; let id = self.next()?; let type_id = self.next()?; + + let decor = self.future_decor.remove(&id); 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), }; self.lookup_type.insert( id, LookupType { handle: module.types.append(crate::Type { - name: self.future_decor.remove(&id).and_then(|dec| dec.name), + name: decor.and_then(|dec| dec.name), inner, }), base_id: Some(type_id), @@ -1208,14 +1237,23 @@ impl> Parser { name: decor.name, binding, ty, + offset: decor + .offset + .ok_or(Error::MissingDecoration(spirv::Decoration::Offset))?, }); } let inner = crate::TypeInner::Struct { members }; + let decor = self.future_decor.remove(&id); + if let Some(ref decor) = decor { + if decor.block.is_some() { + // do nothing + } + } self.lookup_type.insert( id, LookupType { handle: module.types.append(crate::Type { - name: self.future_decor.remove(&id).and_then(|dec| dec.name), + name: decor.and_then(|dec| dec.name), inner, }), base_id: None, diff --git a/src/front/wgsl.rs b/src/front/wgsl.rs index 5e34032ff4..d1d266d31e 100644 --- a/src/front/wgsl.rs +++ b/src/front/wgsl.rs @@ -146,6 +146,7 @@ pub enum Error<'a> { UnknownIdent(&'a str), UnknownType(&'a str), UnknownFunction(&'a str), + MissingMemberOffset(&'a str), MutabilityViolation(&'a str), Other, } @@ -930,6 +931,7 @@ impl Parser { let mut members = Vec::new(); lexer.expect(Token::Paren('{'))?; loop { + let mut offset = !0; if lexer.skip(Token::DoubleParen('[')) { self.scopes.push(Scope::Decoration); let mut ready = true; @@ -942,7 +944,7 @@ impl Parser { ready = true; } Token::Word("offset") if ready => { - let _offset = lexer.next_uint_literal()?; //TODO + offset = lexer.next_uint_literal()?; ready = false; } other => return Err(Error::Unexpected(other)), @@ -955,6 +957,9 @@ impl Parser { Token::Paren('}') => return Ok(members), other => return Err(Error::Unexpected(other)), }; + if offset == !0 { + return Err(Error::MissingMemberOffset(name)); + } lexer.expect(Token::Separator(':'))?; let ty = self.parse_type_decl(lexer, type_arena)?; lexer.expect(Token::Separator(';'))?; @@ -962,6 +967,7 @@ impl Parser { name: Some(name.to_owned()), binding: None, ty, + offset, }); } } @@ -1056,7 +1062,11 @@ impl Parser { Token::Separator('>') => crate::ArraySize::Dynamic, other => return Err(Error::Unexpected(other)), }; - crate::TypeInner::Array { base, size } + crate::TypeInner::Array { + base, + size, + stride: None, + } } Token::Word("struct") => { let members = self.parse_struct_body(lexer, type_arena)?; diff --git a/src/lib.rs b/src/lib.rs index c755629884..c163e89a11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub use crate::arena::{Arena, Handle}; use std::{ collections::{HashMap, HashSet}, hash::BuildHasherDefault, + num::NonZeroU32, }; pub type FastHashMap = HashMap>; @@ -53,6 +54,7 @@ pub struct StructMember { pub name: Option, pub binding: Option, pub ty: Handle, + pub offset: spirv::Word, } bitflags::bitflags! { @@ -96,6 +98,7 @@ pub enum TypeInner { Array { base: Handle, size: ArraySize, + stride: Option, }, Struct { members: Vec,