Fix and refine the generation of readonly descriptor attribute (#1534)

* Vulkano-shaders: Improve handling of readonly descriptors

* Changelog

* Fixed image readonly detection for real this time
This commit is contained in:
Rua 2021-04-05 12:53:18 +02:00 committed by GitHub
parent bba6a0e776
commit 1af922a607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 27 deletions

View File

@ -4,6 +4,7 @@
Breaking changes should be listed first, before other changes, and should be preceded by - **Breaking**. Breaking changes should be listed first, before other changes, and should be preceded by - **Breaking**.
--> -->
- The deprecated `cause` trait function on Vulkano error types is replaced with `source`. - The deprecated `cause` trait function on Vulkano error types is replaced with `source`.
- Vulkano-shaders: Fixed and refined the generation of the `readonly` descriptor attribute. It should now correctly mark uniforms and sampled images as read-only, but storage buffers and images only if explicitly marked as `readonly` in the shader.
# Version 0.22.0 (2021-03-31) # Version 0.22.0 (2021-03-31)

View File

@ -16,6 +16,7 @@ use crate::parse::{Instruction, Spirv};
use crate::{spirv_search, TypesMeta}; use crate::{spirv_search, TypesMeta};
use std::collections::HashSet; use std::collections::HashSet;
#[derive(Debug)]
struct Descriptor { struct Descriptor {
set: u32, set: u32,
binding: u32, binding: u32,
@ -177,6 +178,10 @@ fn find_descriptors(doc: &Spirv, entrypoint_id: u32, interface: &[u32]) -> Vec<D
.get_decoration_params(variable_id, Decoration::DecorationBinding) .get_decoration_params(variable_id, Decoration::DecorationBinding)
.unwrap()[0]; .unwrap()[0];
let nonwritable = doc
.get_decoration_params(variable_id, Decoration::DecorationNonWritable)
.is_some();
// Find information about the kind of binding for this descriptor. // Find information about the kind of binding for this descriptor.
let (desc_ty, readonly, array_count) = let (desc_ty, readonly, array_count) =
descriptor_infos(doc, pointed_ty, storage_class, false).expect(&format!( descriptor_infos(doc, pointed_ty, storage_class, false).expect(&format!(
@ -188,7 +193,7 @@ fn find_descriptors(doc: &Spirv, entrypoint_id: u32, interface: &[u32]) -> Vec<D
set, set,
binding, binding,
array_count, array_count,
readonly, readonly: nonwritable || readonly,
}); });
} }
@ -389,26 +394,23 @@ fn descriptor_infos(
decoration_block ^ decoration_buffer_block, decoration_block ^ decoration_buffer_block,
"Structs in shader interface are expected to be decorated with one of Block or BufferBlock" "Structs in shader interface are expected to be decorated with one of Block or BufferBlock"
); );
let is_ssbo = pointer_storage == StorageClass::StorageClassStorageBuffer;
// Determine whether there's a NonWritable decoration. // false -> VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
let readonly = { // true -> VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
let mut readonly = vec![false; member_types.len()]; let storage = pointer_storage == StorageClass::StorageClassStorageBuffer;
for i in doc.instructions.iter() {
if let Instruction::MemberDecorate { target_id, member, decoration, .. } = i { // Determine whether all members have a NonWritable decoration.
if *target_id == *result_id && *decoration == Decoration::DecorationNonWritable { let nonwritable = (0..member_types.len() as u32).all(|i| {
assert!(!readonly[*member as usize]); doc.get_member_decoration_params(pointed_ty, i, Decoration::DecorationNonWritable).is_some()
readonly[*member as usize] = true; });
}
} // Uniforms are never writable.
} let readonly = !storage || nonwritable;
readonly.iter().all(|x| *x)
};
let desc = quote! { let desc = quote! {
DescriptorDescTy::Buffer(DescriptorBufferDesc { DescriptorDescTy::Buffer(DescriptorBufferDesc {
dynamic: None, dynamic: None,
storage: #is_ssbo, storage: #storage,
}) })
}; };
@ -435,7 +437,7 @@ fn descriptor_infos(
match dim { match dim {
Dim::DimSubpassData => { Dim::DimSubpassData => {
// We are an input attachment. // VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
assert!( assert!(
!force_combined_image_sampled, !force_combined_image_sampled,
"An OpTypeSampledImage can't point to \ "An OpTypeSampledImage can't point to \
@ -459,25 +461,32 @@ fn descriptor_infos(
} }
}; };
Some((desc, true, 1)) Some((desc, true, 1)) // Never writable.
} }
Dim::DimBuffer => { Dim::DimBuffer => {
// We are a texel buffer. // false -> VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
let not_sampled = !sampled; // true -> VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
let storage = !sampled;
let desc = quote! { let desc = quote! {
DescriptorDescTy::TexelBuffer { DescriptorDescTy::TexelBuffer {
storage: #not_sampled, storage: #storage,
format: None, // TODO: specify format if known format: None, // TODO: specify format if known
} }
}; };
Some((desc, true, 1)) Some((desc, !storage, 1)) // Uniforms are never writable.
} }
_ => { _ => {
// We are a sampled or storage image. let (ty, readonly) = match force_combined_image_sampled {
let ty = match force_combined_image_sampled { // VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
true => quote! { DescriptorDescTy::CombinedImageSampler }, // Never writable.
false => quote! { DescriptorDescTy::Image }, true => (quote! { DescriptorDescTy::CombinedImageSampler }, true),
false => {
// false -> VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
// true -> VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
let storage = !sampled;
(quote! { DescriptorDescTy::Image }, !storage) // Sampled images are never writable.
},
}; };
let dim = match *dim { let dim = match *dim {
Dim::Dim1D => { Dim::Dim1D => {
@ -504,7 +513,7 @@ fn descriptor_infos(
}) })
}; };
Some((desc, true, 1)) Some((desc, readonly, 1))
} }
} }
} }