diff --git a/vulkano/src/descriptor_set/layout.rs b/vulkano/src/descriptor_set/layout.rs index 41c4e438ef..95dcae42aa 100644 --- a/vulkano/src/descriptor_set/layout.rs +++ b/vulkano/src/descriptor_set/layout.rs @@ -339,6 +339,8 @@ impl DescriptorSetLayoutCreateInfo { let mut total_descriptor_count = 0; let highest_binding_num = bindings.keys().copied().next_back(); + let mut update_after_bind_binding = None; + let mut buffer_dynamic_binding = None; for (&binding_num, binding) in bindings.iter() { binding @@ -381,11 +383,17 @@ impl DescriptorSetLayoutCreateInfo { })); } - if binding_flags.intersects(DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT) { + if binding_flags.intersects( + DescriptorBindingFlags::UPDATE_AFTER_BIND + | DescriptorBindingFlags::UPDATE_UNUSED_WHILE_PENDING + | DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT, + ) { return Err(Box::new(ValidationError { problem: format!( "`flags` contains `DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR`, \ - and `bindings[{}].flags` contains \ + and `bindings[{}].binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, \ + `DescriptorBindingFlags::UPDATE_UNUSED_WHILE_PENDING` or \ `DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT`", binding_num ) @@ -401,7 +409,7 @@ impl DescriptorSetLayoutCreateInfo { { return Err(Box::new(ValidationError { problem: format!( - "`bindings[{}].flags` contains \ + "`bindings[{}].binding_flags` contains \ `DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT`, but {0} is not the highest binding number in `bindings`", binding_num @@ -413,6 +421,32 @@ impl DescriptorSetLayoutCreateInfo { ..Default::default() })); } + + if binding_flags.intersects(DescriptorBindingFlags::UPDATE_AFTER_BIND) { + if !flags.intersects(DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL) { + return Err(Box::new(ValidationError { + problem: format!( + "`bindings[{}].binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, but \ + `flags` does not contain \ + `DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL`", + binding_num + ) + .into(), + vuids: &["VUID-VkDescriptorSetLayoutCreateInfo-flags-03000"], + ..Default::default() + })); + } + + update_after_bind_binding.get_or_insert(binding_num); + } + + if matches!( + descriptor_type, + DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic + ) { + buffer_dynamic_binding.get_or_insert(binding_num); + } } let max_push_descriptors = device @@ -434,6 +468,24 @@ impl DescriptorSetLayoutCreateInfo { })); } + if let (Some(update_after_bind_binding), Some(buffer_dynamic_binding)) = + (update_after_bind_binding, buffer_dynamic_binding) + { + return Err(Box::new(ValidationError { + problem: format!( + "`bindings[{}].binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `bindings[{}].descriptor_type` is \ + `DescriptorType::UniformBufferDynamic` or \ + `DescriptorType::StorageBufferDynamic`", + update_after_bind_binding, buffer_dynamic_binding + ) + .into(), + vuids: &["VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001"], + ..Default::default() + })); + } + Ok(()) } } @@ -455,13 +507,21 @@ vulkan_bitflags! { /// Flags that control how a descriptor set layout is created. DescriptorSetLayoutCreateFlags = DescriptorSetLayoutCreateFlags(u32); - /* TODO: enable - // TODO: document + /// Whether descriptor sets using this descriptor set layout must be allocated from a + /// descriptor pool whose flags contain [`DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`]. + /// Descriptor set layouts with this flag use alternative (typically higher) device limits on + /// per-stage and total descriptor counts, which have `_update_after_bind_` in their names. + /// + /// This flag must be specified whenever the layout contains one or more bindings that have + /// the [`DescriptorBindingFlags::UPDATE_AFTER_BIND`] flag, but can be specified also if none + /// of the bindings have this flag, purely to use the alternative device limits. + /// + /// [`DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`]: crate::descriptor_set::pool::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND UPDATE_AFTER_BIND_POOL = UPDATE_AFTER_BIND_POOL RequiresOneOf([ RequiresAllOf([APIVersion(V1_2)]), RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), - ]), */ + ]), /// Whether the descriptor set layout should be created for push descriptors. /// @@ -506,6 +566,8 @@ vulkan_bitflags! { #[derive(Clone, Debug, PartialEq, Eq)] pub struct DescriptorSetLayoutBinding { /// Specifies how to create the binding. + /// + /// The default value is empty. pub binding_flags: DescriptorBindingFlags, /// The content and layout of each array element of a binding. @@ -733,6 +795,193 @@ impl DescriptorSetLayoutBinding { } } + if binding_flags.intersects(DescriptorBindingFlags::UPDATE_AFTER_BIND) { + match descriptor_type { + DescriptorType::UniformBuffer => { + if !device + .enabled_features() + .descriptor_binding_uniform_buffer_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::UniformBuffer`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_uniform_buffer_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUniformBufferUpdateAfterBind-03005"], + ..Default::default() + })); + } + } + DescriptorType::Sampler + | DescriptorType::CombinedImageSampler + | DescriptorType::SampledImage => { + if !device + .enabled_features() + .descriptor_binding_sampled_image_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::Sampler`, \ + `DescriptorType::CombinedImageSampler` or \ + `DescriptorType::SampledImage`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_sampled_image_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingSampledImageUpdateAfterBind-03006"], + ..Default::default() + })); + } + } + DescriptorType::StorageImage => { + if !device + .enabled_features() + .descriptor_binding_storage_image_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::StorageImage`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_storage_image_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingStorageImageUpdateAfterBind-03007"], + ..Default::default() + })); + } + } + DescriptorType::StorageBuffer => { + if !device + .enabled_features() + .descriptor_binding_storage_buffer_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::StorageBuffer`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_storage_buffer_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingStorageBufferUpdateAfterBind-03008"], + ..Default::default() + })); + } + } + DescriptorType::UniformTexelBuffer => { + if !device + .enabled_features() + .descriptor_binding_uniform_texel_buffer_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::UniformTexelBuffer`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_uniform_texel_buffer_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUniformTexelBufferUpdateAfterBind-03009"], + ..Default::default() + })); + } + } + DescriptorType::StorageTexelBuffer => { + if !device + .enabled_features() + .descriptor_binding_storage_texel_buffer_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::StorageTexelBuffer`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_storage_texel_buffer_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingStorageTexelBufferUpdateAfterBind-03010"], + ..Default::default() + })); + } + } + DescriptorType::InlineUniformBlock => { + if !device + .enabled_features() + .descriptor_binding_inline_uniform_block_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::InlineUniformBlock`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_inline_uniform_block_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingInlineUniformBlockUpdateAfterBind-02211"], + ..Default::default() + })); + } + } + DescriptorType::AccelerationStructure => { + if !device + .enabled_features() + .descriptor_binding_acceleration_structure_update_after_bind + { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::AccelerationStructure`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_acceleration_structure_update_after_bind" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingAccelerationStructureUpdateAfterBind-03570"], + ..Default::default() + })); + } + } + DescriptorType::InputAttachment + | DescriptorType::UniformBufferDynamic + | DescriptorType::StorageBufferDynamic => { + return Err(Box::new(ValidationError { + problem: "`binding_flags` contains \ + `DescriptorBindingFlags::UPDATE_AFTER_BIND`, and \ + `descriptor_type` is `DescriptorType::InputAttachment`, \ + `DescriptorType::UniformBufferDynamic` or \ + `DescriptorType::StorageBufferDynamic`" + .into(), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-None-03011"], + ..Default::default() + })); + } + } + } + + if binding_flags.intersects(DescriptorBindingFlags::UPDATE_UNUSED_WHILE_PENDING) + && !device + .enabled_features() + .descriptor_binding_update_unused_while_pending + { + return Err(Box::new(ValidationError { + context: "binding_flags".into(), + problem: "contains `DescriptorBindingFlags::UPDATE_UNUSED_WHILE_PENDING`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_update_unused_while_pending" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUpdateUnusedWhilePending-03012"], + })); + } + + if binding_flags.intersects(DescriptorBindingFlags::PARTIALLY_BOUND) + && !device.enabled_features().descriptor_binding_partially_bound + { + return Err(Box::new(ValidationError { + context: "binding_flags".into(), + problem: "contains `DescriptorBindingFlags::PARTIALLY_BOUND`".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_partially_bound" + )])]), + vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingPartiallyBound-03013"], + })); + } + if binding_flags.intersects(DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT) { if !device .enabled_features() @@ -741,9 +990,9 @@ impl DescriptorSetLayoutBinding { return Err(Box::new(ValidationError { context: "binding_flags".into(), problem: "contains `DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT`".into(), - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::Feature("descriptor_binding_variable_descriptor_count")]) - ]), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature( + "descriptor_binding_variable_descriptor_count" + )])]), vuids: &["VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014"], })); } @@ -790,29 +1039,59 @@ vulkan_bitflags! { /// Flags that control how a binding in a descriptor set layout is created. DescriptorBindingFlags = DescriptorBindingFlags(u32); - /* TODO: enable - // TODO: document + /// Allows descriptors in this binding to be updated after a command buffer has already + /// recorded a bind command containing a descriptor set with this layout, as long as the + /// command buffer is not executing. Each descriptor can also be updated concurrently. + /// + /// If a binding has this flag, then the descriptor set layout must be created with the + /// [`DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL`] flag, and descriptor sets using + /// it must be allocated from a descriptor pool that has the + /// [`DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`] flag. + /// In addition, the `descriptor_binding_*_update_after_bind` feature corresponding to the + /// descriptor type of the binding must be enabled. + /// + /// [`DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`]: crate::descriptor_set::pool::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND UPDATE_AFTER_BIND = UPDATE_AFTER_BIND RequiresOneOf([ RequiresAllOf([APIVersion(V1_2)]), RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), - ]), */ + ]), - /* TODO: enable - // TODO: document + /// Allows descriptors in this binding to be updated after a command buffer has already + /// recorded a bind command containing a descriptor set with this layout, as long as the + /// command buffer is not executing, and no shader invocation recorded in the command buffer + /// *uses* the descriptor. Each descriptor can also be updated concurrently. + /// + /// This is a subset of what is allowed by [`DescriptorBindingFlags::UPDATE_AFTER_BIND`], but + /// has much less strict requirements. It does not require any additional flags to be present + /// on the descriptor set layout or the descriptor pool, and instead requires the + /// [`descriptor_binding_update_unused_while_pending`] feature. + /// + /// What counts as "used" depends on whether the [`DescriptorBindingFlags::PARTIALLY_BOUND`] + /// flag is also set. If it is set, then only *dynamic use* by a shader invocation counts as + /// being used, otherwise all *static use* by a shader invocation is considered used. + /// + /// [`descriptor_binding_update_unused_while_pending`]: crate::device::Features::descriptor_binding_update_unused_while_pending UPDATE_UNUSED_WHILE_PENDING = UPDATE_UNUSED_WHILE_PENDING RequiresOneOf([ RequiresAllOf([APIVersion(V1_2)]), RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), - ]), */ + ]), - /* TODO: enable - // TODO: document + /// Allows descriptors to be left empty or invalid even if they are *statically used* by a + /// shader invocation, as long as they are not *dynamically used* . Additionally, if + /// [`DescriptorBindingFlags::UPDATE_UNUSED_WHILE_PENDING`] is set, allows updating descriptors + /// if they are statically used by a command buffer they are recorded in, as long as are not + /// dynamically used. + /// + /// The [`descriptor_binding_partially_bound`] feature must be enabled on the device. + /// + /// [`descriptor_binding_partially_bound`]: crate::device::Features::descriptor_binding_partially_bound PARTIALLY_BOUND = PARTIALLY_BOUND RequiresOneOf([ RequiresAllOf([APIVersion(V1_2)]), RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), - ]), */ + ]), /// Whether the binding has a variable number of descriptors. /// diff --git a/vulkano/src/descriptor_set/mod.rs b/vulkano/src/descriptor_set/mod.rs index 4f13c17229..7f2b057890 100644 --- a/vulkano/src/descriptor_set/mod.rs +++ b/vulkano/src/descriptor_set/mod.rs @@ -87,7 +87,10 @@ pub use self::{ WriteDescriptorSetElements, }, }; -use self::{layout::DescriptorSetLayout, pool::DescriptorPoolAlloc}; +use self::{ + layout::DescriptorSetLayout, + pool::{DescriptorPool, DescriptorPoolAlloc}, +}; use crate::{ acceleration_structure::AccelerationStructure, buffer::view::BufferView, @@ -122,6 +125,9 @@ pub unsafe trait DescriptorSet: /// Returns the allocation of the descriptor set. fn alloc(&self) -> &DescriptorPoolAlloc; + /// Returns the descriptor pool that the descriptor set was allocated from. + fn pool(&self) -> &DescriptorPool; + /// Returns the layout of this descriptor set. #[inline] fn layout(&self) -> &Arc { diff --git a/vulkano/src/descriptor_set/persistent.rs b/vulkano/src/descriptor_set/persistent.rs index 23bd6b72dc..b4f30cd01e 100644 --- a/vulkano/src/descriptor_set/persistent.rs +++ b/vulkano/src/descriptor_set/persistent.rs @@ -21,7 +21,11 @@ //! # Examples //! TODO: -use super::{pool::DescriptorPoolAlloc, sys::UnsafeDescriptorSet, CopyDescriptorSet}; +use super::{ + pool::{DescriptorPool, DescriptorPoolAlloc}, + sys::UnsafeDescriptorSet, + CopyDescriptorSet, +}; use crate::{ descriptor_set::{ allocator::{DescriptorSetAlloc, DescriptorSetAllocator, StandardDescriptorSetAlloc}, @@ -126,6 +130,10 @@ where self.inner.alloc().inner() } + fn pool(&self) -> &DescriptorPool { + self.inner.alloc().pool() + } + fn resources(&self) -> &DescriptorSetResources { &self.resources } diff --git a/vulkano/src/descriptor_set/pool.rs b/vulkano/src/descriptor_set/pool.rs index 708d755418..f21b19ccc6 100644 --- a/vulkano/src/descriptor_set/pool.rs +++ b/vulkano/src/descriptor_set/pool.rs @@ -220,6 +220,33 @@ impl DescriptorPool { for (index, info) in allocate_infos.iter().enumerate() { info.validate(self.device()) .map_err(|err| err.add_context(format!("allocate_infos[{}]", index)))?; + + let &DescriptorSetAllocateInfo { + ref layout, + variable_descriptor_count: _, + _ne: _, + } = info; + + if layout + .flags() + .intersects(DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL) + && !self + .flags + .intersects(DescriptorPoolCreateFlags::UPDATE_AFTER_BIND) + { + return Err(Box::new(ValidationError { + problem: format!( + "`allocate_infos[{}].layout.flags()` contains \ + `DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL`, but \ + `self.flags` does not contain \ + `DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`", + index + ) + .into(), + vuids: &["VUID-VkDescriptorSetAllocateInfo-pSetLayouts-03044"], + ..Default::default() + })); + } } Ok(()) @@ -558,13 +585,18 @@ vulkan_bitflags! { /// destroy the whole pool at once. FREE_DESCRIPTOR_SET = FREE_DESCRIPTOR_SET, - /* TODO: enable - // TODO: document + /// The pool can allocate descriptor sets with a layout whose flags include + /// [`DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL`]. + /// + /// A pool created with this flag can still allocate descriptor sets without the flag. + /// However, descriptor copy operations are only allowed between pools of the same type; + /// it is not possible to copy between a descriptor set whose pool has `UPDATE_AFTER_BIND`, + /// and a descriptor set whose pool does not have this flag. UPDATE_AFTER_BIND = UPDATE_AFTER_BIND RequiresOneOf([ RequiresAllOf([APIVersion(V1_2)]), RequiresAllOf([DeviceExtension(ext_descriptor_indexing)]), - ]), */ + ]), /* TODO: enable // TODO: document diff --git a/vulkano/src/descriptor_set/sys.rs b/vulkano/src/descriptor_set/sys.rs index 16985f45a0..53d13f56b1 100644 --- a/vulkano/src/descriptor_set/sys.rs +++ b/vulkano/src/descriptor_set/sys.rs @@ -11,6 +11,7 @@ use super::{ allocator::{DescriptorSetAlloc, DescriptorSetAllocator, StandardDescriptorSetAlloc}, + pool::DescriptorPool, CopyDescriptorSet, }; use crate::{ @@ -60,6 +61,12 @@ where &self.alloc } + /// Returns the descriptor pool that the descriptor set was allocated from. + #[inline] + pub fn pool(&self) -> &DescriptorPool { + self.alloc.pool() + } + /// Returns the layout of this descriptor set. #[inline] pub fn layout(&self) -> &Arc { @@ -104,7 +111,7 @@ where } for (index, copy) in descriptor_copies.iter().enumerate() { - copy.validate(self.layout(), self.variable_descriptor_count()) + copy.validate(self) .map_err(|err| err.add_context(format!("descriptor_copies[{}]", index)))?; } diff --git a/vulkano/src/descriptor_set/update.rs b/vulkano/src/descriptor_set/update.rs index e6b9ebb883..b71ef4253e 100644 --- a/vulkano/src/descriptor_set/update.rs +++ b/vulkano/src/descriptor_set/update.rs @@ -8,13 +8,18 @@ // according to those terms. use super::{ + allocator::DescriptorSetAlloc, layout::{DescriptorSetLayout, DescriptorType}, + sys::UnsafeDescriptorSet, DescriptorSet, }; use crate::{ acceleration_structure::{AccelerationStructure, AccelerationStructureType}, buffer::{view::BufferView, BufferUsage, Subbuffer}, - descriptor_set::layout::{DescriptorBindingFlags, DescriptorSetLayoutCreateFlags}, + descriptor_set::{ + layout::{DescriptorBindingFlags, DescriptorSetLayoutCreateFlags}, + pool::DescriptorPoolCreateFlags, + }, device::DeviceOwned, image::{ sampler::Sampler, @@ -1629,11 +1634,13 @@ impl CopyDescriptorSet { } } - pub(crate) fn validate( + pub(crate) fn validate

( &self, - dst_set_layout: &DescriptorSetLayout, - dst_set_variable_descriptor_count: u32, - ) -> Result<(), Box> { + dst_set: &UnsafeDescriptorSet

, + ) -> Result<(), Box> + where + P: DescriptorSetAlloc, + { let &Self { ref src_set, src_binding, @@ -1645,7 +1652,73 @@ impl CopyDescriptorSet { } = self; // VUID-VkCopyDescriptorSet-commonparent - assert_eq!(src_set.device(), dst_set_layout.device()); + assert_eq!(src_set.device(), dst_set.device()); + + match ( + src_set + .layout() + .flags() + .intersects(DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL), + dst_set + .layout() + .flags() + .intersects(DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL), + ) { + (true, false) => { + return Err(Box::new(ValidationError { + problem: "`src_set.layout().flags()` contains \ + `DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL`, but \ + `dst_set.layout().flags()` does not also contain it" + .into(), + vuids: &["VUID-VkCopyDescriptorSet-srcSet-01918"], + ..Default::default() + })); + } + (false, true) => { + return Err(Box::new(ValidationError { + problem: "`src_set.layout().flags()` does not contain \ + `DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL`, but \ + `dst_set.layout().flags()` does contain it" + .into(), + vuids: &["VUID-VkCopyDescriptorSet-srcSet-04885"], + ..Default::default() + })); + } + _ => (), + } + + match ( + src_set + .pool() + .flags() + .intersects(DescriptorPoolCreateFlags::UPDATE_AFTER_BIND), + dst_set + .pool() + .flags() + .intersects(DescriptorPoolCreateFlags::UPDATE_AFTER_BIND), + ) { + (true, false) => { + return Err(Box::new(ValidationError { + problem: "`src_set.pool().flags()` contains \ + `DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`, but \ + `dst_set.pool().flags()` does not also contain it" + .into(), + vuids: &["VUID-VkCopyDescriptorSet-srcSet-01920"], + ..Default::default() + })); + } + (false, true) => { + return Err(Box::new(ValidationError { + problem: "`src_set.pool().flags()` does not contain \ + `DescriptorPoolCreateFlags::UPDATE_AFTER_BIND`, but \ + `dst_set.pool().flags()` does contain it" + .into(), + vuids: &["VUID-VkCopyDescriptorSet-srcSet-04887"], + ..Default::default() + })); + } + _ => (), + } let src_layout_binding = match src_set.layout().bindings().get(&src_binding) { Some(layout_binding) => layout_binding, @@ -1679,7 +1752,7 @@ impl CopyDescriptorSet { })); } - let dst_layout_binding = match dst_set_layout.bindings().get(&dst_binding) { + let dst_layout_binding = match dst_set.layout().bindings().get(&dst_binding) { Some(layout_binding) => layout_binding, None => { return Err(Box::new(ValidationError { @@ -1696,7 +1769,7 @@ impl CopyDescriptorSet { .binding_flags .intersects(DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT) { - dst_set_variable_descriptor_count + dst_set.variable_descriptor_count() } else { dst_layout_binding.descriptor_count }; diff --git a/vulkano/src/pipeline/layout.rs b/vulkano/src/pipeline/layout.rs index e7808e177e..e687d208ae 100644 --- a/vulkano/src/pipeline/layout.rs +++ b/vulkano/src/pipeline/layout.rs @@ -473,9 +473,12 @@ impl PipelineLayoutCreateInfo { struct DescriptorLimit { descriptor_types: &'static [DescriptorType], - get_limit: fn(&Properties) -> u32, - limit_name: &'static str, - vuids: &'static [&'static str], + get_limit_all: fn(&Properties) -> Option, + limit_name_all: &'static str, + vuids_all: &'static [&'static str], + get_limit_not_uab: fn(&Properties) -> u32, + limit_name_not_uab: &'static str, + vuids_not_uab: &'static [&'static str], } const PER_STAGE_DESCRIPTOR_LIMITS: [DescriptorLimit; 8] = [ @@ -484,27 +487,36 @@ impl PipelineLayoutCreateInfo { DescriptorType::Sampler, DescriptorType::CombinedImageSampler, ], - get_limit: |p| p.max_per_stage_descriptor_samplers, - limit_name: "max_per_stage_descriptor_samplers", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03016"], + get_limit_all: |p| p.max_per_stage_descriptor_update_after_bind_samplers, + limit_name_all: "max_per_stage_descriptor_update_after_bind_samplers", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03022"], + get_limit_not_uab: |p| p.max_per_stage_descriptor_samplers, + limit_name_not_uab: "max_per_stage_descriptor_samplers", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03016"], }, DescriptorLimit { descriptor_types: &[ DescriptorType::UniformBuffer, DescriptorType::UniformBufferDynamic, ], - get_limit: |p| p.max_per_stage_descriptor_uniform_buffers, - limit_name: "max_per_stage_descriptor_uniform_buffers", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03017"], + get_limit_all: |p| p.max_per_stage_descriptor_update_after_bind_uniform_buffers, + limit_name_all: "max_per_stage_descriptor_update_after_bind_uniform_buffers", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03023"], + get_limit_not_uab: |p| p.max_per_stage_descriptor_uniform_buffers, + limit_name_not_uab: "max_per_stage_descriptor_uniform_buffers", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03017"], }, DescriptorLimit { descriptor_types: &[ DescriptorType::StorageBuffer, DescriptorType::StorageBufferDynamic, ], - get_limit: |p| p.max_per_stage_descriptor_storage_buffers, - limit_name: "max_per_stage_descriptor_storage_buffers", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03018"], + get_limit_all: |p| p.max_per_stage_descriptor_update_after_bind_storage_buffers, + limit_name_all: "max_per_stage_descriptor_update_after_bind_storage_buffers", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03024"], + get_limit_not_uab: |p| p.max_per_stage_descriptor_storage_buffers, + limit_name_not_uab: "max_per_stage_descriptor_storage_buffers", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03018"], }, DescriptorLimit { descriptor_types: &[ @@ -512,42 +524,62 @@ impl PipelineLayoutCreateInfo { DescriptorType::SampledImage, DescriptorType::UniformTexelBuffer, ], - get_limit: |p| p.max_per_stage_descriptor_sampled_images, - limit_name: "max_per_stage_descriptor_sampled_images", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-06939"], + get_limit_all: |p| p.max_per_stage_descriptor_update_after_bind_sampled_images, + limit_name_all: "max_per_stage_descriptor_update_after_bind_sampled_images", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03025"], + get_limit_not_uab: |p| p.max_per_stage_descriptor_sampled_images, + limit_name_not_uab: "max_per_stage_descriptor_sampled_images", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-06939"], }, DescriptorLimit { descriptor_types: &[ DescriptorType::StorageImage, DescriptorType::StorageTexelBuffer, ], - get_limit: |p| p.max_per_stage_descriptor_storage_images, - limit_name: "max_per_stage_descriptor_storage_images", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03020"], + get_limit_all: |p| p.max_per_stage_descriptor_update_after_bind_storage_images, + limit_name_all: "max_per_stage_descriptor_update_after_bind_storage_images", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03026"], + get_limit_not_uab: |p| p.max_per_stage_descriptor_storage_images, + limit_name_not_uab: "max_per_stage_descriptor_storage_images", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03020"], }, DescriptorLimit { descriptor_types: &[DescriptorType::InputAttachment], - get_limit: |p| p.max_per_stage_descriptor_input_attachments, - limit_name: "max_per_stage_descriptor_input_attachments", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03021"], + get_limit_all: |p| p.max_per_stage_descriptor_update_after_bind_input_attachments, + limit_name_all: "max_per_stage_descriptor_update_after_bind_input_attachments", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03027"], + get_limit_not_uab: |p| p.max_per_stage_descriptor_input_attachments, + limit_name_not_uab: "max_per_stage_descriptor_input_attachments", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03021"], }, DescriptorLimit { descriptor_types: &[DescriptorType::InlineUniformBlock], - get_limit: |p| { + get_limit_all: |p| { + p.max_per_stage_descriptor_update_after_bind_inline_uniform_blocks + }, + limit_name_all: "max_per_stage_descriptor_update_after_bind_inline_uniform_blocks", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-02215"], + get_limit_not_uab: |p| { p.max_per_stage_descriptor_inline_uniform_blocks .unwrap_or(0) }, - limit_name: "max_per_stage_descriptor_inline_uniform_blocks", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-02214"], + limit_name_not_uab: "max_per_stage_descriptor_inline_uniform_blocks", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-02214"], }, DescriptorLimit { descriptor_types: &[DescriptorType::AccelerationStructure], - get_limit: |p| { + get_limit_all: |p| { + p.max_per_stage_descriptor_update_after_bind_acceleration_structures + }, + limit_name_all: + "max_per_stage_descriptor_update_after_bind_acceleration_structures", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03572"], + get_limit_not_uab: |p| { p.max_per_stage_descriptor_acceleration_structures .unwrap_or(0) }, - limit_name: "max_per_stage_descriptor_acceleration_structures", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03571"], + limit_name_not_uab: "max_per_stage_descriptor_acceleration_structures", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03571"], }, ]; @@ -557,33 +589,48 @@ impl PipelineLayoutCreateInfo { DescriptorType::Sampler, DescriptorType::CombinedImageSampler, ], - get_limit: |p| p.max_descriptor_set_samplers, - limit_name: "max_descriptor_set_samplers", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03028"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_samplers, + limit_name_all: "max_descriptor_set_update_after_bind_samplers", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03036"], + get_limit_not_uab: |p| p.max_descriptor_set_samplers, + limit_name_not_uab: "max_descriptor_set_samplers", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03028"], }, DescriptorLimit { descriptor_types: &[DescriptorType::UniformBuffer], - get_limit: |p| p.max_descriptor_set_uniform_buffers, - limit_name: "max_descriptor_set_uniform_buffers", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03029"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_uniform_buffers, + limit_name_all: "max_descriptor_set_update_after_bind_uniform_buffers", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03037"], + get_limit_not_uab: |p| p.max_descriptor_set_uniform_buffers, + limit_name_not_uab: "max_descriptor_set_uniform_buffers", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03029"], }, DescriptorLimit { descriptor_types: &[DescriptorType::UniformBufferDynamic], - get_limit: |p| p.max_descriptor_set_uniform_buffers_dynamic, - limit_name: "max_descriptor_set_uniform_buffers_dynamic", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03030"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_uniform_buffers_dynamic, + limit_name_all: "max_descriptor_set_update_after_bind_uniform_buffers_dynamic", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03038"], + get_limit_not_uab: |p| p.max_descriptor_set_uniform_buffers_dynamic, + limit_name_not_uab: "max_descriptor_set_uniform_buffers_dynamic", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03030"], }, DescriptorLimit { descriptor_types: &[DescriptorType::StorageBuffer], - get_limit: |p| p.max_descriptor_set_storage_buffers, - limit_name: "max_descriptor_set_storage_buffers", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03031"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_storage_buffers, + limit_name_all: "max_descriptor_set_update_after_bind_storage_buffers", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03039"], + get_limit_not_uab: |p| p.max_descriptor_set_storage_buffers, + limit_name_not_uab: "max_descriptor_set_storage_buffers", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03031"], }, DescriptorLimit { descriptor_types: &[DescriptorType::StorageBufferDynamic], - get_limit: |p| p.max_descriptor_set_storage_buffers_dynamic, - limit_name: "max_descriptor_set_storage_buffers_dynamic", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03032"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_storage_buffers_dynamic, + limit_name_all: "max_descriptor_set_update_after_bind_storage_buffers_dynamic", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03040"], + get_limit_not_uab: |p| p.max_descriptor_set_storage_buffers_dynamic, + limit_name_not_uab: "max_descriptor_set_storage_buffers_dynamic", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03032"], }, DescriptorLimit { descriptor_types: &[ @@ -591,42 +638,60 @@ impl PipelineLayoutCreateInfo { DescriptorType::SampledImage, DescriptorType::UniformTexelBuffer, ], - get_limit: |p| p.max_descriptor_set_sampled_images, - limit_name: "max_descriptor_set_sampled_images", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03033"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_sampled_images, + limit_name_all: "max_descriptor_set_update_after_bind_sampled_images", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03041"], + get_limit_not_uab: |p| p.max_descriptor_set_sampled_images, + limit_name_not_uab: "max_descriptor_set_sampled_images", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03033"], }, DescriptorLimit { descriptor_types: &[ DescriptorType::StorageImage, DescriptorType::StorageTexelBuffer, ], - get_limit: |p| p.max_descriptor_set_storage_images, - limit_name: "max_descriptor_set_storage_images", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03034"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_storage_images, + limit_name_all: "max_descriptor_set_update_after_bind_storage_images", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03042"], + get_limit_not_uab: |p| p.max_descriptor_set_storage_images, + limit_name_not_uab: "max_descriptor_set_storage_images", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03034"], }, DescriptorLimit { descriptor_types: &[DescriptorType::InputAttachment], - get_limit: |p| p.max_descriptor_set_input_attachments, - limit_name: "max_descriptor_set_input_attachments", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03035"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_input_attachments, + limit_name_all: "max_descriptor_set_update_after_bind_input_attachments", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03043"], + get_limit_not_uab: |p| p.max_descriptor_set_input_attachments, + limit_name_not_uab: "max_descriptor_set_input_attachments", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03035"], }, DescriptorLimit { descriptor_types: &[DescriptorType::InlineUniformBlock], - get_limit: |p| p.max_descriptor_set_inline_uniform_blocks.unwrap_or(0), - limit_name: "max_descriptor_set_inline_uniform_blocks", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-02216"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_inline_uniform_blocks, + limit_name_all: "max_descriptor_set_update_after_bind_inline_uniform_blocks", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-02217"], + get_limit_not_uab: |p| p.max_descriptor_set_inline_uniform_blocks.unwrap_or(0), + limit_name_not_uab: "max_descriptor_set_inline_uniform_blocks", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-02216"], }, DescriptorLimit { descriptor_types: &[DescriptorType::AccelerationStructure], - get_limit: |p| p.max_descriptor_set_acceleration_structures.unwrap_or(0), - limit_name: "max_descriptor_set_acceleration_structures", - vuids: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03573"], + get_limit_all: |p| p.max_descriptor_set_update_after_bind_acceleration_structures, + limit_name_all: "max_descriptor_set_update_after_bind_acceleration_structures", + vuids_all: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03574"], + get_limit_not_uab: |p| p.max_descriptor_set_acceleration_structures.unwrap_or(0), + limit_name_not_uab: "max_descriptor_set_acceleration_structures", + vuids_not_uab: &["VUID-VkPipelineLayoutCreateInfo-descriptorType-03573"], }, ]; - let mut per_stage_descriptors: [HashMap; + let mut per_stage_descriptors_all: [HashMap; PER_STAGE_DESCRIPTOR_LIMITS.len()] = array::from_fn(|_| HashMap::default()); - let mut total_descriptors = [0; TOTAL_DESCRIPTOR_LIMITS.len()]; + let mut per_stage_descriptors_not_uab: [HashMap; + PER_STAGE_DESCRIPTOR_LIMITS.len()] = array::from_fn(|_| HashMap::default()); + let mut total_descriptors_all = [0; TOTAL_DESCRIPTOR_LIMITS.len()]; + let mut total_descriptors_not_uab = [0; TOTAL_DESCRIPTOR_LIMITS.len()]; let mut has_push_descriptor_set = false; for (_set_num, set_layout) in set_layouts.iter().enumerate() { @@ -650,6 +715,10 @@ impl PipelineLayoutCreateInfo { has_push_descriptor_set = true; } + let is_not_uab = !set_layout + .flags() + .intersects(DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL); + for layout_binding in set_layout.bindings().values() { let &DescriptorSetLayoutBinding { binding_flags: _, @@ -660,36 +729,86 @@ impl PipelineLayoutCreateInfo { _ne: _, } = layout_binding; - for (limit, count) in PER_STAGE_DESCRIPTOR_LIMITS + for ((limit, count_all), count_not_uab) in PER_STAGE_DESCRIPTOR_LIMITS .iter() - .zip(&mut per_stage_descriptors) + .zip(&mut per_stage_descriptors_all) + .zip(&mut per_stage_descriptors_not_uab) { if limit.descriptor_types.contains(&descriptor_type) { for stage in stages { - *count.entry(stage).or_default() += descriptor_count; + *count_all.entry(stage).or_default() += descriptor_count; + + if is_not_uab { + *count_not_uab.entry(stage).or_default() += descriptor_count; + } } } } - for (limit, count) in TOTAL_DESCRIPTOR_LIMITS.iter().zip(&mut total_descriptors) { + for ((limit, count_all), count_not_uab) in TOTAL_DESCRIPTOR_LIMITS + .iter() + .zip(&mut total_descriptors_all) + .zip(&mut total_descriptors_not_uab) + { if limit.descriptor_types.contains(&descriptor_type) { - *count += descriptor_count; + *count_all += descriptor_count; + + if is_not_uab { + *count_not_uab += descriptor_count; + } } } } } - for (limit, count) in PER_STAGE_DESCRIPTOR_LIMITS + for ((limit, count_all), count_not_uab) in PER_STAGE_DESCRIPTOR_LIMITS .iter() - .zip(per_stage_descriptors) + .zip(per_stage_descriptors_all) + .zip(per_stage_descriptors_not_uab) { - if let Some((max_stage, max_count)) = count.into_iter().max_by_key(|(_, c)| *c) { - if max_count > (limit.get_limit)(properties) { + let limit_not_uab = (limit.get_limit_not_uab)(properties); + + if let Some((max_stage, max_count)) = count_not_uab.into_iter().max_by_key(|(_, c)| *c) + { + if max_count > limit_not_uab { + return Err(Box::new(ValidationError { + context: "set_layouts".into(), + problem: format!( + "the combined number of {} descriptors, \ + belonging to descriptor set layouts without the \ + `DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL` flag, \ + accessible to the `ShaderStage::{:?}` stage, \ + exceeds the `{}` limit", + limit.descriptor_types[1..].iter().fold( + format!("`DescriptorType::{:?}`", limit.descriptor_types[0]), + |mut s, dt| { + write!(s, " + `DescriptorType::{:?}`", dt).unwrap(); + s + } + ), + max_stage, + limit.limit_name_not_uab, + ) + .into(), + vuids: limit.vuids_not_uab, + ..Default::default() + })); + } + } + + let limit_all = match (limit.get_limit_all)(properties) { + Some(x) => x, + None => continue, + }; + + if let Some((max_stage, max_count)) = count_all.into_iter().max_by_key(|(_, c)| *c) { + if max_count > limit_all { return Err(Box::new(ValidationError { context: "set_layouts".into(), problem: format!( - "the combined number of {} descriptors accessible to the \ - `ShaderStage::{:?}` stage exceeds the `{}` limit", + "the combined number of {} descriptors, \ + accessible to the `ShaderStage::{:?}` stage, \ + exceeds the `{}` limit", limit.descriptor_types[1..].iter().fold( format!("`DescriptorType::{:?}`", limit.descriptor_types[0]), |mut s, dt| { @@ -698,23 +817,59 @@ impl PipelineLayoutCreateInfo { } ), max_stage, - limit.limit_name, + limit.limit_name_all, ) .into(), - vuids: limit.vuids, + vuids: limit.vuids_all, ..Default::default() })); } } } - for (limit, count) in TOTAL_DESCRIPTOR_LIMITS.iter().zip(total_descriptors) { - if count > (limit.get_limit)(properties) { + for ((limit, count_all), count_not_uab) in TOTAL_DESCRIPTOR_LIMITS + .iter() + .zip(total_descriptors_all) + .zip(total_descriptors_not_uab) + { + let limit_not_uab = (limit.get_limit_not_uab)(properties); + + if count_not_uab > limit_not_uab { + return Err(Box::new(ValidationError { + context: "set_layouts".into(), + problem: format!( + "the combined number of {} descriptors, \ + belonging to descriptor set layouts without the \ + `DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL` flag, \ + accessible across all shader stages, \ + exceeds the `{}` limit", + limit.descriptor_types[1..].iter().fold( + format!("`DescriptorType::{:?}`", limit.descriptor_types[0]), + |mut s, dt| { + write!(s, " + `DescriptorType::{:?}`", dt).unwrap(); + s + } + ), + limit.limit_name_not_uab, + ) + .into(), + vuids: limit.vuids_not_uab, + ..Default::default() + })); + } + + let limit_all = match (limit.get_limit_all)(properties) { + Some(x) => x, + None => continue, + }; + + if count_all > limit_all { return Err(Box::new(ValidationError { context: "set_layouts".into(), problem: format!( - "the combined number of {} descriptors accessible across all \ - shader stages exceeds the `{}` limit", + "the combined number of {} descriptors, \ + accessible across all shader stages, \ + exceeds the `{}` limit", limit.descriptor_types[1..].iter().fold( format!("`DescriptorType::{:?}`", limit.descriptor_types[0]), |mut s, dt| { @@ -722,10 +877,10 @@ impl PipelineLayoutCreateInfo { s } ), - limit.limit_name, + limit.limit_name_all, ) .into(), - vuids: limit.vuids, + vuids: limit.vuids_all, ..Default::default() })); }