mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Handle struct members alignments in generated code
This commit is contained in:
parent
85ded76ead
commit
e53a7e7bcc
@ -486,6 +486,7 @@ unsafe impl ::vulkano::descriptor_set::PipelineLayoutDesc for Layout {{
|
||||
output
|
||||
}
|
||||
|
||||
// TODO: struct definitions don't use this function, so irrelevant elements should be removed
|
||||
fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
|
||||
for instruction in doc.instructions.iter() {
|
||||
match instruction {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::mem;
|
||||
|
||||
use parse;
|
||||
use enums;
|
||||
|
||||
@ -24,16 +26,21 @@ fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
|
||||
|
||||
let mut members_defs = Vec::with_capacity(members.len());
|
||||
|
||||
// Contains the offset of the next field.
|
||||
// Equals to `None` if there's a runtime-sized field in there.
|
||||
let mut current_rust_offset = Some(0);
|
||||
|
||||
for (num, &member) in members.iter().enumerate() {
|
||||
let ty = ::type_from_id(doc, member);
|
||||
let (ty, rust_size, rust_align) = type_from_id(doc, member);
|
||||
let member_name = ::member_name_from_id(doc, struct_id, num as u32);
|
||||
|
||||
// Ignore the field if it is built in, which includes `gl_Position` for example.
|
||||
// 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) {
|
||||
continue;
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let offset = doc.instructions.iter().filter_map(|i| {
|
||||
let spirv_offset = doc.instructions.iter().filter_map(|i| {
|
||||
match *i {
|
||||
parse::Instruction::MemberDecorate { target_id, member,
|
||||
decoration: enums::Decoration::DecorationOffset,
|
||||
@ -47,20 +54,39 @@ fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
|
||||
|
||||
None
|
||||
}).next().expect(&format!("Struct member `{}` of `{}` is missing an `Offset` decoration",
|
||||
member_name, name));
|
||||
member_name, name)) as usize;
|
||||
|
||||
members_defs.push(format!("{name}: {ty} /* {off} */", name = member_name, ty = ty, off = offset));
|
||||
// We need to add a dummy field if necessary.
|
||||
{
|
||||
let current_rust_offset = current_rust_offset.as_mut().expect("Found runtime-sized member in non-final position");
|
||||
|
||||
// Updating current_rust_offset to take the alignment of the next field into account
|
||||
*current_rust_offset = if *current_rust_offset == 0 {
|
||||
0
|
||||
} else {
|
||||
(1 + (*current_rust_offset - 1) / rust_align) * rust_align
|
||||
};
|
||||
|
||||
if spirv_offset != *current_rust_offset {
|
||||
let diff = spirv_offset.checked_sub(*current_rust_offset).unwrap();
|
||||
members_defs.push(format!("_dummy: [u8; {}]", diff)); // FIXME: fix name if there are multiple dummies
|
||||
*current_rust_offset += diff;
|
||||
}
|
||||
}
|
||||
|
||||
// Updating `current_rust_offset`.
|
||||
if let Some(s) = rust_size {
|
||||
*current_rust_offset.as_mut().unwrap() += s;
|
||||
} else {
|
||||
current_rust_offset = None;
|
||||
}
|
||||
|
||||
members_defs.push(format!("{name}: {ty}", name = member_name, ty = ty));
|
||||
}
|
||||
|
||||
// GLSL doesn't allow empty structures. However it is possible to have structures entirely
|
||||
// made of built-in members, hence this check.
|
||||
if !members_defs.is_empty() {
|
||||
format!("#[repr(C)]\n#[derive(Copy, Clone, Debug, Default)]\n\
|
||||
pub struct {name} {{\n\t{members}\n}}\n",
|
||||
name = name, members = members_defs.join(",\n\t"))
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
format!("#[repr(C)]\n#[derive(Copy, Clone, Debug, Default)]\n\
|
||||
pub struct {name} {{\n\t{members}\n}}\n",
|
||||
name = name, members = members_defs.join(",\n\t"))
|
||||
}
|
||||
|
||||
/// Returns true if a `BuiltIn` decorator is applied on a struct member.
|
||||
@ -81,3 +107,58 @@ fn is_builtin_member(doc: &parse::Spirv, id: u32, member_id: u32) -> bool {
|
||||
|
||||
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.
|
||||
fn type_from_id(doc: &parse::Spirv, searched: u32) -> (String, Option<usize>, usize) {
|
||||
for instruction in doc.instructions.iter() {
|
||||
match instruction {
|
||||
&parse::Instruction::TypeBool { result_id } if result_id == searched => {
|
||||
return ("bool".to_owned(), Some(mem::size_of::<bool>()), mem::align_of::<bool>())
|
||||
},
|
||||
&parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
|
||||
// FIXME: width
|
||||
return ("i32".to_owned(), Some(mem::size_of::<i32>()), mem::align_of::<i32>())
|
||||
},
|
||||
&parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
|
||||
// FIXME: width
|
||||
return ("f32".to_owned(), Some(mem::size_of::<f32>()), mem::align_of::<f32>())
|
||||
},
|
||||
&parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
|
||||
debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
|
||||
let (t, t_size, t_align) = type_from_id(doc, component_id);
|
||||
return (format!("[{}; {}]", t, count), t_size.map(|s| s * count as usize), t_align);
|
||||
},
|
||||
&parse::Instruction::TypeMatrix { result_id, column_type_id, column_count } if result_id == searched => {
|
||||
// FIXME: row-major or column-major
|
||||
debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
|
||||
let (t, t_size, t_align) = type_from_id(doc, column_type_id);
|
||||
return (format!("[{}; {}]", t, column_count), t_size.map(|s| s * column_count as usize), t_align);
|
||||
},
|
||||
&parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
|
||||
debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
|
||||
let (t, t_size, t_align) = type_from_id(doc, type_id);
|
||||
let len = doc.instructions.iter().filter_map(|e| {
|
||||
match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
|
||||
}).next().expect("failed to find array length");
|
||||
let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
|
||||
return (format!("[{}; {}]", t, len), t_size.map(|s| s * len as usize), t_align); // FIXME:
|
||||
},
|
||||
&parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
|
||||
debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
|
||||
let (t, _, t_align) = type_from_id(doc, type_id);
|
||||
return (format!("[{}]", t), None, t_align);
|
||||
},
|
||||
&parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
|
||||
let name = ::name_from_id(doc, result_id);
|
||||
let size = member_types.iter().filter_map(|&t| type_from_id(doc, t).1).fold(0, |a,b|a+b);
|
||||
let align = member_types.iter().map(|&t| type_from_id(doc, t).2).max().unwrap_or(1);
|
||||
return (name, Some(size), align);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
panic!("Type #{} not found", searched)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user