diff --git a/vulkano-shaders/src/descriptor_sets.rs b/vulkano-shaders/src/descriptor_sets.rs index c180d457..c1671544 100644 --- a/vulkano-shaders/src/descriptor_sets.rs +++ b/vulkano-shaders/src/descriptor_sets.rs @@ -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() +} diff --git a/vulkano-shaders/src/parse.rs b/vulkano-shaders/src/parse.rs index 0e6b8ed1..ac10e655 100644 --- a/vulkano-shaders/src/parse.rs +++ b/vulkano-shaders/src/parse.rs @@ -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, arrayed: bool, ms: bool, sampled: Option, format: ImageFormat, access: Option }, + 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= 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] },