Improve shader analysis, add and refine DescriptorRequirements fields (#1786)

* Improve shader analysis, add and refine DescriptorRequirements fields

* Simplify a bit
This commit is contained in:
Rua 2022-01-11 03:06:22 +01:00 committed by GitHub
parent dcf6c40ce7
commit 16171c51ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 746 additions and 484 deletions

View File

@ -15,7 +15,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -12,7 +12,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{

View File

@ -13,7 +13,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{

View File

@ -13,7 +13,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{

View File

@ -17,7 +17,7 @@
use std::mem;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -75,7 +75,7 @@ fn main() {
layout(local_size_x = 12) in;
// Uniform Buffer Object
layout(set = 0, binding = 0) uniform readonly InData {
layout(set = 0, binding = 0) uniform InData {
uint data;
} ubo;

View File

@ -19,7 +19,7 @@ use std::io::BufWriter;
use std::path::Path;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;

View File

@ -21,7 +21,7 @@ use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;

View File

@ -14,7 +14,7 @@ use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::PrimaryCommandBuffer;
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageAccess;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};

View File

@ -12,7 +12,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;

View File

@ -11,7 +11,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -14,7 +14,7 @@ use std::time::Instant;
use vulkano::buffer::cpu_pool::CpuBufferPool;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;

View File

@ -12,8 +12,8 @@ use proc_macro2::TokenStream;
use vulkano::pipeline::layout::PipelineLayoutPcRange;
use vulkano::shader::spirv::ExecutionModel;
use vulkano::shader::{
DescriptorRequirements, GeometryShaderExecution, ShaderExecution, ShaderInterfaceEntry,
ShaderInterfaceEntryType, SpecializationConstantRequirements,
DescriptorIdentifier, DescriptorRequirements, GeometryShaderExecution, ShaderExecution,
ShaderInterfaceEntry, ShaderInterfaceEntryType, SpecializationConstantRequirements,
};
use vulkano::shader::{EntryPointInfo, ShaderInterface, ShaderStages};
@ -84,7 +84,10 @@ fn write_descriptor_requirements(
image_view_type,
multisampled,
mutable,
sampler_no_unnormalized,
sampler_with_images,
stages,
storage_image_atomic,
} = reqs;
let descriptor_types = descriptor_types.into_iter().map(|ty| {
@ -105,6 +108,33 @@ fn write_descriptor_requirements(
}
None => quote! { None },
};
let mutable = mutable.iter();
let sampler_no_unnormalized = sampler_no_unnormalized.iter();
let sampler_with_images = {
sampler_with_images.iter().map(|(&index, identifiers)| {
let identifiers = identifiers.iter().map(
|DescriptorIdentifier {
set,
binding,
index,
}| {
quote! {
vulkano::shader::DescriptorIdentifier {
set: #set,
binding: #binding,
index: #index,
}
}
},
);
quote! {
(
#index,
[#(#identifiers),*].into_iter().collect(),
)
}
})
};
let stages = {
let ShaderStages {
vertex,
@ -138,6 +168,7 @@ fn write_descriptor_requirements(
}
}
};
let storage_image_atomic = storage_image_atomic.iter();
quote! {
(
@ -148,8 +179,11 @@ fn write_descriptor_requirements(
format: #format,
image_view_type: #image_view_type,
multisampled: #multisampled,
mutable: #mutable,
mutable: [#(#mutable),*].into_iter().collect(),
sampler_no_unnormalized: [#(#sampler_no_unnormalized),*].into_iter().collect(),
sampler_with_images: [#(#sampler_with_images),*].into_iter().collect(),
stages: #stages,
storage_image_atomic: [#(#storage_image_atomic),*].into_iter().collect(),
},
),
}

View File

@ -2713,7 +2713,7 @@ impl SyncCommandBufferBuilder {
| DescriptorType::StorageBuffer
| DescriptorType::StorageBufferDynamic => AccessFlags {
shader_read: true,
shader_write: reqs.mutable,
shader_write: false,
..AccessFlags::none()
},
DescriptorType::InputAttachment => AccessFlags {
@ -2727,41 +2727,51 @@ impl SyncCommandBufferBuilder {
}
}
},
exclusive: reqs.mutable,
exclusive: false,
};
let buffer_resource = move |buffer: Arc<dyn BufferAccess>| {
(
KeyTy::Buffer(buffer),
format!("Buffer bound to set {} descriptor {}", set, binding).into(),
Some((
access,
ImageLayout::Undefined,
ImageLayout::Undefined,
ImageUninitializedSafe::Unsafe,
)),
)
};
let image_resource = move |image: Arc<dyn ImageAccess>| {
let layout = image
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view")
.layout_for(descriptor_type);
(
KeyTy::Image(image),
format!("Image bound to set {} descriptor {}", set, binding).into(),
if descriptor_type == DescriptorType::InputAttachment {
// FIXME: This is tricky. Since we read from the input attachment
// and this input attachment is being written in an earlier pass,
// vulkano will think that it needs to put a pipeline barrier and will
// return a `Conflict` error. For now as a work-around we simply ignore
// input attachments.
None
} else {
Some((access, layout, layout, ImageUninitializedSafe::Unsafe))
},
)
};
let access = (0..).map(|index| {
let mut access = access;
let mutable = reqs.mutable.contains(&index);
access.access.shader_write = mutable;
access.exclusive = mutable;
access
});
let buffer_resource =
move |(access, buffer): (PipelineMemoryAccess, Arc<dyn BufferAccess>)| {
(
KeyTy::Buffer(buffer),
format!("Buffer bound to set {} descriptor {}", set, binding).into(),
Some((
access,
ImageLayout::Undefined,
ImageLayout::Undefined,
ImageUninitializedSafe::Unsafe,
)),
)
};
let image_resource =
move |(access, image): (PipelineMemoryAccess, Arc<dyn ImageAccess>)| {
let layout = image
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view")
.layout_for(descriptor_type);
(
KeyTy::Image(image),
format!("Image bound to set {} descriptor {}", set, binding).into(),
if descriptor_type == DescriptorType::InputAttachment {
// FIXME: This is tricky. Since we read from the input attachment
// and this input attachment is being written in an earlier pass,
// vulkano will think that it needs to put a pipeline barrier and will
// return a `Conflict` error. For now as a work-around we simply ignore
// input attachments.
None
} else {
Some((access, layout, layout, ImageUninitializedSafe::Unsafe))
},
)
};
match state.descriptor_sets[&set]
.resources()
@ -2770,32 +2780,48 @@ impl SyncCommandBufferBuilder {
{
DescriptorBindingResources::None(_) => continue,
DescriptorBindingResources::Buffer(elements) => {
resources.extend(elements.iter().flatten().cloned().map(buffer_resource));
resources.extend(
access
.zip(elements)
.filter_map(|(access, element)| {
element.as_ref().map(|buffer| (access, buffer.clone()))
})
.map(buffer_resource),
);
}
DescriptorBindingResources::BufferView(elements) => {
resources.extend(
elements
.iter()
.flatten()
.map(|buffer_view| buffer_view.buffer())
access
.zip(elements)
.filter_map(|(access, element)| {
element
.as_ref()
.map(|buffer_view| (access, buffer_view.buffer()))
})
.map(buffer_resource),
);
}
DescriptorBindingResources::ImageView(elements) => {
resources.extend(
elements
.iter()
.flatten()
.map(|image_view| image_view.image())
access
.zip(elements)
.filter_map(|(access, element)| {
element
.as_ref()
.map(|image_view| (access, image_view.image()))
})
.map(image_resource),
);
}
DescriptorBindingResources::ImageViewSampler(elements) => {
resources.extend(
elements
.iter()
.flatten()
.map(|(image_view, _)| image_view.image())
access
.zip(elements)
.filter_map(|(access, element)| {
element
.as_ref()
.map(|(image_view, _)| (access, image_view.image()))
})
.map(image_resource),
);
}

View File

@ -315,7 +315,10 @@ impl DescriptorDesc {
image_view_type,
multisampled,
mutable,
sampler_no_unnormalized,
sampler_with_images,
stages,
storage_image_atomic,
} = descriptor_requirements;
if !descriptor_types.contains(&self.ty) {

View File

@ -409,4 +409,4 @@ where
fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
(**self).current_layer_levels_access()
}
}
}

View File

@ -30,7 +30,7 @@ use crate::DeviceSize;
use crate::OomError;
use crate::Version;
use crate::VulkanObject;
use fnv::FnvHashMap;
use fnv::{FnvHashMap, FnvHashSet};
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::error;
@ -549,12 +549,30 @@ pub struct DescriptorRequirements {
/// Whether image views bound to this descriptor must have multisampling enabled or disabled.
pub multisampled: bool,
/// Whether the shader requires mutable (exclusive) access to the resource bound to this
/// descriptor.
pub mutable: bool,
/// The descriptor indices that require mutable (exclusive) access to the bound resource.
pub mutable: FnvHashSet<u32>,
/// For sampler bindings, the descriptor indices that perform sampling operations that are not
/// permitted with unnormalized coordinates. This includes sampling with `ImplicitLod`,
/// `Dref` or `Proj` SPIR-V instructions or with an LOD bias or offset.
pub sampler_no_unnormalized: FnvHashSet<u32>,
/// For sampler bindings, the sampled image descriptors that are used in combination with each
/// sampler descriptor index.
pub sampler_with_images: FnvHashMap<u32, FnvHashSet<DescriptorIdentifier>>,
/// The shader stages that the descriptor must be declared for.
pub stages: ShaderStages,
/// For storage image bindings, the descriptor indices that atomic operations are used with.
pub storage_image_atomic: FnvHashSet<u32>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DescriptorIdentifier {
pub set: u32,
pub binding: u32,
pub index: u32,
}
impl DescriptorRequirements {
@ -588,14 +606,27 @@ impl DescriptorRequirements {
return Err(DescriptorRequirementsIncompatible::Multisampled);
}
let sampler_with_images = {
let mut result = self.sampler_with_images.clone();
for (&index, other_identifiers) in &other.sampler_with_images {
result.entry(index).or_default().extend(other_identifiers);
}
result
};
Ok(Self {
descriptor_types,
descriptor_count: self.descriptor_count.max(other.descriptor_count),
format: self.format.or(other.format),
image_view_type: self.image_view_type.or(other.image_view_type),
multisampled: self.multisampled,
mutable: self.mutable || other.mutable,
mutable: &self.mutable | &other.mutable,
sampler_no_unnormalized: &self.sampler_no_unnormalized | &other.sampler_no_unnormalized,
sampler_with_images,
stages: self.stages | other.stages,
storage_image_atomic: &self.storage_image_atomic | &other.storage_image_atomic,
})
}
}

File diff suppressed because it is too large Load Diff