layers: Validate copying mutable descriptor set types
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index 29cbf59..13c66f6 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -234,6 +234,14 @@
return false;
}
+const std::vector<VkDescriptorType> &cvdescriptorset::DescriptorSetLayoutDef::GetMutableTypes(uint32_t binding) const {
+ if (binding >= mutable_types_.size()) {
+ static const std::vector<VkDescriptorType> empty = {};
+ return empty;
+ }
+ return mutable_types_[binding];
+}
+
// 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());
@@ -784,7 +792,7 @@
break;
case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE:
for (uint32_t di = 0; di < layout_->GetDescriptorCountFromIndex(i); ++di) {
- descriptors_.emplace_back(new ((free_descriptor++)->InlineUniform()) MutableDescriptor());
+ descriptors_.emplace_back(new ((free_descriptor++)->Mutable()) MutableDescriptor());
descriptors_.back()->AddParent(this);
}
break;
@@ -1641,6 +1649,7 @@
uint32_t update_count = std::min(descriptors_remaining, current_binding.GetDescriptorCount() - offset);
for (uint32_t di = 0; di < update_count; ++di, ++update_index) {
descriptors_[global_idx + di]->WriteUpdate(this, state_data_, update, update_index);
+ descriptors_[global_idx + di]->SetDescriptorType(update->descriptorType);
}
// Roll over to next binding in case of consecutive update
descriptors_remaining -= update_count;
@@ -1891,6 +1900,58 @@
}
}
+ if (dst_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ if (src_type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ if (!dst_layout->IsTypeMutable(src_type, update->dstBinding)) {
+ *error_code = "VUID-VkCopyDescriptorSet-dstSet-04612";
+ std::stringstream error_str;
+ error_str << "Attempting copy update with dstBinding descriptor type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, but the new "
+ "active descriptor type "
+ << string_VkDescriptorType(src_type)
+ << " is not in the corresponding pMutableDescriptorTypeLists list.";
+ *error_msg = error_str.str();
+ return false;
+ }
+ }
+ } else if (src_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ const auto *descriptor = src_set->GetDescriptorFromGlobalIndex(update->srcBinding);
+ if (descriptor->active_descriptor_type != dst_type) {
+ *error_code = "VUID-VkCopyDescriptorSet-srcSet-04613";
+ std::stringstream error_str;
+ error_str << "Attempting copy update with srcBinding descriptor type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, but the "
+ "active descriptor type ("
+ << string_VkDescriptorType(descriptor->active_descriptor_type)
+ << ") does not match the dstBinding descriptor type " << string_VkDescriptorType(dst_type) << ".";
+ *error_msg = error_str.str();
+ return false;
+ }
+ }
+
+ if (dst_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ if (src_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ const auto &mutable_src_types = src_layout->GetMutableTypes(update->srcBinding);
+ const auto &mutable_dst_types = dst_layout->GetMutableTypes(update->dstBinding);
+ bool complete_match = mutable_src_types.size() == mutable_dst_types.size();
+ if (complete_match) {
+ for (const auto mutable_src_type : mutable_src_types) {
+ if (std::find(mutable_dst_types.begin(), mutable_dst_types.end(), mutable_src_type) ==
+ mutable_dst_types.end()) {
+ complete_match = false;
+ break;
+ }
+ }
+ }
+ if (!complete_match) {
+ *error_code = "VUID-VkCopyDescriptorSet-dstSet-04614";
+ std::stringstream error_str;
+ error_str << "Attempting copy update with dstBinding and new active descriptor type being "
+ "VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, but their corresponding pMutableDescriptorTypeLists do not match.";
+ *error_msg = error_str.str();
+ return false;
+ }
+ }
+ }
+
// Update parameters all look good and descriptor updated so verify update contents
if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, dst_set, dst_type, dst_start_idx, func_name, error_code,
error_msg)) {
@@ -1916,6 +1977,7 @@
} else {
dst->updated = false;
}
+ dst->active_descriptor_type = src->active_descriptor_type;
}
if (!(layout_->GetDescriptorBindingFlagsFromBinding(update->dstBinding) &
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index 5aa1b03..a8e9272 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -176,6 +176,7 @@
VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t) const;
VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t) const;
bool IsTypeMutable(const VkDescriptorType type, uint32_t binding) const;
+ const std::vector<VkDescriptorType> &GetMutableTypes(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;
@@ -276,6 +277,7 @@
return layout_id_->GetImmutableSamplerPtrFromIndex(index);
}
bool IsTypeMutable(const VkDescriptorType type, uint32_t binding) const { return layout_id_->IsTypeMutable(type, binding); }
+ const std::vector<VkDescriptorType> &GetMutableTypes(uint32_t binding) const { return layout_id_->GetMutableTypes(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 {
@@ -386,7 +388,7 @@
class Descriptor {
public:
- Descriptor(DescriptorClass class_) : updated(false), descriptor_class(class_) {}
+ Descriptor(DescriptorClass class_) : updated(false), descriptor_class(class_), active_descriptor_type(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {}
virtual ~Descriptor(){};
virtual void WriteUpdate(DescriptorSet *set_state, const ValidationStateTracker *dev_data, const VkWriteDescriptorSet *, const uint32_t) = 0;
virtual void CopyUpdate(DescriptorSet *set_state, const ValidationStateTracker *dev_data, const Descriptor *) = 0;
@@ -396,9 +398,11 @@
virtual bool IsImmutableSampler() const { return false; };
virtual bool AddParent(BASE_NODE *base_node) { return false; }
virtual void RemoveParent(BASE_NODE *base_node) {}
+ void SetDescriptorType(VkDescriptorType type) { active_descriptor_type = type; }
bool updated; // Has descriptor been updated?
DescriptorClass descriptor_class;
+ VkDescriptorType active_descriptor_type;
};
// Return true if this layout is compatible with passed in layout from a pipelineLayout,
@@ -652,6 +656,7 @@
AccelerationStructureDescriptor *AccelerationStructure() {
return &(reinterpret_cast<AnyDescriptor *>(this)->accelerator_structure);
}
+ MutableDescriptor *Mutable() { return &(reinterpret_cast<AnyDescriptor *>(this)->mutable_descriptor); }
};
// Structs to contain common elements that need to be shared between Validate* and Perform* calls below