Properly generate infos about descriptors in vulkano-shaders

This commit is contained in:
Pierre Krieger 2016-05-12 13:39:31 +02:00
parent 3b04d46dbb
commit c95d456926
2 changed files with 125 additions and 63 deletions

View File

@ -50,69 +50,7 @@ pub fn write_descriptor_sets(doc: &parse::Spirv) -> String {
}).next().expect(&format!("Uniform `{}` is missing a binding", name));
// Find informations about the kind of binding for this descriptor.
let (desc_ty, readonly) = doc.instructions.iter().filter_map(|i| {
match i {
&parse::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 {
&parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationBufferBlock, .. } if target_id == pointed_ty => {
Some(true)
},
&parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationBlock, .. } if target_id == pointed_ty => {
Some(false)
},
_ => None,
}
}).next().expect("Found a buffer uniform with neither the Block nor BufferBlock decorations");
// Determine whether there's a NonWritable decoration.
let non_writable = false; // TODO: tricky because the decoration is on struct members
Some((format!("DescriptorDescTy::Buffer(DescriptorBufferDesc {{
dynamic: Some(false),
storage: {}
}})", if is_ssbo { "true" } else { "false "}), true))
},
&parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
sampled, ref format, ref access, .. }
if result_id == pointed_ty && sampled == Some(true) =>
{
// FIXME: wrong
let desc = format!("DescriptorDescTy::Image(DescriptorImageDesc {{
sampled: true,
dimensions: DescriptorImageDescDimensions::TwoDimensional,
format: None,
multisampled: false,
array_layers: DescriptorImageDescArray::NonArrayed,
}})");
Some((desc, true))
},
&parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
sampled, ref format, ref access, .. }
if result_id == pointed_ty && sampled == Some(false) =>
{
// FIXME: everything wrong here
Some(("DescriptorDescTy::InputAttachment { multisampled: false, array_layers: DescriptorImageDescArray::NonArrayed }".to_owned(), true))
},
&parse::Instruction::TypeSampledImage { result_id, image_type_id }
if result_id == pointed_ty =>
{
// FIXME: wrong
let desc = format!("DescriptorDescTy::CombinedImageSampler(DescriptorImageDesc {{
sampled: true,
dimensions: DescriptorImageDescDimensions::TwoDimensional,
format: None,
multisampled: false,
array_layers: DescriptorImageDescArray::NonArrayed,
}})");
Some((desc, true))
},
_ => None, // TODO: other types
}
}).next().expect(&format!("Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)", name, pointed_ty));
let (desc_ty, readonly) = descriptor_infos(doc, pointed_ty, false).expect(&format!("Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)", name, pointed_ty));
descriptors.push(Descriptor {
name: name,
@ -199,3 +137,125 @@ fn pointer_variable_ty(doc: &parse::Spirv, variable: u32) -> u32 {
}
}).next().unwrap()
}
/// Returns a `DescriptorDescTy` constructor and a bool indicating whether the descriptor is
/// read-only.
///
/// See also section 14.5.2 of the Vulkan specs: Descriptor Set Interface
fn descriptor_infos(doc: &parse::Spirv, pointed_ty: u32, force_combined_image_sampled: bool)
-> Option<(String, bool)>
{
doc.instructions.iter().filter_map(|i| {
match i {
&parse::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 {
&parse::Instruction::Decorate
{ target_id, decoration: enums::Decoration::DecorationBufferBlock, .. }
if target_id == pointed_ty =>
{
Some(true)
},
&parse::Instruction::Decorate
{ target_id, decoration: enums::Decoration::DecorationBlock, .. }
if target_id == pointed_ty =>
{
Some(false)
},
_ => None,
}
}).next().expect("Found a buffer uniform with neither the Block nor BufferBlock \
decorations");
// Determine whether there's a NonWritable decoration.
let non_writable = false; // TODO: tricky because the decoration is on struct members
let desc = format!("DescriptorDescTy::Buffer(DescriptorBufferDesc {{
dynamic: Some(false),
storage: {}
}})", if is_ssbo { "true" } else { "false "});
Some((desc, true))
},
&parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
sampled, ref format, ref access, .. }
if result_id == pointed_ty =>
{
let sampled = sampled.expect("Vulkan requires that variables of type OpTypeImage \
have a Sampled operand of 1 or 2");
let ms = if ms { "true" } else { "false" };
let arrayed = if arrayed {
"DescriptorImageDescArray::Arrayed { max_layers: None }"
} else {
"DescriptorImageDescArray::NonArrayed"
};
if let &enums::Dim::DimSubpassData = dim {
// We are an input attachment.
assert!(!force_combined_image_sampled, "An OpTypeSampledImage can't point to \
an OpTypeImage whose dimension is \
SubpassData");
assert!(if let &enums::ImageFormat::ImageFormatUnknown = format { true }
else { false }, "If Dim is SubpassData, Image Format must be Unknown");
assert!(!sampled, "If Dim is SubpassData, Sampled must be 2");
let desc = format!("DescriptorDescTy::InputAttachment {{
multisampled: {},
array_layers: {}
}}", ms, arrayed);
Some((desc, true))
} else if let &enums::Dim::DimBuffer = dim {
// We are a texel buffer.
let desc = format!("DescriptorDescTy::TexelBuffer {{
sampled: {},
format: None, // TODO: specify format if known
}}", sampled);
Some((desc, true))
} else {
// We are a sampled or storage image.
let sampled = if sampled { "true" } else { "false" };
let ty = if force_combined_image_sampled { "CombinedImageSampler" }
else { "Image" };
let dim = match *dim {
enums::Dim::Dim1D => "DescriptorImageDescDimensions::OneDimensional",
enums::Dim::Dim2D => "DescriptorImageDescDimensions::TwoDimensional",
enums::Dim::Dim3D => "DescriptorImageDescDimensions::ThreeDimensional",
enums::Dim::DimCube => "DescriptorImageDescDimensions::Cube",
enums::Dim::DimRect => panic!("Vulkan doesn't support rectangle textures"),
_ => unreachable!()
};
let desc = format!("DescriptorDescTy::{}(DescriptorImageDesc {{
sampled: {},
dimensions: {},
format: None, // TODO: specify format if known
multisampled: {},
array_layers: {},
}})", ty, sampled, dim, ms, arrayed);
Some((desc, true))
}
},
&parse::Instruction::TypeSampledImage { result_id, image_type_id }
if result_id == pointed_ty =>
{
descriptor_infos(doc, image_type_id, true)
},
&parse::Instruction::TypeSampler { result_id } if result_id == pointed_ty => {
let desc = format!("DescriptorDescTy::Sampler");
Some((desc, true))
},
_ => None, // TODO: other types
}
}).next()
}

View File

@ -101,6 +101,7 @@ pub enum Instruction {
TypeVector { result_id: u32, component_id: u32, count: u32 },
TypeMatrix { result_id: u32, column_type_id: u32, column_count: u32 },
TypeImage { result_id: u32, sampled_type_id: u32, dim: Dim, depth: Option<bool>, arrayed: bool, ms: bool, sampled: Option<bool>, format: ImageFormat, access: Option<AccessQualifier> },
TypeSampler { result_id: u32 },
TypeSampledImage { result_id: u32, image_type_id: u32 },
TypeArray { result_id: u32, type_id: u32, length_id: u32 },
TypeRuntimeArray { result_id: u32, type_id: u32 },
@ -170,6 +171,7 @@ fn decode_instruction(opcode: u16, operands: &[u32]) -> Result<Instruction, Pars
format: try!(ImageFormat::from_num(operands[7])),
access: if operands.len() >= 9 { Some(try!(AccessQualifier::from_num(operands[8]))) } else { None },
},
26 => Instruction::TypeSampler { result_id: operands[0] },
27 => Instruction::TypeSampledImage { result_id: operands[0], image_type_id: operands[1] },
28 => Instruction::TypeArray { result_id: operands[0], type_id: operands[1], length_id: operands[2] },
29 => Instruction::TypeRuntimeArray { result_id: operands[0], type_id: operands[1] },