mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
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:
parent
dcf6c40ce7
commit
16171c51ac
@ -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};
|
||||
|
@ -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::{
|
||||
|
@ -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::{
|
||||
|
@ -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::{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
},
|
||||
),
|
||||
}
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -409,4 +409,4 @@ where
|
||||
fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
|
||||
(**self).current_layer_levels_access()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user