mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-10-30 05:52:44 +00:00
handle spirv group decorations (#1126)
This commit is contained in:
parent
51cc13a0f4
commit
84d6f1b33a
@ -29,12 +29,9 @@ pub fn write_descriptor_sets(doc: &Spirv) -> TokenStream {
|
||||
}
|
||||
|
||||
// Looping to find all the elements that have the `DescriptorSet` decoration.
|
||||
for instruction in doc.instructions.iter() {
|
||||
let (variable_id, set) = match instruction {
|
||||
&Instruction::Decorate { target_id, decoration: Decoration::DecorationDescriptorSet, ref params }
|
||||
=> (target_id, params[0]),
|
||||
_ => continue,
|
||||
};
|
||||
for set_decoration in doc.get_decorations(Decoration::DecorationDescriptorSet) {
|
||||
let variable_id = set_decoration.target_id;
|
||||
let set = set_decoration.params[0];
|
||||
|
||||
// Find which type is pointed to by this variable.
|
||||
let pointed_ty = pointer_variable_ty(doc, variable_id);
|
||||
@ -42,20 +39,8 @@ pub fn write_descriptor_sets(doc: &Spirv) -> TokenStream {
|
||||
let name = spirv_search::name_from_id(doc, variable_id);
|
||||
|
||||
// Find the binding point of this descriptor.
|
||||
let binding = doc.instructions
|
||||
.iter()
|
||||
.filter_map(|i| {
|
||||
match i {
|
||||
&Instruction::Decorate {
|
||||
target_id,
|
||||
decoration: Decoration::DecorationBinding,
|
||||
ref params,
|
||||
} if target_id == variable_id => Some(params[0]),
|
||||
_ => None, // TODO: other types
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.expect(&format!("Uniform `{}` is missing a binding", name));
|
||||
// TODO: There was a previous todo here, I think it was asking for this to be implemented for member decorations? check git history
|
||||
let binding = doc.get_decoration_params(variable_id, Decoration::DecorationBinding).unwrap()[0];
|
||||
|
||||
// Find information about the kind of binding for this descriptor.
|
||||
let (desc_ty, readonly, array_count) = descriptor_infos(doc, pointed_ty, false)
|
||||
@ -200,18 +185,10 @@ fn descriptor_infos(doc: &Spirv, pointed_ty: u32, force_combined_image_sampled:
|
||||
match i {
|
||||
&Instruction::TypeStruct { result_id, .. } if result_id == pointed_ty => {
|
||||
// Determine whether there's a Block or BufferBlock decoration.
|
||||
let is_ssbo = doc.instructions.iter().filter_map(|i| {
|
||||
match i {
|
||||
&Instruction::Decorate
|
||||
{ target_id, decoration: Decoration::DecorationBufferBlock, .. }
|
||||
if target_id == pointed_ty => Some(true),
|
||||
&Instruction::Decorate
|
||||
{ target_id, decoration: Decoration::DecorationBlock, .. }
|
||||
if target_id == pointed_ty => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}).next().expect("Found a buffer uniform with neither the Block nor BufferBlock \
|
||||
decorations");
|
||||
let decoration_buffer_block = doc.get_decoration_params(pointed_ty, Decoration::DecorationBufferBlock).is_some();
|
||||
let decoration_block = doc.get_decoration_params(pointed_ty, Decoration::DecorationBlock).is_some();
|
||||
assert!(decoration_buffer_block ^ decoration_block, "Found a buffer uniform with neither the Block nor BufferBlock decorations, or both.");
|
||||
let is_ssbo = decoration_buffer_block && !decoration_block;
|
||||
|
||||
// Determine whether there's a NonWritable decoration.
|
||||
//let non_writable = false; // TODO: tricky because the decoration is on struct members
|
||||
|
@ -10,7 +10,7 @@
|
||||
use syn::Ident;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
|
||||
use enums::{StorageClass, ExecutionModel, ExecutionMode};
|
||||
use enums::{StorageClass, ExecutionModel, ExecutionMode, Decoration};
|
||||
use parse::{Instruction, Spirv};
|
||||
use spirv_search;
|
||||
|
||||
@ -221,11 +221,9 @@ fn write_interface_structs(doc: &Spirv, capitalized_ep_name: &str, interface: &[
|
||||
continue;
|
||||
} // FIXME: hack
|
||||
|
||||
let location = match spirv_search::location_decoration(doc, result_id) {
|
||||
Some(l) => l,
|
||||
None => panic!("Attribute `{}` (id {}) is missing a location",
|
||||
name,
|
||||
result_id),
|
||||
let location = match doc.get_decoration_params(result_id, Decoration::DecorationLocation) {
|
||||
Some(l) => l[0],
|
||||
None => panic!("Attribute `{}` (id {}) is missing a location", name, result_id),
|
||||
};
|
||||
|
||||
let (format, location_len) = spirv_search::format_from_id(doc, result_type_id, ignore_first_array);
|
||||
|
@ -15,7 +15,7 @@ use parse::ParseError;
|
||||
macro_rules! enumeration {
|
||||
($(typedef enum $unused:ident { $($elem:ident = $value:expr,)+ } $name:ident;)+) => (
|
||||
$(
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum $name {
|
||||
$($elem),+
|
||||
}
|
||||
|
@ -161,6 +161,17 @@ pub enum Instruction {
|
||||
decoration: Decoration,
|
||||
params: Vec<u32>,
|
||||
},
|
||||
DecorationGroup {
|
||||
result_id: u32,
|
||||
},
|
||||
GroupDecorate {
|
||||
decoration_group: u32,
|
||||
targets: Vec<u32>,
|
||||
},
|
||||
GroupMemberDecorate {
|
||||
decoration_group: u32,
|
||||
targets: Vec<(u32, u32)>,
|
||||
},
|
||||
Label { result_id: u32 },
|
||||
Branch { result_id: u32 },
|
||||
Kill,
|
||||
@ -331,6 +342,17 @@ fn decode_instruction(opcode: u16, operands: &[u32]) -> Result<Instruction, Pars
|
||||
decoration: Decoration::from_num(operands[2])?,
|
||||
params: operands[3 ..].to_owned(),
|
||||
},
|
||||
73 => Instruction::DecorationGroup {
|
||||
result_id: operands[0],
|
||||
},
|
||||
74 => Instruction::GroupDecorate {
|
||||
decoration_group: operands[0],
|
||||
targets: operands[1 ..].to_owned(),
|
||||
},
|
||||
75 => Instruction::GroupMemberDecorate {
|
||||
decoration_group: operands[0],
|
||||
targets: operands.chunks(2).map(|x| (x[0], x[1])).collect(),
|
||||
},
|
||||
248 => Instruction::Label { result_id: operands[0] },
|
||||
249 => Instruction::Branch { result_id: operands[0] },
|
||||
252 => Instruction::Kill,
|
||||
@ -357,6 +379,151 @@ fn parse_string(data: &[u32]) -> (String, &[u32]) {
|
||||
(s, &data[r ..])
|
||||
}
|
||||
|
||||
pub(crate) struct FoundDecoration {
|
||||
pub target_id: u32,
|
||||
pub params: Vec<u32>
|
||||
}
|
||||
|
||||
impl Spirv {
|
||||
/// Returns the params and the id of all decorations that match the passed Decoration type
|
||||
///
|
||||
/// for each matching OpDecorate:
|
||||
/// if it points at a regular target:
|
||||
/// creates a FoundDecoration with its params and target_id
|
||||
/// if it points at a group:
|
||||
/// the OpDecorate's target_id is ignored and a seperate FoundDecoration is created only for each target_id given in matching OpGroupDecorate instructions.
|
||||
pub(crate) fn get_decorations(&self, find_decoration: Decoration) -> Vec<FoundDecoration> {
|
||||
let mut decorations = vec!();
|
||||
for instruction in &self.instructions {
|
||||
if let Instruction::Decorate { target_id, ref decoration, ref params } = instruction {
|
||||
if *decoration == find_decoration {
|
||||
// assume by default it is just pointing at the target_id
|
||||
let mut target_ids = vec!(*target_id);
|
||||
|
||||
// however it might be pointing at a group, which can have multiple target_ids
|
||||
for inner_instruction in &self.instructions {
|
||||
if let Instruction::DecorationGroup { result_id } = inner_instruction {
|
||||
if *result_id == *target_id {
|
||||
target_ids.clear();
|
||||
|
||||
for inner_instruction in &self.instructions {
|
||||
if let Instruction::GroupDecorate { decoration_group, targets } = inner_instruction {
|
||||
if *decoration_group == *target_id {
|
||||
target_ids.extend(targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// result_id must be unique so we can safely break here
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create for all target_ids found
|
||||
for target_id in target_ids {
|
||||
decorations.push(FoundDecoration {
|
||||
target_id,
|
||||
params: params.clone()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
decorations
|
||||
}
|
||||
|
||||
/// Returns the params held by the decoration for the specified id and type
|
||||
/// Searches OpDecorate and OpGroupMemberDecorate
|
||||
/// Returns None if such a decoration does not exist
|
||||
pub(crate) fn get_decoration_params(&self, id: u32, find_decoration: Decoration) -> Option<Vec<u32>> {
|
||||
for instruction in &self.instructions {
|
||||
match instruction {
|
||||
Instruction::Decorate { target_id, ref decoration, ref params }
|
||||
if *target_id == id && *decoration == find_decoration => {
|
||||
return Some(params.clone());
|
||||
}
|
||||
Instruction::GroupDecorate { decoration_group, ref targets } => {
|
||||
for group_target_id in targets {
|
||||
if *group_target_id == id {
|
||||
for instruction in &self.instructions {
|
||||
if let Instruction::Decorate { target_id, ref decoration, ref params } = instruction {
|
||||
if target_id == decoration_group && *decoration == find_decoration {
|
||||
return Some(params.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the params held by the decoration for the member specified by id, member and type
|
||||
/// Searches OpMemberDecorate and OpGroupMemberDecorate
|
||||
/// Returns None if such a decoration does not exist
|
||||
pub(crate) fn get_member_decoration_params(&self, struct_id: u32, member_literal: u32, find_decoration: Decoration) -> Option<Vec<u32>> {
|
||||
for instruction in &self.instructions {
|
||||
match instruction {
|
||||
Instruction::MemberDecorate { target_id, member, ref decoration, ref params }
|
||||
if *target_id == struct_id && *member == member_literal && *decoration == find_decoration => {
|
||||
return Some(params.clone());
|
||||
}
|
||||
Instruction::GroupMemberDecorate { decoration_group, ref targets } => {
|
||||
for (group_target_struct_id, group_target_member_literal) in targets {
|
||||
if *group_target_struct_id == struct_id && *group_target_member_literal == member_literal {
|
||||
for instruction in &self.instructions {
|
||||
if let Instruction::Decorate { target_id, ref decoration, ref params } = instruction {
|
||||
if target_id == decoration_group && *decoration == find_decoration {
|
||||
return Some(params.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the params held by the Decoration::DecorationBuiltIn for the specified struct id
|
||||
/// Searches OpMemberDecorate and OpGroupMemberDecorate
|
||||
/// Returns None if such a decoration does not exist
|
||||
///
|
||||
/// This function does not need a member_literal argument because the spirv spec requires that a
|
||||
/// struct must contain either all builtin or all non-builtin members.
|
||||
pub(crate) fn get_member_decoration_builtin_params(&self, struct_id: u32) -> Option<Vec<u32>> {
|
||||
for instruction in &self.instructions {
|
||||
match instruction {
|
||||
Instruction::MemberDecorate { target_id, decoration: Decoration::DecorationBuiltIn, ref params, .. }
|
||||
if *target_id == struct_id => {
|
||||
return Some(params.clone());
|
||||
}
|
||||
Instruction::GroupMemberDecorate { decoration_group, ref targets } => {
|
||||
for (group_target_struct_id, _) in targets {
|
||||
if *group_target_struct_id == struct_id {
|
||||
for instruction in &self.instructions {
|
||||
if let Instruction::Decorate { target_id, decoration: Decoration::DecorationBuiltIn, ref params } = instruction {
|
||||
if target_id == decoration_group {
|
||||
return Some(params.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use parse;
|
||||
|
@ -72,15 +72,8 @@ pub fn write_specialization_constants(doc: &Spirv) -> TokenStream {
|
||||
let (rust_ty, rust_size, rust_alignment) = spec_const_type_from_id(doc, type_id);
|
||||
let rust_size = rust_size.expect("Found runtime-sized specialization constant");
|
||||
|
||||
let constant_id = doc.instructions
|
||||
.iter()
|
||||
.filter_map(|i| match i {
|
||||
&Instruction::Decorate { target_id, decoration: Decoration::DecorationSpecId, ref params }
|
||||
if target_id == result_id => Some(params[0]),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
.expect("Found a specialization constant with no SpecId decoration");
|
||||
let constant_id = doc.get_decoration_params(result_id, Decoration::DecorationSpecId)
|
||||
.unwrap()[0];
|
||||
|
||||
spec_consts.push(SpecConst {
|
||||
name: spirv_search::name_from_id(doc, result_id),
|
||||
|
@ -130,28 +130,13 @@ pub fn member_name_from_id(doc: &Spirv, searched: u32, searched_member: u32) ->
|
||||
String::from("__unnamed")
|
||||
}
|
||||
|
||||
pub fn location_decoration(doc: &Spirv, searched: u32) -> Option<u32> {
|
||||
for instruction in &doc.instructions {
|
||||
if let &Instruction::Decorate { target_id, decoration: Decoration::DecorationLocation, ref params } = instruction {
|
||||
if target_id == searched {
|
||||
return Some(params[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns true if a `BuiltIn` decorator is applied on an id.
|
||||
pub fn is_builtin(doc: &Spirv, id: u32) -> bool {
|
||||
for instruction in &doc.instructions {
|
||||
match *instruction {
|
||||
Instruction::Decorate { target_id, decoration: Decoration::DecorationBuiltIn, .. }
|
||||
if target_id == id => { return true }
|
||||
Instruction::MemberDecorate { target_id, decoration: Decoration::DecorationBuiltIn, .. }
|
||||
if target_id == id => { return true }
|
||||
_ => (),
|
||||
}
|
||||
if doc.get_decoration_params(id, Decoration::DecorationBuiltIn).is_some() {
|
||||
return true
|
||||
}
|
||||
if doc.get_member_decoration_builtin_params(id).is_some() {
|
||||
return true
|
||||
}
|
||||
|
||||
for instruction in &doc.instructions {
|
||||
|
@ -57,29 +57,13 @@ fn write_struct(doc: &Spirv, struct_id: u32, members: &[u32]) -> (TokenStream, O
|
||||
|
||||
// Ignore the whole struct is a member is built in, which includes
|
||||
// `gl_Position` for example.
|
||||
if is_builtin_member(doc, struct_id, num as u32) {
|
||||
if doc.get_member_decoration_params(struct_id, num as u32, Decoration::DecorationBuiltIn).is_some() {
|
||||
return (quote!{}, None); // TODO: is this correct? shouldn't it return a correct struct but with a flag or something?
|
||||
}
|
||||
|
||||
// Finding offset of the current member, as requested by the SPIR-V code.
|
||||
let spirv_offset = doc.instructions
|
||||
.iter()
|
||||
.filter_map(|i| {
|
||||
match *i {
|
||||
Instruction::MemberDecorate {
|
||||
target_id,
|
||||
member,
|
||||
decoration: Decoration::DecorationOffset,
|
||||
ref params,
|
||||
} if target_id == struct_id && member as usize == num => {
|
||||
return Some(params[0]);
|
||||
},
|
||||
_ => (),
|
||||
};
|
||||
|
||||
None
|
||||
})
|
||||
.next();
|
||||
let spirv_offset = doc.get_member_decoration_params(struct_id, num as u32, Decoration::DecorationOffset)
|
||||
.map(|x| x[0]);
|
||||
|
||||
// Some structs don't have `Offset` decorations, in the case they are used as local
|
||||
// variables only. Ignoring these.
|
||||
@ -128,39 +112,22 @@ fn write_struct(doc: &Spirv, struct_id: u32, members: &[u32]) -> (TokenStream, O
|
||||
}
|
||||
|
||||
// Try determine the total size of the struct in order to add padding at the end of the struct.
|
||||
let spirv_req_total_size = doc.instructions
|
||||
.iter()
|
||||
.filter_map(|i| match *i {
|
||||
Instruction::Decorate {
|
||||
target_id,
|
||||
decoration: Decoration::DecorationArrayStride,
|
||||
ref params,
|
||||
} => {
|
||||
for inst in doc.instructions.iter() {
|
||||
match *inst {
|
||||
Instruction::TypeArray {
|
||||
result_id, type_id, ..
|
||||
} if result_id == target_id && type_id == struct_id => {
|
||||
return Some(params[0]);
|
||||
},
|
||||
Instruction::TypeRuntimeArray { result_id, type_id }
|
||||
if result_id == target_id && type_id == struct_id => {
|
||||
return Some(params[0]);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.fold(None, |a, b| if let Some(a) = a {
|
||||
assert_eq!(a, b);
|
||||
Some(a)
|
||||
} else {
|
||||
Some(b)
|
||||
});
|
||||
let mut spirv_req_total_size = None;
|
||||
for inst in doc.instructions.iter() {
|
||||
match *inst {
|
||||
Instruction::TypeArray { result_id, type_id, .. } if type_id == struct_id => {
|
||||
if let Some(params) = doc.get_decoration_params(result_id, Decoration::DecorationArrayStride) {
|
||||
spirv_req_total_size = Some(params[0]);
|
||||
}
|
||||
}
|
||||
Instruction::TypeRuntimeArray { result_id, type_id } if type_id == struct_id => {
|
||||
if let Some(params) = doc.get_decoration_params(result_id, Decoration::DecorationArrayStride) {
|
||||
spirv_req_total_size = Some(params[0]);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
// Adding the final padding members.
|
||||
if let (Some(cur_size), Some(req_size)) = (current_rust_offset, spirv_req_total_size) {
|
||||
@ -218,19 +185,6 @@ fn write_struct(doc: &Spirv, struct_id: u32, members: &[u32]) -> (TokenStream, O
|
||||
(ast, spirv_req_total_size.map(|sz| sz as usize).or(current_rust_offset))
|
||||
}
|
||||
|
||||
/// Returns true if a `BuiltIn` decorator is applied on a struct member.
|
||||
fn is_builtin_member(doc: &Spirv, id: u32, member_id: u32) -> bool {
|
||||
for instruction in &doc.instructions {
|
||||
match *instruction {
|
||||
Instruction::MemberDecorate { target_id, member, decoration: Decoration::DecorationBuiltIn, .. }
|
||||
if target_id == id && member == member_id => { return true }
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns the type name to put in the Rust struct, and its size and alignment.
|
||||
///
|
||||
/// The size can be `None` if it's only known at runtime.
|
||||
@ -381,15 +335,7 @@ pub fn type_from_id(doc: &Spirv, searched: u32) -> (TokenStream, Option<usize>,
|
||||
.next()
|
||||
.expect("failed to find array length");
|
||||
let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
|
||||
let stride = doc.instructions.iter().filter_map(|e| match e {
|
||||
Instruction::Decorate {
|
||||
target_id,
|
||||
decoration: Decoration::DecorationArrayStride,
|
||||
ref params,
|
||||
} if *target_id == searched => Some(params[0]),
|
||||
_ => None,
|
||||
})
|
||||
.next().expect("failed to find ArrayStride decoration");
|
||||
let stride = doc.get_decoration_params(searched, Decoration::DecorationArrayStride).unwrap()[0];
|
||||
if stride as usize > t_size {
|
||||
panic!("Not possible to generate a rust array with the correct alignment since the SPIR-V \
|
||||
ArrayStride is larger than the size of the array element in rust. Try wrapping \
|
||||
|
Loading…
Reference in New Issue
Block a user