layers: Validate updating mutable type is allowed
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index bcfed5d..29cbf59 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -80,6 +80,18 @@
sorted_bindings.emplace(p_create_info->pBindings + i, flags);
}
+ const auto *mutable_descriptor_type_create_info = LvlFindInChain<VkMutableDescriptorTypeCreateInfoVALVE>(p_create_info->pNext);
+ if (mutable_descriptor_type_create_info) {
+ mutable_types_.resize(mutable_descriptor_type_create_info->mutableDescriptorTypeListCount);
+ for (uint32_t i = 0; i < mutable_descriptor_type_create_info->mutableDescriptorTypeListCount; ++i) {
+ const auto &list = mutable_descriptor_type_create_info->pMutableDescriptorTypeLists[i];
+ mutable_types_[i].reserve(list.descriptorTypeCount);
+ for (uint32_t j = 0; j < list.descriptorTypeCount; ++j) {
+ mutable_types_[i].push_back(list.pDescriptorTypes[j]);
+ }
+ }
+ }
+
// Store the create info in the sorted order from above
uint32_t index = 0;
binding_count_ = static_cast<uint32_t>(sorted_bindings.size());
@@ -206,6 +218,22 @@
return nullptr;
}
+bool cvdescriptorset::DescriptorSetLayoutDef::IsTypeMutable(const VkDescriptorType type, uint32_t binding) const {
+ if (binding < mutable_types_.size()) {
+ if (mutable_types_[binding].size() > 0) {
+ for (const auto mutable_type : mutable_types_[binding]) {
+ if (type == mutable_type) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ // If mutableDescriptorTypeListCount is zero or if VkMutableDescriptorTypeCreateInfoVALVE structure is not included in the pNext
+ // chain, the VkMutableDescriptorTypeListVALVE for each element is considered to be zero or NULL for each member.
+ return false;
+}
+
// If our layout is compatible with rh_ds_layout, return true.
bool cvdescriptorset::DescriptorSetLayout::IsCompatible(DescriptorSetLayout const *rh_ds_layout) const {
bool compatible = (this == rh_ds_layout) || (GetLayoutDef() == rh_ds_layout->GetLayoutDef());
@@ -3436,6 +3464,19 @@
*error_msg = error_str.str();
return false;
}
+ const auto orig_binding = DescriptorSetLayout::ConstBindingIterator(dest_set->GetLayout().get(), update->dstBinding);
+ if (!orig_binding.AtEnd() && orig_binding.GetType() == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ // Check if the new descriptor descriptor type is in the list of allowed mutable types for this binding
+ if (!orig_binding.Layout()->IsTypeMutable(update->descriptorType, update->dstBinding)) {
+ *error_code = "VUID-VkWriteDescriptorSet-dstSet-04611";
+ std::stringstream error_str;
+ error_str << "Write update type is " << string_VkDescriptorType(update->descriptorType)
+ << ", but descriptor set layout binding was created with type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE and used type "
+ "is not in VkMutableDescriptorTypeListVALVE::pDescriptorTypes for this binding.";
+ *error_msg = error_str.str();
+ return false;
+ }
+ }
// All checks passed, update is clean
return true;
}
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index 5ac768d..5aa1b03 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -175,6 +175,7 @@
}
VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t) const;
VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t) const;
+ bool IsTypeMutable(const VkDescriptorType type, uint32_t binding) const;
// For a particular binding, get the global index range
// This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists
const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t) const;
@@ -196,6 +197,8 @@
VkDescriptorSetLayoutCreateFlags flags_;
std::vector<safe_VkDescriptorSetLayoutBinding> bindings_;
std::vector<VkDescriptorBindingFlags> binding_flags_;
+ // List of mutable types for each binding: [binding][mutable type]
+ std::vector<std::vector<VkDescriptorType>> mutable_types_;
// Convenience data structures for rapid lookup of various descriptor set layout properties
std::set<uint32_t> non_empty_bindings_; // Containing non-emtpy bindings in numerical order
@@ -272,6 +275,7 @@
VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
return layout_id_->GetImmutableSamplerPtrFromIndex(index);
}
+ bool IsTypeMutable(const VkDescriptorType type, uint32_t binding) const { return layout_id_->IsTypeMutable(type, binding); }
// For a particular binding, get the global index range
// This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists
const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t binding) const {