• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2015-2019 The Khronos Group Inc.
2  * Copyright (c) 2015-2019 Valve Corporation
3  * Copyright (c) 2015-2019 LunarG, Inc.
4  * Copyright (C) 2015-2019 Google Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Author: Tobin Ehlis <tobine@google.com>
19  *         John Zulauf <jzulauf@lunarg.com>
20  */
21 
22 // Allow use of STL min and max functions in Windows
23 #define NOMINMAX
24 
25 #include "chassis.h"
26 #include "core_validation_error_enums.h"
27 #include "core_validation.h"
28 #include "descriptor_sets.h"
29 #include "hash_vk_types.h"
30 #include "vk_enum_string_helper.h"
31 #include "vk_safe_struct.h"
32 #include "vk_typemap_helper.h"
33 #include "buffer_validation.h"
34 #include <sstream>
35 #include <algorithm>
36 #include <array>
37 #include <memory>
38 
39 // ExtendedBinding collects a VkDescriptorSetLayoutBinding and any extended
40 // state that comes from a different array/structure so they can stay together
41 // while being sorted by binding number.
42 struct ExtendedBinding {
ExtendedBindingExtendedBinding43     ExtendedBinding(const VkDescriptorSetLayoutBinding *l, VkDescriptorBindingFlagsEXT f) : layout_binding(l), binding_flags(f) {}
44 
45     const VkDescriptorSetLayoutBinding *layout_binding;
46     VkDescriptorBindingFlagsEXT binding_flags;
47 };
48 
49 struct BindingNumCmp {
operator ()BindingNumCmp50     bool operator()(const ExtendedBinding &a, const ExtendedBinding &b) const {
51         return a.layout_binding->binding < b.layout_binding->binding;
52     }
53 };
54 
55 using DescriptorSet = cvdescriptorset::DescriptorSet;
56 using DescriptorSetLayout = cvdescriptorset::DescriptorSetLayout;
57 using DescriptorSetLayoutDef = cvdescriptorset::DescriptorSetLayoutDef;
58 using DescriptorSetLayoutId = cvdescriptorset::DescriptorSetLayoutId;
59 
60 // Canonical dictionary of DescriptorSetLayoutDef (without any handle/device specific information)
61 cvdescriptorset::DescriptorSetLayoutDict descriptor_set_layout_dict;
62 
GetCanonicalId(const VkDescriptorSetLayoutCreateInfo * p_create_info)63 DescriptorSetLayoutId GetCanonicalId(const VkDescriptorSetLayoutCreateInfo *p_create_info) {
64     return descriptor_set_layout_dict.look_up(DescriptorSetLayoutDef(p_create_info));
65 }
66 
67 // Construct DescriptorSetLayout instance from given create info
68 // Proactively reserve and resize as possible, as the reallocation was visible in profiling
DescriptorSetLayoutDef(const VkDescriptorSetLayoutCreateInfo * p_create_info)69 cvdescriptorset::DescriptorSetLayoutDef::DescriptorSetLayoutDef(const VkDescriptorSetLayoutCreateInfo *p_create_info)
70     : flags_(p_create_info->flags), binding_count_(0), descriptor_count_(0), dynamic_descriptor_count_(0) {
71     const auto *flags_create_info = lvl_find_in_chain<VkDescriptorSetLayoutBindingFlagsCreateInfoEXT>(p_create_info->pNext);
72 
73     binding_type_stats_ = {0, 0, 0};
74     std::set<ExtendedBinding, BindingNumCmp> sorted_bindings;
75     const uint32_t input_bindings_count = p_create_info->bindingCount;
76     // Sort the input bindings in binding number order, eliminating duplicates
77     for (uint32_t i = 0; i < input_bindings_count; i++) {
78         VkDescriptorBindingFlagsEXT flags = 0;
79         if (flags_create_info && flags_create_info->bindingCount == p_create_info->bindingCount) {
80             flags = flags_create_info->pBindingFlags[i];
81         }
82         sorted_bindings.insert(ExtendedBinding(p_create_info->pBindings + i, flags));
83     }
84 
85     // Store the create info in the sorted order from above
86     std::map<uint32_t, uint32_t> binding_to_dyn_count;
87     uint32_t index = 0;
88     binding_count_ = static_cast<uint32_t>(sorted_bindings.size());
89     bindings_.reserve(binding_count_);
90     binding_flags_.reserve(binding_count_);
91     binding_to_index_map_.reserve(binding_count_);
92     for (auto input_binding : sorted_bindings) {
93         // Add to binding and map, s.t. it is robust to invalid duplication of binding_num
94         const auto binding_num = input_binding.layout_binding->binding;
95         binding_to_index_map_[binding_num] = index++;
96         bindings_.emplace_back(input_binding.layout_binding);
97         auto &binding_info = bindings_.back();
98         binding_flags_.emplace_back(input_binding.binding_flags);
99 
100         descriptor_count_ += binding_info.descriptorCount;
101         if (binding_info.descriptorCount > 0) {
102             non_empty_bindings_.insert(binding_num);
103         }
104 
105         if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
106             binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
107             binding_to_dyn_count[binding_num] = binding_info.descriptorCount;
108             dynamic_descriptor_count_ += binding_info.descriptorCount;
109             binding_type_stats_.dynamic_buffer_count++;
110         } else if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
111                    (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) {
112             binding_type_stats_.non_dynamic_buffer_count++;
113         } else {
114             binding_type_stats_.image_sampler_count++;
115         }
116     }
117     assert(bindings_.size() == binding_count_);
118     assert(binding_flags_.size() == binding_count_);
119     uint32_t global_index = 0;
120     global_index_range_.reserve(binding_count_);
121     // Vector order is finalized so build vectors of descriptors and dynamic offsets by binding index
122     for (uint32_t i = 0; i < binding_count_; ++i) {
123         auto final_index = global_index + bindings_[i].descriptorCount;
124         global_index_range_.emplace_back(global_index, final_index);
125         global_index = final_index;
126     }
127 
128     // Now create dyn offset array mapping for any dynamic descriptors
129     uint32_t dyn_array_idx = 0;
130     binding_to_dynamic_array_idx_map_.reserve(binding_to_dyn_count.size());
131     for (const auto &bc_pair : binding_to_dyn_count) {
132         binding_to_dynamic_array_idx_map_[bc_pair.first] = dyn_array_idx;
133         dyn_array_idx += bc_pair.second;
134     }
135 }
136 
hash() const137 size_t cvdescriptorset::DescriptorSetLayoutDef::hash() const {
138     hash_util::HashCombiner hc;
139     hc << flags_;
140     hc.Combine(bindings_);
141     hc.Combine(binding_flags_);
142     return hc.Value();
143 }
144 //
145 
146 // Return valid index or "end" i.e. binding_count_;
147 // The asserts in "Get" are reduced to the set where no valid answer(like null or 0) could be given
148 // Common code for all binding lookups.
GetIndexFromBinding(uint32_t binding) const149 uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetIndexFromBinding(uint32_t binding) const {
150     const auto &bi_itr = binding_to_index_map_.find(binding);
151     if (bi_itr != binding_to_index_map_.cend()) return bi_itr->second;
152     return GetBindingCount();
153 }
GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) const154 VkDescriptorSetLayoutBinding const *cvdescriptorset::DescriptorSetLayoutDef::GetDescriptorSetLayoutBindingPtrFromIndex(
155     const uint32_t index) const {
156     if (index >= bindings_.size()) return nullptr;
157     return bindings_[index].ptr();
158 }
159 // Return descriptorCount for given index, 0 if index is unavailable
GetDescriptorCountFromIndex(const uint32_t index) const160 uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetDescriptorCountFromIndex(const uint32_t index) const {
161     if (index >= bindings_.size()) return 0;
162     return bindings_[index].descriptorCount;
163 }
164 // For the given index, return descriptorType
GetTypeFromIndex(const uint32_t index) const165 VkDescriptorType cvdescriptorset::DescriptorSetLayoutDef::GetTypeFromIndex(const uint32_t index) const {
166     assert(index < bindings_.size());
167     if (index < bindings_.size()) return bindings_[index].descriptorType;
168     return VK_DESCRIPTOR_TYPE_MAX_ENUM;
169 }
170 // For the given index, return stageFlags
GetStageFlagsFromIndex(const uint32_t index) const171 VkShaderStageFlags cvdescriptorset::DescriptorSetLayoutDef::GetStageFlagsFromIndex(const uint32_t index) const {
172     assert(index < bindings_.size());
173     if (index < bindings_.size()) return bindings_[index].stageFlags;
174     return VkShaderStageFlags(0);
175 }
176 // Return binding flags for given index, 0 if index is unavailable
GetDescriptorBindingFlagsFromIndex(const uint32_t index) const177 VkDescriptorBindingFlagsEXT cvdescriptorset::DescriptorSetLayoutDef::GetDescriptorBindingFlagsFromIndex(
178     const uint32_t index) const {
179     if (index >= binding_flags_.size()) return 0;
180     return binding_flags_[index];
181 }
182 
GetGlobalIndexRangeFromIndex(uint32_t index) const183 const cvdescriptorset::IndexRange &cvdescriptorset::DescriptorSetLayoutDef::GetGlobalIndexRangeFromIndex(uint32_t index) const {
184     const static IndexRange kInvalidRange = {0xFFFFFFFF, 0xFFFFFFFF};
185     if (index >= binding_flags_.size()) return kInvalidRange;
186     return global_index_range_[index];
187 }
188 
189 // For the given binding, return the global index range (half open)
190 // As start and end are often needed in pairs, get both with a single lookup.
GetGlobalIndexRangeFromBinding(const uint32_t binding) const191 const cvdescriptorset::IndexRange &cvdescriptorset::DescriptorSetLayoutDef::GetGlobalIndexRangeFromBinding(
192     const uint32_t binding) const {
193     uint32_t index = GetIndexFromBinding(binding);
194     return GetGlobalIndexRangeFromIndex(index);
195 }
196 
197 // For given binding, return ptr to ImmutableSampler array
GetImmutableSamplerPtrFromBinding(const uint32_t binding) const198 VkSampler const *cvdescriptorset::DescriptorSetLayoutDef::GetImmutableSamplerPtrFromBinding(const uint32_t binding) const {
199     const auto &bi_itr = binding_to_index_map_.find(binding);
200     if (bi_itr != binding_to_index_map_.end()) {
201         return bindings_[bi_itr->second].pImmutableSamplers;
202     }
203     return nullptr;
204 }
205 // Move to next valid binding having a non-zero binding count
GetNextValidBinding(const uint32_t binding) const206 uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetNextValidBinding(const uint32_t binding) const {
207     auto it = non_empty_bindings_.upper_bound(binding);
208     assert(it != non_empty_bindings_.cend());
209     if (it != non_empty_bindings_.cend()) return *it;
210     return GetMaxBinding() + 1;
211 }
212 // For given index, return ptr to ImmutableSampler array
GetImmutableSamplerPtrFromIndex(const uint32_t index) const213 VkSampler const *cvdescriptorset::DescriptorSetLayoutDef::GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
214     if (index < bindings_.size()) {
215         return bindings_[index].pImmutableSamplers;
216     }
217     return nullptr;
218 }
219 
220 // If our layout is compatible with rh_ds_layout, return true.
IsCompatible(DescriptorSetLayout const * rh_ds_layout) const221 bool cvdescriptorset::DescriptorSetLayout::IsCompatible(DescriptorSetLayout const *rh_ds_layout) const {
222     bool compatible = (this == rh_ds_layout) || (GetLayoutDef() == rh_ds_layout->GetLayoutDef());
223     return compatible;
224 }
225 // If our layout is compatible with rh_ds_layout, return true,
226 //  else return false and fill in error_msg will description of what causes incompatibility
VerifySetLayoutCompatibility(DescriptorSetLayout const * lh_ds_layout,DescriptorSetLayout const * rh_ds_layout,std::string * error_msg)227 bool cvdescriptorset::VerifySetLayoutCompatibility(DescriptorSetLayout const *lh_ds_layout, DescriptorSetLayout const *rh_ds_layout,
228                                                    std::string *error_msg) {
229     // Short circuit the detailed check.
230     if (lh_ds_layout->IsCompatible(rh_ds_layout)) return true;
231 
232     // Do a detailed compatibility check of this lhs def (referenced by lh_ds_layout), vs. the rhs (layout and def)
233     // Should only be run if trivial accept has failed, and in that context should return false.
234     VkDescriptorSetLayout lh_dsl_handle = lh_ds_layout->GetDescriptorSetLayout();
235     VkDescriptorSetLayout rh_dsl_handle = rh_ds_layout->GetDescriptorSetLayout();
236     DescriptorSetLayoutDef const *lh_ds_layout_def = lh_ds_layout->GetLayoutDef();
237     DescriptorSetLayoutDef const *rh_ds_layout_def = rh_ds_layout->GetLayoutDef();
238 
239     // Check descriptor counts
240     if (lh_ds_layout_def->GetTotalDescriptorCount() != rh_ds_layout_def->GetTotalDescriptorCount()) {
241         std::stringstream error_str;
242         error_str << "DescriptorSetLayout " << lh_dsl_handle << " has " << lh_ds_layout_def->GetTotalDescriptorCount()
243                   << " descriptors, but DescriptorSetLayout " << rh_dsl_handle << ", which comes from pipelineLayout, has "
244                   << rh_ds_layout_def->GetTotalDescriptorCount() << " descriptors.";
245         *error_msg = error_str.str();
246         return false;  // trivial fail case
247     }
248 
249     // Descriptor counts match so need to go through bindings one-by-one
250     //  and verify that type and stageFlags match
251     for (const auto &binding : lh_ds_layout_def->GetBindings()) {
252         // TODO : Do we also need to check immutable samplers?
253         // VkDescriptorSetLayoutBinding *rh_binding;
254         if (binding.descriptorCount != rh_ds_layout_def->GetDescriptorCountFromBinding(binding.binding)) {
255             std::stringstream error_str;
256             error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << lh_dsl_handle
257                       << " has a descriptorCount of " << binding.descriptorCount << " but binding " << binding.binding
258                       << " for DescriptorSetLayout " << rh_dsl_handle
259                       << ", which comes from pipelineLayout, has a descriptorCount of "
260                       << rh_ds_layout_def->GetDescriptorCountFromBinding(binding.binding);
261             *error_msg = error_str.str();
262             return false;
263         } else if (binding.descriptorType != rh_ds_layout_def->GetTypeFromBinding(binding.binding)) {
264             std::stringstream error_str;
265             error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << lh_dsl_handle << " is type '"
266                       << string_VkDescriptorType(binding.descriptorType) << "' but binding " << binding.binding
267                       << " for DescriptorSetLayout " << rh_dsl_handle << ", which comes from pipelineLayout, is type '"
268                       << string_VkDescriptorType(rh_ds_layout_def->GetTypeFromBinding(binding.binding)) << "'";
269             *error_msg = error_str.str();
270             return false;
271         } else if (binding.stageFlags != rh_ds_layout_def->GetStageFlagsFromBinding(binding.binding)) {
272             std::stringstream error_str;
273             error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << lh_dsl_handle << " has stageFlags "
274                       << binding.stageFlags << " but binding " << binding.binding << " for DescriptorSetLayout " << rh_dsl_handle
275                       << ", which comes from pipelineLayout, has stageFlags "
276                       << rh_ds_layout_def->GetStageFlagsFromBinding(binding.binding);
277             *error_msg = error_str.str();
278             return false;
279         }
280     }
281     // No detailed check should succeed if the trivial check failed -- or the dictionary has failed somehow.
282     bool compatible = true;
283     assert(!compatible);
284     return compatible;
285 }
286 
IsNextBindingConsistent(const uint32_t binding) const287 bool cvdescriptorset::DescriptorSetLayoutDef::IsNextBindingConsistent(const uint32_t binding) const {
288     if (!binding_to_index_map_.count(binding + 1)) return false;
289     auto const &bi_itr = binding_to_index_map_.find(binding);
290     if (bi_itr != binding_to_index_map_.end()) {
291         const auto &next_bi_itr = binding_to_index_map_.find(binding + 1);
292         if (next_bi_itr != binding_to_index_map_.end()) {
293             auto type = bindings_[bi_itr->second].descriptorType;
294             auto stage_flags = bindings_[bi_itr->second].stageFlags;
295             auto immut_samp = bindings_[bi_itr->second].pImmutableSamplers ? true : false;
296             auto flags = binding_flags_[bi_itr->second];
297             if ((type != bindings_[next_bi_itr->second].descriptorType) ||
298                 (stage_flags != bindings_[next_bi_itr->second].stageFlags) ||
299                 (immut_samp != (bindings_[next_bi_itr->second].pImmutableSamplers ? true : false)) ||
300                 (flags != binding_flags_[next_bi_itr->second])) {
301                 return false;
302             }
303             return true;
304         }
305     }
306     return false;
307 }
308 
309 // The DescriptorSetLayout stores the per handle data for a descriptor set layout, and references the common defintion for the
310 // handle invariant portion
DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo * p_create_info,const VkDescriptorSetLayout layout)311 cvdescriptorset::DescriptorSetLayout::DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *p_create_info,
312                                                           const VkDescriptorSetLayout layout)
313     : layout_(layout), layout_destroyed_(false), layout_id_(GetCanonicalId(p_create_info)) {}
314 
315 // Validate descriptor set layout create info
ValidateDescriptorSetLayoutCreateInfo(const debug_report_data * report_data,const VkDescriptorSetLayoutCreateInfo * create_info,const bool push_descriptor_ext,const uint32_t max_push_descriptors,const bool descriptor_indexing_ext,const VkPhysicalDeviceDescriptorIndexingFeaturesEXT * descriptor_indexing_features,const VkPhysicalDeviceInlineUniformBlockFeaturesEXT * inline_uniform_block_features,const VkPhysicalDeviceInlineUniformBlockPropertiesEXT * inline_uniform_block_props,const DeviceExtensions * device_extensions)316 bool cvdescriptorset::ValidateDescriptorSetLayoutCreateInfo(
317     const debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *create_info, const bool push_descriptor_ext,
318     const uint32_t max_push_descriptors, const bool descriptor_indexing_ext,
319     const VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features,
320     const VkPhysicalDeviceInlineUniformBlockFeaturesEXT *inline_uniform_block_features,
321     const VkPhysicalDeviceInlineUniformBlockPropertiesEXT *inline_uniform_block_props, const DeviceExtensions *device_extensions) {
322     bool skip = false;
323     std::unordered_set<uint32_t> bindings;
324     uint64_t total_descriptors = 0;
325 
326     const auto *flags_create_info = lvl_find_in_chain<VkDescriptorSetLayoutBindingFlagsCreateInfoEXT>(create_info->pNext);
327 
328     const bool push_descriptor_set = !!(create_info->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
329     if (push_descriptor_set && !push_descriptor_ext) {
330         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
331                         kVUID_Core_DrawState_ExtensionNotEnabled,
332                         "Attempted to use %s in %s but its required extension %s has not been enabled.\n",
333                         "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR", "VkDescriptorSetLayoutCreateInfo::flags",
334                         VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
335     }
336 
337     const bool update_after_bind_set = !!(create_info->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT);
338     if (update_after_bind_set && !descriptor_indexing_ext) {
339         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
340                         kVUID_Core_DrawState_ExtensionNotEnabled,
341                         "Attemped to use %s in %s but its required extension %s has not been enabled.\n",
342                         "VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT", "VkDescriptorSetLayoutCreateInfo::flags",
343                         VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
344     }
345 
346     auto valid_type = [push_descriptor_set](const VkDescriptorType type) {
347         return !push_descriptor_set ||
348                ((type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) && (type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) &&
349                 (type != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT));
350     };
351 
352     uint32_t max_binding = 0;
353 
354     for (uint32_t i = 0; i < create_info->bindingCount; ++i) {
355         const auto &binding_info = create_info->pBindings[i];
356         max_binding = std::max(max_binding, binding_info.binding);
357 
358         if (!bindings.insert(binding_info.binding).second) {
359             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
360                             "VUID-VkDescriptorSetLayoutCreateInfo-binding-00279",
361                             "duplicated binding number in VkDescriptorSetLayoutBinding.");
362         }
363         if (!valid_type(binding_info.descriptorType)) {
364             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
365                             (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
366                                 ? "VUID-VkDescriptorSetLayoutCreateInfo-flags-02208"
367                                 : "VUID-VkDescriptorSetLayoutCreateInfo-flags-00280",
368                             "invalid type %s ,for push descriptors in VkDescriptorSetLayoutBinding entry %" PRIu32 ".",
369                             string_VkDescriptorType(binding_info.descriptorType), i);
370         }
371 
372         if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
373             if (!device_extensions->vk_ext_inline_uniform_block) {
374                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0,
375                                 "UNASSIGNED-Extension not enabled",
376                                 "Creating VkDescriptorSetLayout with descriptor type  VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT "
377                                 "but extension %s is missing",
378                                 VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
379             } else {
380                 if ((binding_info.descriptorCount % 4) != 0) {
381                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
382                                     "VUID-VkDescriptorSetLayoutBinding-descriptorType-02209",
383                                     "descriptorCount =(%" PRIu32 ") must be a multiple of 4", binding_info.descriptorCount);
384                 }
385                 if (binding_info.descriptorCount > inline_uniform_block_props->maxInlineUniformBlockSize) {
386                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
387                                     "VUID-VkDescriptorSetLayoutBinding-descriptorType-02210",
388                                     "descriptorCount =(%" PRIu32 ") must be less than or equal to maxInlineUniformBlockSize",
389                                     binding_info.descriptorCount);
390                 }
391             }
392         }
393 
394         total_descriptors += binding_info.descriptorCount;
395     }
396 
397     if (flags_create_info) {
398         if (flags_create_info->bindingCount != 0 && flags_create_info->bindingCount != create_info->bindingCount) {
399             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
400                             "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-bindingCount-03002",
401                             "VkDescriptorSetLayoutCreateInfo::bindingCount (%d) != "
402                             "VkDescriptorSetLayoutBindingFlagsCreateInfoEXT::bindingCount (%d)",
403                             create_info->bindingCount, flags_create_info->bindingCount);
404         }
405 
406         if (flags_create_info->bindingCount == create_info->bindingCount) {
407             for (uint32_t i = 0; i < create_info->bindingCount; ++i) {
408                 const auto &binding_info = create_info->pBindings[i];
409 
410                 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT) {
411                     if (!update_after_bind_set) {
412                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
413                                         "VUID-VkDescriptorSetLayoutCreateInfo-flags-03000",
414                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
415                     }
416 
417                     if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER &&
418                         !descriptor_indexing_features->descriptorBindingUniformBufferUpdateAfterBind) {
419                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
420                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
421                                         "descriptorBindingUniformBufferUpdateAfterBind-03005",
422                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
423                     }
424                     if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
425                          binding_info.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
426                          binding_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) &&
427                         !descriptor_indexing_features->descriptorBindingSampledImageUpdateAfterBind) {
428                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
429                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
430                                         "descriptorBindingSampledImageUpdateAfterBind-03006",
431                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
432                     }
433                     if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
434                         !descriptor_indexing_features->descriptorBindingStorageImageUpdateAfterBind) {
435                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
436                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
437                                         "descriptorBindingStorageImageUpdateAfterBind-03007",
438                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
439                     }
440                     if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER &&
441                         !descriptor_indexing_features->descriptorBindingStorageBufferUpdateAfterBind) {
442                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
443                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
444                                         "descriptorBindingStorageBufferUpdateAfterBind-03008",
445                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
446                     }
447                     if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER &&
448                         !descriptor_indexing_features->descriptorBindingUniformTexelBufferUpdateAfterBind) {
449                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
450                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
451                                         "descriptorBindingUniformTexelBufferUpdateAfterBind-03009",
452                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
453                     }
454                     if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER &&
455                         !descriptor_indexing_features->descriptorBindingStorageTexelBufferUpdateAfterBind) {
456                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
457                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
458                                         "descriptorBindingStorageTexelBufferUpdateAfterBind-03010",
459                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
460                     }
461                     if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ||
462                          binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
463                          binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
464                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
465                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-None-03011",
466                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
467                     }
468 
469                     if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT &&
470                         !inline_uniform_block_features->descriptorBindingInlineUniformBlockUpdateAfterBind) {
471                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
472                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-"
473                                         "descriptorBindingInlineUniformBlockUpdateAfterBind-02211",
474                                         "Invalid flags (VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT) for "
475                                         "VkDescriptorSetLayoutBinding entry %" PRIu32
476                                         " with descriptorBindingInlineUniformBlockUpdateAfterBind not enabled",
477                                         i);
478                     }
479                 }
480 
481                 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT) {
482                     if (!descriptor_indexing_features->descriptorBindingUpdateUnusedWhilePending) {
483                         skip |= log_msg(
484                             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
485                             "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingUpdateUnusedWhilePending-03012",
486                             "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
487                     }
488                 }
489 
490                 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT) {
491                     if (!descriptor_indexing_features->descriptorBindingPartiallyBound) {
492                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
493                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingPartiallyBound-03013",
494                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
495                     }
496                 }
497 
498                 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT) {
499                     if (binding_info.binding != max_binding) {
500                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
501                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-pBindingFlags-03004",
502                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
503                     }
504 
505                     if (!descriptor_indexing_features->descriptorBindingVariableDescriptorCount) {
506                         skip |= log_msg(
507                             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
508                             "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingVariableDescriptorCount-03014",
509                             "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
510                     }
511                     if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
512                          binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
513                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
514                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-pBindingFlags-03015",
515                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
516                     }
517                 }
518 
519                 if (push_descriptor_set &&
520                     (flags_create_info->pBindingFlags[i] &
521                      (VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT |
522                       VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT))) {
523                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
524                                     "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-flags-03003",
525                                     "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
526                 }
527             }
528         }
529     }
530 
531     if ((push_descriptor_set) && (total_descriptors > max_push_descriptors)) {
532         const char *undefined = push_descriptor_ext ? "" : " -- undefined";
533         skip |=
534             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
535                     "VUID-VkDescriptorSetLayoutCreateInfo-flags-00281",
536                     "for push descriptor, total descriptor count in layout (%" PRIu64
537                     ") must not be greater than VkPhysicalDevicePushDescriptorPropertiesKHR::maxPushDescriptors (%" PRIu32 "%s).",
538                     total_descriptors, max_push_descriptors, undefined);
539     }
540 
541     return skip;
542 }
543 
AllocateDescriptorSetsData(uint32_t count)544 cvdescriptorset::AllocateDescriptorSetsData::AllocateDescriptorSetsData(uint32_t count)
545     : required_descriptors_by_type{}, layout_nodes(count, nullptr) {}
546 
DescriptorSet(const VkDescriptorSet set,const VkDescriptorPool pool,const std::shared_ptr<DescriptorSetLayout const> & layout,uint32_t variable_count,cvdescriptorset::DescriptorSet::StateTracker * state_data)547 cvdescriptorset::DescriptorSet::DescriptorSet(const VkDescriptorSet set, const VkDescriptorPool pool,
548                                               const std::shared_ptr<DescriptorSetLayout const> &layout, uint32_t variable_count,
549                                               cvdescriptorset::DescriptorSet::StateTracker *state_data)
550     : some_update_(false),
551       set_(set),
552       pool_state_(nullptr),
553       p_layout_(layout),
554       state_data_(state_data),
555       variable_count_(variable_count),
556       change_count_(0) {
557     pool_state_ = state_data->GetDescriptorPoolState(pool);
558     // Foreach binding, create default descriptors of given type
559     descriptors_.reserve(p_layout_->GetTotalDescriptorCount());
560     for (uint32_t i = 0; i < p_layout_->GetBindingCount(); ++i) {
561         auto type = p_layout_->GetTypeFromIndex(i);
562         switch (type) {
563             case VK_DESCRIPTOR_TYPE_SAMPLER: {
564                 auto immut_sampler = p_layout_->GetImmutableSamplerPtrFromIndex(i);
565                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di) {
566                     if (immut_sampler) {
567                         descriptors_.emplace_back(new SamplerDescriptor(immut_sampler + di));
568                         some_update_ = true;  // Immutable samplers are updated at creation
569                     } else
570                         descriptors_.emplace_back(new SamplerDescriptor(nullptr));
571                 }
572                 break;
573             }
574             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
575                 auto immut = p_layout_->GetImmutableSamplerPtrFromIndex(i);
576                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di) {
577                     if (immut) {
578                         descriptors_.emplace_back(new ImageSamplerDescriptor(immut + di));
579                         some_update_ = true;  // Immutable samplers are updated at creation
580                     } else
581                         descriptors_.emplace_back(new ImageSamplerDescriptor(nullptr));
582                 }
583                 break;
584             }
585             // ImageDescriptors
586             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
587             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
588             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
589                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
590                     descriptors_.emplace_back(new ImageDescriptor(type));
591                 break;
592             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
593             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
594                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
595                     descriptors_.emplace_back(new TexelDescriptor(type));
596                 break;
597             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
598             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
599             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
600             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
601                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
602                     descriptors_.emplace_back(new BufferDescriptor(type));
603                 break;
604             case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
605                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
606                     descriptors_.emplace_back(new InlineUniformDescriptor(type));
607                 break;
608             case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
609                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
610                     descriptors_.emplace_back(new AccelerationStructureDescriptor(type));
611                 break;
612             default:
613                 assert(0);  // Bad descriptor type specified
614                 break;
615         }
616     }
617 }
618 
~DescriptorSet()619 cvdescriptorset::DescriptorSet::~DescriptorSet() { InvalidateBoundCmdBuffers(); }
620 
StringDescriptorReqViewType(descriptor_req req)621 static std::string StringDescriptorReqViewType(descriptor_req req) {
622     std::string result("");
623     for (unsigned i = 0; i <= VK_IMAGE_VIEW_TYPE_END_RANGE; i++) {
624         if (req & (1 << i)) {
625             if (result.size()) result += ", ";
626             result += string_VkImageViewType(VkImageViewType(i));
627         }
628     }
629 
630     if (!result.size()) result = "(none)";
631 
632     return result;
633 }
634 
StringDescriptorReqComponentType(descriptor_req req)635 static char const *StringDescriptorReqComponentType(descriptor_req req) {
636     if (req & DESCRIPTOR_REQ_COMPONENT_TYPE_SINT) return "SINT";
637     if (req & DESCRIPTOR_REQ_COMPONENT_TYPE_UINT) return "UINT";
638     if (req & DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT) return "FLOAT";
639     return "(none)";
640 }
641 
DescriptorRequirementsBitsFromFormat(VkFormat fmt)642 unsigned DescriptorRequirementsBitsFromFormat(VkFormat fmt) {
643     if (FormatIsSInt(fmt)) return DESCRIPTOR_REQ_COMPONENT_TYPE_SINT;
644     if (FormatIsUInt(fmt)) return DESCRIPTOR_REQ_COMPONENT_TYPE_UINT;
645     if (FormatIsDepthAndStencil(fmt)) return DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT | DESCRIPTOR_REQ_COMPONENT_TYPE_UINT;
646     if (fmt == VK_FORMAT_UNDEFINED) return 0;
647     // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
648     return DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT;
649 }
650 
651 // Validate that the state of this set is appropriate for the given bindings and dynamic_offsets at Draw time
652 //  This includes validating that all descriptors in the given bindings are updated,
653 //  that any update buffers are valid, and that any dynamic offsets are within the bounds of their buffers.
654 // Return true if state is acceptable, or false and write an error message into error string
ValidateDrawState(const DescriptorSet * descriptor_set,const std::map<uint32_t,descriptor_req> & bindings,const std::vector<uint32_t> & dynamic_offsets,const CMD_BUFFER_STATE * cb_node,const char * caller,std::string * error) const655 bool CoreChecks::ValidateDrawState(const DescriptorSet *descriptor_set, const std::map<uint32_t, descriptor_req> &bindings,
656                                    const std::vector<uint32_t> &dynamic_offsets, const CMD_BUFFER_STATE *cb_node,
657                                    const char *caller, std::string *error) const {
658     using DescriptorClass = cvdescriptorset::DescriptorClass;
659     using BufferDescriptor = cvdescriptorset::BufferDescriptor;
660     using ImageDescriptor = cvdescriptorset::ImageDescriptor;
661     using ImageSamplerDescriptor = cvdescriptorset::ImageSamplerDescriptor;
662     using SamplerDescriptor = cvdescriptorset::SamplerDescriptor;
663     using TexelDescriptor = cvdescriptorset::TexelDescriptor;
664     for (auto binding_pair : bindings) {
665         auto binding = binding_pair.first;
666         DescriptorSetLayout::ConstBindingIterator binding_it(descriptor_set->GetLayout().get(), binding);
667         if (binding_it.AtEnd()) {  //  End at construction is the condition for an invalid binding.
668             std::stringstream error_str;
669             error_str << "Attempting to validate DrawState for binding #" << binding
670                       << " which is an invalid binding for this descriptor set.";
671             *error = error_str.str();
672             return false;
673         }
674 
675         if (binding_it.GetDescriptorBindingFlags() &
676             (VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT)) {
677             // Can't validate the descriptor because it may not have been updated,
678             // or the view could have been destroyed
679             continue;
680         }
681 
682         // Copy the range, the end range is subject to update based on variable length descriptor arrays.
683         cvdescriptorset::IndexRange index_range = binding_it.GetGlobalIndexRange();
684         auto array_idx = 0;  // Track array idx if we're dealing with array descriptors
685 
686         if (binding_it.IsVariableDescriptorCount()) {
687             // Only validate the first N descriptors if it uses variable_count
688             index_range.end = index_range.start + descriptor_set->GetVariableDescriptorCount();
689         }
690 
691         for (uint32_t i = index_range.start; i < index_range.end; ++i, ++array_idx) {
692             uint32_t index = i - index_range.start;
693             const auto *descriptor = descriptor_set->GetDescriptorFromGlobalIndex(i);
694 
695             if (descriptor->GetClass() == DescriptorClass::InlineUniform) {
696                 // Can't validate the descriptor because it may not have been updated.
697                 continue;
698             } else if (!descriptor->updated) {
699                 std::stringstream error_str;
700                 error_str << "Descriptor in binding #" << binding << " index " << index
701                           << " is being used in draw but has never been updated via vkUpdateDescriptorSets() or a similar call.";
702                 *error = error_str.str();
703                 return false;
704             } else {
705                 auto descriptor_class = descriptor->GetClass();
706                 if (descriptor_class == DescriptorClass::GeneralBuffer) {
707                     // Verify that buffers are valid
708                     auto buffer = static_cast<const BufferDescriptor *>(descriptor)->GetBuffer();
709                     auto buffer_node = GetBufferState(buffer);
710                     if (!buffer_node) {
711                         std::stringstream error_str;
712                         error_str << "Descriptor in binding #" << binding << " index " << index << " references invalid buffer "
713                                   << buffer << ".";
714                         *error = error_str.str();
715                         return false;
716                     } else if (!buffer_node->sparse) {
717                         for (auto mem_binding : buffer_node->GetBoundMemory()) {
718                             if (!GetDevMemState(mem_binding)) {
719                                 std::stringstream error_str;
720                                 error_str << "Descriptor in binding #" << binding << " index " << index << " uses buffer " << buffer
721                                           << " that references invalid memory " << mem_binding << ".";
722                                 *error = error_str.str();
723                                 return false;
724                             }
725                         }
726                     }
727                     if (descriptor->IsDynamic()) {
728                         // Validate that dynamic offsets are within the buffer
729                         auto buffer_size = buffer_node->createInfo.size;
730                         auto range = static_cast<const BufferDescriptor *>(descriptor)->GetRange();
731                         auto desc_offset = static_cast<const BufferDescriptor *>(descriptor)->GetOffset();
732                         auto dyn_offset = dynamic_offsets[binding_it.GetDynamicOffsetIndex() + array_idx];
733                         if (VK_WHOLE_SIZE == range) {
734                             if ((dyn_offset + desc_offset) > buffer_size) {
735                                 std::stringstream error_str;
736                                 error_str << "Dynamic descriptor in binding #" << binding << " index " << index << " uses buffer "
737                                           << buffer << " with update range of VK_WHOLE_SIZE has dynamic offset " << dyn_offset
738                                           << " combined with offset " << desc_offset << " that oversteps the buffer size of "
739                                           << buffer_size << ".";
740                                 *error = error_str.str();
741                                 return false;
742                             }
743                         } else {
744                             if ((dyn_offset + desc_offset + range) > buffer_size) {
745                                 std::stringstream error_str;
746                                 error_str << "Dynamic descriptor in binding #" << binding << " index " << index << " uses buffer "
747                                           << buffer << " with dynamic offset " << dyn_offset << " combined with offset "
748                                           << desc_offset << " and range " << range << " that oversteps the buffer size of "
749                                           << buffer_size << ".";
750                                 *error = error_str.str();
751                                 return false;
752                             }
753                         }
754                     }
755                 } else if (descriptor_class == DescriptorClass::ImageSampler || descriptor_class == DescriptorClass::Image) {
756                     VkImageView image_view;
757                     VkImageLayout image_layout;
758                     if (descriptor_class == DescriptorClass::ImageSampler) {
759                         image_view = static_cast<const ImageSamplerDescriptor *>(descriptor)->GetImageView();
760                         image_layout = static_cast<const ImageSamplerDescriptor *>(descriptor)->GetImageLayout();
761                     } else {
762                         image_view = static_cast<const ImageDescriptor *>(descriptor)->GetImageView();
763                         image_layout = static_cast<const ImageDescriptor *>(descriptor)->GetImageLayout();
764                     }
765                     auto reqs = binding_pair.second;
766 
767                     auto image_view_state = GetImageViewState(image_view);
768                     if (nullptr == image_view_state) {
769                         // Image view must have been destroyed since initial update. Could potentially flag the descriptor
770                         //  as "invalid" (updated = false) at DestroyImageView() time and detect this error at bind time
771                         std::stringstream error_str;
772                         error_str << "Descriptor in binding #" << binding << " index " << index << " is using imageView "
773                                   << report_data->FormatHandle(image_view).c_str() << " that has been destroyed.";
774                         *error = error_str.str();
775                         return false;
776                     }
777                     const auto &image_view_ci = image_view_state->create_info;
778 
779                     if (reqs & DESCRIPTOR_REQ_ALL_VIEW_TYPE_BITS) {
780                         if (~reqs & (1 << image_view_ci.viewType)) {
781                             // bad view type
782                             std::stringstream error_str;
783                             error_str << "Descriptor in binding #" << binding << " index " << index
784                                       << " requires an image view of type " << StringDescriptorReqViewType(reqs) << " but got "
785                                       << string_VkImageViewType(image_view_ci.viewType) << ".";
786                             *error = error_str.str();
787                             return false;
788                         }
789 
790                         if (!(reqs & image_view_state->descriptor_format_bits)) {
791                             // bad component type
792                             std::stringstream error_str;
793                             error_str << "Descriptor in binding #" << binding << " index " << index << " requires "
794                                       << StringDescriptorReqComponentType(reqs)
795                                       << " component type, but bound descriptor format is " << string_VkFormat(image_view_ci.format)
796                                       << ".";
797                             *error = error_str.str();
798                             return false;
799                         }
800                     }
801 
802                     if (!disabled.image_layout_validation) {
803                         auto image_node = GetImageState(image_view_ci.image);
804                         assert(image_node);
805                         // Verify Image Layout
806                         // No "invalid layout" VUID required for this call, since the optimal_layout parameter is UNDEFINED.
807                         bool hit_error = false;
808                         VerifyImageLayout(cb_node, image_node, image_view_state->normalized_subresource_range,
809                                           image_view_ci.subresourceRange.aspectMask, image_layout, VK_IMAGE_LAYOUT_UNDEFINED,
810                                           caller, kVUIDUndefined, "VUID-VkDescriptorImageInfo-imageLayout-00344", &hit_error);
811                         if (hit_error) {
812                             *error =
813                                 "Image layout specified at vkUpdateDescriptorSet* or vkCmdPushDescriptorSet* time "
814                                 "doesn't match actual image layout at time descriptor is used. See previous error callback for "
815                                 "specific details.";
816                             return false;
817                         }
818                     }
819 
820                     // Verify Sample counts
821                     if ((reqs & DESCRIPTOR_REQ_SINGLE_SAMPLE) && image_view_state->samples != VK_SAMPLE_COUNT_1_BIT) {
822                         std::stringstream error_str;
823                         error_str << "Descriptor in binding #" << binding << " index " << index
824                                   << " requires bound image to have VK_SAMPLE_COUNT_1_BIT but got "
825                                   << string_VkSampleCountFlagBits(image_view_state->samples) << ".";
826                         *error = error_str.str();
827                         return false;
828                     }
829                     if ((reqs & DESCRIPTOR_REQ_MULTI_SAMPLE) && image_view_state->samples == VK_SAMPLE_COUNT_1_BIT) {
830                         std::stringstream error_str;
831                         error_str << "Descriptor in binding #" << binding << " index " << index
832                                   << " requires bound image to have multiple samples, but got VK_SAMPLE_COUNT_1_BIT.";
833                         *error = error_str.str();
834                         return false;
835                     }
836                 } else if (descriptor_class == DescriptorClass::TexelBuffer) {
837                     auto texel_buffer = static_cast<const TexelDescriptor *>(descriptor);
838                     auto buffer_view = GetBufferViewState(texel_buffer->GetBufferView());
839 
840                     if (nullptr == buffer_view) {
841                         std::stringstream error_str;
842                         error_str << "Descriptor in binding #" << binding << " index " << index << " is using bufferView "
843                                   << buffer_view << " that has been destroyed.";
844                         *error = error_str.str();
845                         return false;
846                     }
847                     auto buffer = buffer_view->create_info.buffer;
848                     auto buffer_state = GetBufferState(buffer);
849                     if (!buffer_state) {
850                         std::stringstream error_str;
851                         error_str << "Descriptor in binding #" << binding << " index " << index << " is using buffer "
852                                   << buffer_state << " that has been destroyed.";
853                         *error = error_str.str();
854                         return false;
855                     }
856                     auto reqs = binding_pair.second;
857                     auto format_bits = DescriptorRequirementsBitsFromFormat(buffer_view->create_info.format);
858 
859                     if (!(reqs & format_bits)) {
860                         // bad component type
861                         std::stringstream error_str;
862                         error_str << "Descriptor in binding #" << binding << " index " << index << " requires "
863                                   << StringDescriptorReqComponentType(reqs) << " component type, but bound descriptor format is "
864                                   << string_VkFormat(buffer_view->create_info.format) << ".";
865                         *error = error_str.str();
866                         return false;
867                     }
868                 }
869                 if (descriptor_class == DescriptorClass::ImageSampler || descriptor_class == DescriptorClass::PlainSampler) {
870                     // Verify Sampler still valid
871                     VkSampler sampler;
872                     if (descriptor_class == DescriptorClass::ImageSampler) {
873                         sampler = static_cast<const ImageSamplerDescriptor *>(descriptor)->GetSampler();
874                     } else {
875                         sampler = static_cast<const SamplerDescriptor *>(descriptor)->GetSampler();
876                     }
877                     if (!ValidateSampler(sampler)) {
878                         std::stringstream error_str;
879                         error_str << "Descriptor in binding #" << binding << " index " << index << " is using sampler " << sampler
880                                   << " that has been destroyed.";
881                         *error = error_str.str();
882                         return false;
883                     } else {
884                         const SAMPLER_STATE *sampler_state = GetSamplerState(sampler);
885                         if (sampler_state->samplerConversion && !descriptor->IsImmutableSampler()) {
886                             std::stringstream error_str;
887                             error_str << "sampler (" << sampler << ") in the descriptor set (" << descriptor_set->GetSet()
888                                       << ") contains a YCBCR conversion (" << sampler_state->samplerConversion
889                                       << ") , then the sampler MUST also exists as an immutable sampler.";
890                             *error = error_str.str();
891                         }
892                     }
893                 }
894             }
895         }
896     }
897     return true;
898 }
899 
900 // Set is being deleted or updates so invalidate all bound cmd buffers
InvalidateBoundCmdBuffers()901 void cvdescriptorset::DescriptorSet::InvalidateBoundCmdBuffers() {
902     state_data_->InvalidateCommandBuffers(cb_bindings, VulkanTypedHandle(set_, kVulkanObjectTypeDescriptorSet));
903 }
904 
905 // Loop through the write updates to do for a push descriptor set, ignoring dstSet
PerformPushDescriptorsUpdate(uint32_t write_count,const VkWriteDescriptorSet * p_wds)906 void cvdescriptorset::DescriptorSet::PerformPushDescriptorsUpdate(uint32_t write_count, const VkWriteDescriptorSet *p_wds) {
907     assert(IsPushDescriptor());
908     for (uint32_t i = 0; i < write_count; i++) {
909         PerformWriteUpdate(&p_wds[i]);
910     }
911 }
912 
913 // Perform write update in given update struct
PerformWriteUpdate(const VkWriteDescriptorSet * update)914 void cvdescriptorset::DescriptorSet::PerformWriteUpdate(const VkWriteDescriptorSet *update) {
915     // Perform update on a per-binding basis as consecutive updates roll over to next binding
916     auto descriptors_remaining = update->descriptorCount;
917     auto binding_being_updated = update->dstBinding;
918     auto offset = update->dstArrayElement;
919     uint32_t update_index = 0;
920     while (descriptors_remaining) {
921         uint32_t update_count = std::min(descriptors_remaining, GetDescriptorCountFromBinding(binding_being_updated));
922         auto global_idx = p_layout_->GetGlobalIndexRangeFromBinding(binding_being_updated).start + offset;
923         // Loop over the updates for a single binding at a time
924         for (uint32_t di = 0; di < update_count; ++di, ++update_index) {
925             descriptors_[global_idx + di]->WriteUpdate(update, update_index);
926         }
927         // Roll over to next binding in case of consecutive update
928         descriptors_remaining -= update_count;
929         offset = 0;
930         binding_being_updated++;
931     }
932     if (update->descriptorCount) {
933         some_update_ = true;
934         change_count_++;
935     }
936 
937     if (!(p_layout_->GetDescriptorBindingFlagsFromBinding(update->dstBinding) &
938           (VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT))) {
939         InvalidateBoundCmdBuffers();
940     }
941 }
942 // Validate Copy update
ValidateCopyUpdate(const VkCopyDescriptorSet * update,const DescriptorSet * dst_set,const DescriptorSet * src_set,const char * func_name,std::string * error_code,std::string * error_msg)943 bool CoreChecks::ValidateCopyUpdate(const VkCopyDescriptorSet *update, const DescriptorSet *dst_set, const DescriptorSet *src_set,
944                                     const char *func_name, std::string *error_code, std::string *error_msg) {
945     auto dst_layout = dst_set->GetLayout();
946     auto src_layout = src_set->GetLayout();
947 
948     // Verify dst layout still valid
949     if (dst_layout->IsDestroyed()) {
950         *error_code = "VUID-VkCopyDescriptorSet-dstSet-parameter";
951         string_sprintf(error_msg,
952                        "Cannot call %s to perform copy update on dstSet %s"
953                        " created with destroyed %s.",
954                        func_name, report_data->FormatHandle(dst_set->GetSet()).c_str(),
955                        report_data->FormatHandle(dst_layout->GetDescriptorSetLayout()).c_str());
956         return false;
957     }
958 
959     // Verify src layout still valid
960     if (src_layout->IsDestroyed()) {
961         *error_code = "VUID-VkCopyDescriptorSet-srcSet-parameter";
962         string_sprintf(error_msg,
963                        "Cannot call %s to perform copy update of dstSet %s"
964                        " from srcSet %s"
965                        " created with destroyed %s.",
966                        func_name, report_data->FormatHandle(dst_set->GetSet()).c_str(),
967                        report_data->FormatHandle(src_set->GetSet()).c_str(),
968                        report_data->FormatHandle(src_layout->GetDescriptorSetLayout()).c_str());
969         return false;
970     }
971 
972     if (!dst_layout->HasBinding(update->dstBinding)) {
973         *error_code = "VUID-VkCopyDescriptorSet-dstBinding-00347";
974         std::stringstream error_str;
975         error_str << "DescriptorSet " << dst_set->GetSet() << " does not have copy update dest binding of " << update->dstBinding;
976         *error_msg = error_str.str();
977         return false;
978     }
979     if (!src_set->HasBinding(update->srcBinding)) {
980         *error_code = "VUID-VkCopyDescriptorSet-srcBinding-00345";
981         std::stringstream error_str;
982         error_str << "DescriptorSet " << dst_set->GetSet() << " does not have copy update src binding of " << update->srcBinding;
983         *error_msg = error_str.str();
984         return false;
985     }
986     // Verify idle ds
987     if (dst_set->in_use.load() &&
988         !(dst_layout->GetDescriptorBindingFlagsFromBinding(update->dstBinding) &
989           (VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT))) {
990         // TODO : Re-using Free Idle error code, need copy update idle error code
991         *error_code = "VUID-vkFreeDescriptorSets-pDescriptorSets-00309";
992         std::stringstream error_str;
993         error_str << "Cannot call " << func_name << " to perform copy update on descriptor set " << dst_set->GetSet()
994                   << " that is in use by a command buffer";
995         *error_msg = error_str.str();
996         return false;
997     }
998     // src & dst set bindings are valid
999     // Check bounds of src & dst
1000     auto src_start_idx = src_set->GetGlobalIndexRangeFromBinding(update->srcBinding).start + update->srcArrayElement;
1001     if ((src_start_idx + update->descriptorCount) > src_set->GetTotalDescriptorCount()) {
1002         // SRC update out of bounds
1003         *error_code = "VUID-VkCopyDescriptorSet-srcArrayElement-00346";
1004         std::stringstream error_str;
1005         error_str << "Attempting copy update from descriptorSet " << update->srcSet << " binding#" << update->srcBinding
1006                   << " with offset index of " << src_set->GetGlobalIndexRangeFromBinding(update->srcBinding).start
1007                   << " plus update array offset of " << update->srcArrayElement << " and update of " << update->descriptorCount
1008                   << " descriptors oversteps total number of descriptors in set: " << src_set->GetTotalDescriptorCount();
1009         *error_msg = error_str.str();
1010         return false;
1011     }
1012     auto dst_start_idx = dst_layout->GetGlobalIndexRangeFromBinding(update->dstBinding).start + update->dstArrayElement;
1013     if ((dst_start_idx + update->descriptorCount) > dst_layout->GetTotalDescriptorCount()) {
1014         // DST update out of bounds
1015         *error_code = "VUID-VkCopyDescriptorSet-dstArrayElement-00348";
1016         std::stringstream error_str;
1017         error_str << "Attempting copy update to descriptorSet " << dst_set->GetSet() << " binding#" << update->dstBinding
1018                   << " with offset index of " << dst_layout->GetGlobalIndexRangeFromBinding(update->dstBinding).start
1019                   << " plus update array offset of " << update->dstArrayElement << " and update of " << update->descriptorCount
1020                   << " descriptors oversteps total number of descriptors in set: " << dst_layout->GetTotalDescriptorCount();
1021         *error_msg = error_str.str();
1022         return false;
1023     }
1024     // Check that types match
1025     // TODO : Base default error case going from here is "VUID-VkAcquireNextImageInfoKHR-semaphore-parameter"2ba which covers all
1026     // consistency issues, need more fine-grained error codes
1027     *error_code = "VUID-VkCopyDescriptorSet-srcSet-00349";
1028     auto src_type = src_set->GetTypeFromBinding(update->srcBinding);
1029     auto dst_type = dst_layout->GetTypeFromBinding(update->dstBinding);
1030     if (src_type != dst_type) {
1031         std::stringstream error_str;
1032         error_str << "Attempting copy update to descriptorSet " << dst_set->GetSet() << " binding #" << update->dstBinding
1033                   << " with type " << string_VkDescriptorType(dst_type) << " from descriptorSet " << src_set->GetSet()
1034                   << " binding #" << update->srcBinding << " with type " << string_VkDescriptorType(src_type)
1035                   << ". Types do not match";
1036         *error_msg = error_str.str();
1037         return false;
1038     }
1039     // Verify consistency of src & dst bindings if update crosses binding boundaries
1040     if ((!VerifyUpdateConsistency(DescriptorSetLayout::ConstBindingIterator(src_layout.get(), update->srcBinding),
1041                                   update->srcArrayElement, update->descriptorCount, "copy update from", src_set->GetSet(),
1042                                   error_msg)) ||
1043         (!VerifyUpdateConsistency(DescriptorSetLayout::ConstBindingIterator(dst_layout.get(), update->dstBinding),
1044                                   update->dstArrayElement, update->descriptorCount, "copy update to", dst_set->GetSet(),
1045                                   error_msg))) {
1046         return false;
1047     }
1048 
1049     if ((src_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT) &&
1050         !(dst_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT)) {
1051         *error_code = "VUID-VkCopyDescriptorSet-srcSet-01918";
1052         std::stringstream error_str;
1053         error_str << "If pname:srcSet's (" << update->srcSet
1054                   << ") layout was created with the "
1055                      "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT flag "
1056                      "set, then pname:dstSet's ("
1057                   << update->dstSet
1058                   << ") layout must: also have been created with the "
1059                      "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT flag set";
1060         *error_msg = error_str.str();
1061         return false;
1062     }
1063 
1064     if (!(src_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT) &&
1065         (dst_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT)) {
1066         *error_code = "VUID-VkCopyDescriptorSet-srcSet-01919";
1067         std::stringstream error_str;
1068         error_str << "If pname:srcSet's (" << update->srcSet
1069                   << ") layout was created without the "
1070                      "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT flag "
1071                      "set, then pname:dstSet's ("
1072                   << update->dstSet
1073                   << ") layout must: also have been created without the "
1074                      "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT flag set";
1075         *error_msg = error_str.str();
1076         return false;
1077     }
1078 
1079     if ((src_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT) &&
1080         !(dst_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT)) {
1081         *error_code = "VUID-VkCopyDescriptorSet-srcSet-01920";
1082         std::stringstream error_str;
1083         error_str << "If the descriptor pool from which pname:srcSet (" << update->srcSet
1084                   << ") was allocated was created "
1085                      "with the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT flag "
1086                      "set, then the descriptor pool from which pname:dstSet ("
1087                   << update->dstSet
1088                   << ") was allocated must: "
1089                      "also have been created with the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT flag set";
1090         *error_msg = error_str.str();
1091         return false;
1092     }
1093 
1094     if (!(src_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT) &&
1095         (dst_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT)) {
1096         *error_code = "VUID-VkCopyDescriptorSet-srcSet-01921";
1097         std::stringstream error_str;
1098         error_str << "If the descriptor pool from which pname:srcSet (" << update->srcSet
1099                   << ") was allocated was created "
1100                      "without the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT flag "
1101                      "set, then the descriptor pool from which pname:dstSet ("
1102                   << update->dstSet
1103                   << ") was allocated must: "
1104                      "also have been created without the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT flag set";
1105         *error_msg = error_str.str();
1106         return false;
1107     }
1108 
1109     if (src_type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
1110         if ((update->srcArrayElement % 4) != 0) {
1111             *error_code = "VUID-VkCopyDescriptorSet-srcBinding-02223";
1112             std::stringstream error_str;
1113             error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
1114                       << "srcArrayElement " << update->srcArrayElement << " not a multiple of 4";
1115             *error_msg = error_str.str();
1116             return false;
1117         }
1118         if ((update->dstArrayElement % 4) != 0) {
1119             *error_code = "VUID-VkCopyDescriptorSet-dstBinding-02224";
1120             std::stringstream error_str;
1121             error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
1122                       << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
1123             *error_msg = error_str.str();
1124             return false;
1125         }
1126         if ((update->descriptorCount % 4) != 0) {
1127             *error_code = "VUID-VkCopyDescriptorSet-srcBinding-02225";
1128             std::stringstream error_str;
1129             error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
1130                       << "descriptorCount " << update->descriptorCount << " not a multiple of 4";
1131             *error_msg = error_str.str();
1132             return false;
1133         }
1134     }
1135 
1136     // Update parameters all look good and descriptor updated so verify update contents
1137     if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, func_name, error_code, error_msg)) return false;
1138 
1139     // All checks passed so update is good
1140     return true;
1141 }
1142 // Perform Copy update
PerformCopyUpdate(const VkCopyDescriptorSet * update,const DescriptorSet * src_set)1143 void cvdescriptorset::DescriptorSet::PerformCopyUpdate(const VkCopyDescriptorSet *update, const DescriptorSet *src_set) {
1144     auto src_start_idx = src_set->GetGlobalIndexRangeFromBinding(update->srcBinding).start + update->srcArrayElement;
1145     auto dst_start_idx = p_layout_->GetGlobalIndexRangeFromBinding(update->dstBinding).start + update->dstArrayElement;
1146     // Update parameters all look good so perform update
1147     for (uint32_t di = 0; di < update->descriptorCount; ++di) {
1148         auto src = src_set->descriptors_[src_start_idx + di].get();
1149         auto dst = descriptors_[dst_start_idx + di].get();
1150         if (src->updated) {
1151             dst->CopyUpdate(src);
1152             some_update_ = true;
1153             change_count_++;
1154         } else {
1155             dst->updated = false;
1156         }
1157     }
1158 
1159     if (!(p_layout_->GetDescriptorBindingFlagsFromBinding(update->dstBinding) &
1160           (VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT))) {
1161         InvalidateBoundCmdBuffers();
1162     }
1163 }
1164 
1165 // Update the drawing state for the affected descriptors.
1166 // Set cb_node to this set and this set to cb_node.
1167 // Add the bindings of the descriptor
1168 // Set the layout based on the current descriptor layout (will mask subsequent layer mismatch errors)
1169 // TODO: Modify the UpdateDrawState virtural functions to *only* set initial layout and not change layouts
1170 // Prereq: This should be called for a set that has been confirmed to be active for the given cb_node, meaning it's going
1171 //   to be used in a draw by the given cb_node
UpdateDrawState(ValidationStateTracker * device_data,CMD_BUFFER_STATE * cb_node,const std::map<uint32_t,descriptor_req> & binding_req_map)1172 void cvdescriptorset::DescriptorSet::UpdateDrawState(ValidationStateTracker *device_data, CMD_BUFFER_STATE *cb_node,
1173                                                      const std::map<uint32_t, descriptor_req> &binding_req_map) {
1174     if (!device_data->disabled.command_buffer_state) {
1175         // bind cb to this descriptor set
1176         // Add bindings for descriptor set, the set's pool, and individual objects in the set
1177         auto inserted = cb_node->object_bindings.emplace(set_, kVulkanObjectTypeDescriptorSet);
1178         if (inserted.second) {
1179             cb_bindings.insert(cb_node);
1180             auto inserted2 = cb_node->object_bindings.emplace(pool_state_->pool, kVulkanObjectTypeDescriptorPool);
1181             if (inserted2.second) {
1182                 pool_state_->cb_bindings.insert(cb_node);
1183             }
1184         }
1185     }
1186 
1187     // Descriptor UpdateDrawState functions do two things - associate resources to the command buffer,
1188     // and call image layout validation callbacks. If both are disabled, skip the entire loop.
1189     if (device_data->disabled.command_buffer_state && device_data->disabled.image_layout_validation) {
1190         return;
1191     }
1192 
1193     // For the active slots, use set# to look up descriptorSet from boundDescriptorSets, and bind all of that descriptor set's
1194     // resources
1195     for (auto binding_req_pair : binding_req_map) {
1196         auto binding = binding_req_pair.first;
1197         // We aren't validating descriptors created with PARTIALLY_BOUND or UPDATE_AFTER_BIND, so don't record state
1198         if (p_layout_->GetDescriptorBindingFlagsFromBinding(binding) &
1199             (VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT)) {
1200             continue;
1201         }
1202         auto range = p_layout_->GetGlobalIndexRangeFromBinding(binding);
1203         for (uint32_t i = range.start; i < range.end; ++i) {
1204             descriptors_[i]->UpdateDrawState(device_data, cb_node);
1205         }
1206     }
1207 }
1208 
FilterOneBindingReq(const BindingReqMap::value_type & binding_req_pair,BindingReqMap * out_req,const TrackedBindings & bindings,uint32_t limit)1209 void cvdescriptorset::DescriptorSet::FilterOneBindingReq(const BindingReqMap::value_type &binding_req_pair, BindingReqMap *out_req,
1210                                                          const TrackedBindings &bindings, uint32_t limit) {
1211     if (bindings.size() < limit) {
1212         const auto it = bindings.find(binding_req_pair.first);
1213         if (it == bindings.cend()) out_req->emplace(binding_req_pair);
1214     }
1215 }
1216 
FilterBindingReqs(const CMD_BUFFER_STATE & cb_state,const PIPELINE_STATE & pipeline,const BindingReqMap & in_req,BindingReqMap * out_req) const1217 void cvdescriptorset::DescriptorSet::FilterBindingReqs(const CMD_BUFFER_STATE &cb_state, const PIPELINE_STATE &pipeline,
1218                                                        const BindingReqMap &in_req, BindingReqMap *out_req) const {
1219     // For const cleanliness we have to find in the maps...
1220     const auto validated_it = cached_validation_.find(&cb_state);
1221     if (validated_it == cached_validation_.cend()) {
1222         // We have nothing validated, copy in to out
1223         for (const auto &binding_req_pair : in_req) {
1224             out_req->emplace(binding_req_pair);
1225         }
1226         return;
1227     }
1228     const auto &validated = validated_it->second;
1229 
1230     const auto image_sample_version_it = validated.image_samplers.find(&pipeline);
1231     const VersionedBindings *image_sample_version = nullptr;
1232     if (image_sample_version_it != validated.image_samplers.cend()) {
1233         image_sample_version = &(image_sample_version_it->second);
1234     }
1235     const auto &dynamic_buffers = validated.dynamic_buffers;
1236     const auto &non_dynamic_buffers = validated.non_dynamic_buffers;
1237     const auto &stats = p_layout_->GetBindingTypeStats();
1238     for (const auto &binding_req_pair : in_req) {
1239         auto binding = binding_req_pair.first;
1240         VkDescriptorSetLayoutBinding const *layout_binding = p_layout_->GetDescriptorSetLayoutBindingPtrFromBinding(binding);
1241         if (!layout_binding) {
1242             continue;
1243         }
1244         // Caching criteria differs per type.
1245         // If image_layout have changed , the image descriptors need to be validated against them.
1246         if ((layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
1247             (layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
1248             FilterOneBindingReq(binding_req_pair, out_req, dynamic_buffers, stats.dynamic_buffer_count);
1249         } else if ((layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
1250                    (layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) {
1251             FilterOneBindingReq(binding_req_pair, out_req, non_dynamic_buffers, stats.non_dynamic_buffer_count);
1252         } else {
1253             // This is rather crude, as the changed layouts may not impact the bound descriptors,
1254             // but the simple "versioning" is a simple "dirt" test.
1255             bool stale = true;
1256             if (image_sample_version) {
1257                 const auto version_it = image_sample_version->find(binding);
1258                 if (version_it != image_sample_version->cend() && (version_it->second == cb_state.image_layout_change_count)) {
1259                     stale = false;
1260                 }
1261             }
1262             if (stale) {
1263                 out_req->emplace(binding_req_pair);
1264             }
1265         }
1266     }
1267 }
1268 
UpdateValidationCache(const CMD_BUFFER_STATE & cb_state,const PIPELINE_STATE & pipeline,const BindingReqMap & updated_bindings)1269 void cvdescriptorset::DescriptorSet::UpdateValidationCache(const CMD_BUFFER_STATE &cb_state, const PIPELINE_STATE &pipeline,
1270                                                            const BindingReqMap &updated_bindings) {
1271     // For const cleanliness we have to find in the maps...
1272     auto &validated = cached_validation_[&cb_state];
1273 
1274     auto &image_sample_version = validated.image_samplers[&pipeline];
1275     auto &dynamic_buffers = validated.dynamic_buffers;
1276     auto &non_dynamic_buffers = validated.non_dynamic_buffers;
1277     for (const auto &binding_req_pair : updated_bindings) {
1278         auto binding = binding_req_pair.first;
1279         VkDescriptorSetLayoutBinding const *layout_binding = p_layout_->GetDescriptorSetLayoutBindingPtrFromBinding(binding);
1280         if (!layout_binding) {
1281             continue;
1282         }
1283         // Caching criteria differs per type.
1284         if ((layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
1285             (layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
1286             dynamic_buffers.emplace(binding);
1287         } else if ((layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
1288                    (layout_binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) {
1289             non_dynamic_buffers.emplace(binding);
1290         } else {
1291             // Save the layout change version...
1292             image_sample_version[binding] = cb_state.image_layout_change_count;
1293         }
1294     }
1295 }
1296 
SamplerDescriptor(const VkSampler * immut)1297 cvdescriptorset::SamplerDescriptor::SamplerDescriptor(const VkSampler *immut) : sampler_(VK_NULL_HANDLE), immutable_(false) {
1298     updated = false;
1299     descriptor_class = PlainSampler;
1300     if (immut) {
1301         sampler_ = *immut;
1302         immutable_ = true;
1303         updated = true;
1304     }
1305 }
1306 // Validate given sampler. Currently this only checks to make sure it exists in the samplerMap
ValidateSampler(const VkSampler sampler) const1307 bool CoreChecks::ValidateSampler(const VkSampler sampler) const { return (GetSamplerState(sampler) != nullptr); }
1308 
ValidateImageUpdate(VkImageView image_view,VkImageLayout image_layout,VkDescriptorType type,const char * func_name,std::string * error_code,std::string * error_msg)1309 bool CoreChecks::ValidateImageUpdate(VkImageView image_view, VkImageLayout image_layout, VkDescriptorType type,
1310                                      const char *func_name, std::string *error_code, std::string *error_msg) {
1311     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00326";
1312     auto iv_state = GetImageViewState(image_view);
1313     assert(iv_state);
1314 
1315     // Note that when an imageview is created, we validated that memory is bound so no need to re-check here
1316     // Validate that imageLayout is compatible with aspect_mask and image format
1317     //  and validate that image usage bits are correct for given usage
1318     VkImageAspectFlags aspect_mask = iv_state->create_info.subresourceRange.aspectMask;
1319     VkImage image = iv_state->create_info.image;
1320     VkFormat format = VK_FORMAT_MAX_ENUM;
1321     VkImageUsageFlags usage = 0;
1322     auto image_node = GetImageState(image);
1323     assert(image_node);
1324 
1325     format = image_node->createInfo.format;
1326     usage = image_node->createInfo.usage;
1327     // Validate that memory is bound to image
1328     // TODO: This should have its own valid usage id apart from 2524 which is from CreateImageView case. The only
1329     //  the error here occurs is if memory bound to a created imageView has been freed.
1330     if (ValidateMemoryIsBoundToImage(image_node, func_name, "VUID-VkImageViewCreateInfo-image-01020")) {
1331         *error_code = "VUID-VkImageViewCreateInfo-image-01020";
1332         *error_msg = "No memory bound to image.";
1333         return false;
1334     }
1335 
1336     // KHR_maintenance1 allows rendering into 2D or 2DArray views which slice a 3D image,
1337     // but not binding them to descriptor sets.
1338     if (image_node->createInfo.imageType == VK_IMAGE_TYPE_3D && (iv_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_2D ||
1339                                                                  iv_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
1340         *error_code = "VUID-VkDescriptorImageInfo-imageView-00343";
1341         *error_msg = "ImageView must not be a 2D or 2DArray view of a 3D image";
1342         return false;
1343     }
1344 
1345     // TODO : The various image aspect and format checks here are based on general spec language in 11.5 Image Views section under
1346     // vkCreateImageView(). What's the best way to create unique id for these cases?
1347     *error_code = "UNASSIGNED-CoreValidation-DrawState-InvalidImageView";
1348     bool ds = FormatIsDepthOrStencil(format);
1349     switch (image_layout) {
1350         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
1351             // Only Color bit must be set
1352             if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
1353                 std::stringstream error_str;
1354                 error_str
1355                     << "ImageView (" << report_data->FormatHandle(image_view).c_str()
1356                     << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but does not have VK_IMAGE_ASPECT_COLOR_BIT set.";
1357                 *error_msg = error_str.str();
1358                 return false;
1359             }
1360             // format must NOT be DS
1361             if (ds) {
1362                 std::stringstream error_str;
1363                 error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str()
1364                           << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but the image format is "
1365                           << string_VkFormat(format) << " which is not a color format.";
1366                 *error_msg = error_str.str();
1367                 return false;
1368             }
1369             break;
1370         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
1371         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
1372             // Depth or stencil bit must be set, but both must NOT be set
1373             if (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
1374                 if (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
1375                     // both  must NOT be set
1376                     std::stringstream error_str;
1377                     error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str()
1378                               << ") has both STENCIL and DEPTH aspects set";
1379                     *error_msg = error_str.str();
1380                     return false;
1381                 }
1382             } else if (!(aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
1383                 // Neither were set
1384                 std::stringstream error_str;
1385                 error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str() << ") has layout "
1386                           << string_VkImageLayout(image_layout) << " but does not have STENCIL or DEPTH aspects set";
1387                 *error_msg = error_str.str();
1388                 return false;
1389             }
1390             // format must be DS
1391             if (!ds) {
1392                 std::stringstream error_str;
1393                 error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str() << ") has layout "
1394                           << string_VkImageLayout(image_layout) << " but the image format is " << string_VkFormat(format)
1395                           << " which is not a depth/stencil format.";
1396                 *error_msg = error_str.str();
1397                 return false;
1398             }
1399             break;
1400         default:
1401             // For other layouts if the source is depth/stencil image, both aspect bits must not be set
1402             if (ds) {
1403                 if (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
1404                     if (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
1405                         // both  must NOT be set
1406                         std::stringstream error_str;
1407                         error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str() << ") has layout "
1408                                   << string_VkImageLayout(image_layout) << " and is using depth/stencil image of format "
1409                                   << string_VkFormat(format)
1410                                   << " but it has both STENCIL and DEPTH aspects set, which is illegal. When using a depth/stencil "
1411                                      "image in a descriptor set, please only set either VK_IMAGE_ASPECT_DEPTH_BIT or "
1412                                      "VK_IMAGE_ASPECT_STENCIL_BIT depending on whether it will be used for depth reads or stencil "
1413                                      "reads respectively.";
1414                         *error_code = "VUID-VkDescriptorImageInfo-imageView-01976";
1415                         *error_msg = error_str.str();
1416                         return false;
1417                     }
1418                 }
1419             }
1420             break;
1421     }
1422     // Now validate that usage flags are correctly set for given type of update
1423     //  As we're switching per-type, if any type has specific layout requirements, check those here as well
1424     // TODO : The various image usage bit requirements are in general spec language for VkImageUsageFlags bit block in 11.3 Images
1425     // under vkCreateImage()
1426     // TODO : Need to also validate case "VUID-VkWriteDescriptorSet-descriptorType-00336" where STORAGE_IMAGE & INPUT_ATTACH types
1427     // must have been created with identify swizzle
1428     const char *error_usage_bit = nullptr;
1429     switch (type) {
1430         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1431         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
1432             if (!(usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
1433                 error_usage_bit = "VK_IMAGE_USAGE_SAMPLED_BIT";
1434             }
1435             break;
1436         }
1437         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
1438             if (!(usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
1439                 error_usage_bit = "VK_IMAGE_USAGE_STORAGE_BIT";
1440             } else if (VK_IMAGE_LAYOUT_GENERAL != image_layout) {
1441                 std::stringstream error_str;
1442                 // TODO : Need to create custom enum error codes for these cases
1443                 if (image_node->shared_presentable) {
1444                     if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != image_layout) {
1445                         error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str()
1446                                   << ") of VK_DESCRIPTOR_TYPE_STORAGE_IMAGE type with a front-buffered image is being updated with "
1447                                      "layout "
1448                                   << string_VkImageLayout(image_layout)
1449                                   << " but according to spec section 13.1 Descriptor Types, 'Front-buffered images that report "
1450                                      "support for VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT must be in the "
1451                                      "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR layout.'";
1452                         *error_msg = error_str.str();
1453                         return false;
1454                     }
1455                 } else if (VK_IMAGE_LAYOUT_GENERAL != image_layout) {
1456                     error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str()
1457                               << ") of VK_DESCRIPTOR_TYPE_STORAGE_IMAGE type is being updated with layout "
1458                               << string_VkImageLayout(image_layout)
1459                               << " but according to spec section 13.1 Descriptor Types, 'Load and store operations on storage "
1460                                  "images can only be done on images in VK_IMAGE_LAYOUT_GENERAL layout.'";
1461                     *error_msg = error_str.str();
1462                     return false;
1463                 }
1464             }
1465             break;
1466         }
1467         case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
1468             if (!(usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) {
1469                 error_usage_bit = "VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT";
1470             }
1471             break;
1472         }
1473         default:
1474             break;
1475     }
1476     if (error_usage_bit) {
1477         std::stringstream error_str;
1478         error_str << "ImageView (" << report_data->FormatHandle(image_view).c_str() << ") with usage mask " << std::hex
1479                   << std::showbase << usage << " being used for a descriptor update of type " << string_VkDescriptorType(type)
1480                   << " does not have " << error_usage_bit << " set.";
1481         *error_msg = error_str.str();
1482         return false;
1483     }
1484 
1485     if ((type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) || (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
1486         // Test that the layout is compatible with the descriptorType for the two sampled image types
1487         const static std::array<VkImageLayout, 3> valid_layouts = {
1488             {VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL}};
1489 
1490         struct ExtensionLayout {
1491             VkImageLayout layout;
1492             bool DeviceExtensions::*extension;
1493         };
1494 
1495         const static std::array<ExtensionLayout, 3> extended_layouts{
1496             {//  Note double brace req'd for aggregate initialization
1497              {VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, &DeviceExtensions::vk_khr_shared_presentable_image},
1498              {VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, &DeviceExtensions::vk_khr_maintenance2},
1499              {VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, &DeviceExtensions::vk_khr_maintenance2}}};
1500         auto is_layout = [image_layout, this](const ExtensionLayout &ext_layout) {
1501             return device_extensions.*(ext_layout.extension) && (ext_layout.layout == image_layout);
1502         };
1503 
1504         bool valid_layout = (std::find(valid_layouts.cbegin(), valid_layouts.cend(), image_layout) != valid_layouts.cend()) ||
1505                             std::any_of(extended_layouts.cbegin(), extended_layouts.cend(), is_layout);
1506 
1507         if (!valid_layout) {
1508             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-01403";
1509             std::stringstream error_str;
1510             error_str << "Descriptor update with descriptorType " << string_VkDescriptorType(type)
1511                       << " is being updated with invalid imageLayout " << string_VkImageLayout(image_layout) << " for image "
1512                       << report_data->FormatHandle(image).c_str() << " in imageView "
1513                       << report_data->FormatHandle(image_view).c_str()
1514                       << ". Allowed layouts are: VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "
1515                       << "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL";
1516             for (auto &ext_layout : extended_layouts) {
1517                 if (device_extensions.*(ext_layout.extension)) {
1518                     error_str << ", " << string_VkImageLayout(ext_layout.layout);
1519                 }
1520             }
1521             *error_msg = error_str.str();
1522             return false;
1523         }
1524     }
1525 
1526     return true;
1527 }
1528 
WriteUpdate(const VkWriteDescriptorSet * update,const uint32_t index)1529 void cvdescriptorset::SamplerDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
1530     if (!immutable_) {
1531         sampler_ = update->pImageInfo[index].sampler;
1532     }
1533     updated = true;
1534 }
1535 
CopyUpdate(const Descriptor * src)1536 void cvdescriptorset::SamplerDescriptor::CopyUpdate(const Descriptor *src) {
1537     if (!immutable_) {
1538         auto update_sampler = static_cast<const SamplerDescriptor *>(src)->sampler_;
1539         sampler_ = update_sampler;
1540     }
1541     updated = true;
1542 }
1543 
UpdateDrawState(ValidationStateTracker * dev_data,CMD_BUFFER_STATE * cb_node)1544 void cvdescriptorset::SamplerDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, CMD_BUFFER_STATE *cb_node) {
1545     if (!immutable_) {
1546         auto sampler_state = dev_data->GetSamplerState(sampler_);
1547         if (sampler_state) dev_data->AddCommandBufferBindingSampler(cb_node, sampler_state);
1548     }
1549 }
1550 
ImageSamplerDescriptor(const VkSampler * immut)1551 cvdescriptorset::ImageSamplerDescriptor::ImageSamplerDescriptor(const VkSampler *immut)
1552     : sampler_(VK_NULL_HANDLE), immutable_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
1553     updated = false;
1554     descriptor_class = ImageSampler;
1555     if (immut) {
1556         sampler_ = *immut;
1557         immutable_ = true;
1558     }
1559 }
1560 
WriteUpdate(const VkWriteDescriptorSet * update,const uint32_t index)1561 void cvdescriptorset::ImageSamplerDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
1562     updated = true;
1563     const auto &image_info = update->pImageInfo[index];
1564     if (!immutable_) {
1565         sampler_ = image_info.sampler;
1566     }
1567     image_view_ = image_info.imageView;
1568     image_layout_ = image_info.imageLayout;
1569 }
1570 
CopyUpdate(const Descriptor * src)1571 void cvdescriptorset::ImageSamplerDescriptor::CopyUpdate(const Descriptor *src) {
1572     if (!immutable_) {
1573         auto update_sampler = static_cast<const ImageSamplerDescriptor *>(src)->sampler_;
1574         sampler_ = update_sampler;
1575     }
1576     auto image_view = static_cast<const ImageSamplerDescriptor *>(src)->image_view_;
1577     auto image_layout = static_cast<const ImageSamplerDescriptor *>(src)->image_layout_;
1578     updated = true;
1579     image_view_ = image_view;
1580     image_layout_ = image_layout;
1581 }
1582 
UpdateDrawState(ValidationStateTracker * dev_data,CMD_BUFFER_STATE * cb_node)1583 void cvdescriptorset::ImageSamplerDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, CMD_BUFFER_STATE *cb_node) {
1584     // First add binding for any non-immutable sampler
1585     if (!immutable_) {
1586         auto sampler_state = dev_data->GetSamplerState(sampler_);
1587         if (sampler_state) dev_data->AddCommandBufferBindingSampler(cb_node, sampler_state);
1588     }
1589     // Add binding for image
1590     auto iv_state = dev_data->GetImageViewState(image_view_);
1591     if (iv_state) {
1592         dev_data->AddCommandBufferBindingImageView(cb_node, iv_state);
1593         dev_data->CallSetImageViewInitialLayoutCallback(cb_node, *iv_state, image_layout_);
1594     }
1595 }
1596 
ImageDescriptor(const VkDescriptorType type)1597 cvdescriptorset::ImageDescriptor::ImageDescriptor(const VkDescriptorType type)
1598     : storage_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
1599     updated = false;
1600     descriptor_class = Image;
1601     if (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE == type) storage_ = true;
1602 }
1603 
WriteUpdate(const VkWriteDescriptorSet * update,const uint32_t index)1604 void cvdescriptorset::ImageDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
1605     updated = true;
1606     const auto &image_info = update->pImageInfo[index];
1607     image_view_ = image_info.imageView;
1608     image_layout_ = image_info.imageLayout;
1609 }
1610 
CopyUpdate(const Descriptor * src)1611 void cvdescriptorset::ImageDescriptor::CopyUpdate(const Descriptor *src) {
1612     auto image_view = static_cast<const ImageDescriptor *>(src)->image_view_;
1613     auto image_layout = static_cast<const ImageDescriptor *>(src)->image_layout_;
1614     updated = true;
1615     image_view_ = image_view;
1616     image_layout_ = image_layout;
1617 }
1618 
UpdateDrawState(ValidationStateTracker * dev_data,CMD_BUFFER_STATE * cb_node)1619 void cvdescriptorset::ImageDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, CMD_BUFFER_STATE *cb_node) {
1620     // Add binding for image
1621     auto iv_state = dev_data->GetImageViewState(image_view_);
1622     if (iv_state) {
1623         dev_data->AddCommandBufferBindingImageView(cb_node, iv_state);
1624         dev_data->CallSetImageViewInitialLayoutCallback(cb_node, *iv_state, image_layout_);
1625     }
1626 }
1627 
BufferDescriptor(const VkDescriptorType type)1628 cvdescriptorset::BufferDescriptor::BufferDescriptor(const VkDescriptorType type)
1629     : storage_(false), dynamic_(false), buffer_(VK_NULL_HANDLE), offset_(0), range_(0) {
1630     updated = false;
1631     descriptor_class = GeneralBuffer;
1632     if (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == type) {
1633         dynamic_ = true;
1634     } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == type) {
1635         storage_ = true;
1636     } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == type) {
1637         dynamic_ = true;
1638         storage_ = true;
1639     }
1640 }
WriteUpdate(const VkWriteDescriptorSet * update,const uint32_t index)1641 void cvdescriptorset::BufferDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
1642     updated = true;
1643     const auto &buffer_info = update->pBufferInfo[index];
1644     buffer_ = buffer_info.buffer;
1645     offset_ = buffer_info.offset;
1646     range_ = buffer_info.range;
1647 }
1648 
CopyUpdate(const Descriptor * src)1649 void cvdescriptorset::BufferDescriptor::CopyUpdate(const Descriptor *src) {
1650     auto buff_desc = static_cast<const BufferDescriptor *>(src);
1651     updated = true;
1652     buffer_ = buff_desc->buffer_;
1653     offset_ = buff_desc->offset_;
1654     range_ = buff_desc->range_;
1655 }
1656 
UpdateDrawState(ValidationStateTracker * dev_data,CMD_BUFFER_STATE * cb_node)1657 void cvdescriptorset::BufferDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, CMD_BUFFER_STATE *cb_node) {
1658     auto buffer_node = dev_data->GetBufferState(buffer_);
1659     if (buffer_node) dev_data->AddCommandBufferBindingBuffer(cb_node, buffer_node);
1660 }
1661 
TexelDescriptor(const VkDescriptorType type)1662 cvdescriptorset::TexelDescriptor::TexelDescriptor(const VkDescriptorType type) : buffer_view_(VK_NULL_HANDLE), storage_(false) {
1663     updated = false;
1664     descriptor_class = TexelBuffer;
1665     if (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER == type) storage_ = true;
1666 }
1667 
WriteUpdate(const VkWriteDescriptorSet * update,const uint32_t index)1668 void cvdescriptorset::TexelDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
1669     updated = true;
1670     buffer_view_ = update->pTexelBufferView[index];
1671 }
1672 
CopyUpdate(const Descriptor * src)1673 void cvdescriptorset::TexelDescriptor::CopyUpdate(const Descriptor *src) {
1674     updated = true;
1675     buffer_view_ = static_cast<const TexelDescriptor *>(src)->buffer_view_;
1676 }
1677 
UpdateDrawState(ValidationStateTracker * dev_data,CMD_BUFFER_STATE * cb_node)1678 void cvdescriptorset::TexelDescriptor::UpdateDrawState(ValidationStateTracker *dev_data, CMD_BUFFER_STATE *cb_node) {
1679     auto bv_state = dev_data->GetBufferViewState(buffer_view_);
1680     if (bv_state) {
1681         dev_data->AddCommandBufferBindingBufferView(cb_node, bv_state);
1682     }
1683 }
1684 
1685 // This is a helper function that iterates over a set of Write and Copy updates, pulls the DescriptorSet* for updated
1686 //  sets, and then calls their respective Validate[Write|Copy]Update functions.
1687 // If the update hits an issue for which the callback returns "true", meaning that the call down the chain should
1688 //  be skipped, then true is returned.
1689 // If there is no issue with the update, then false is returned.
ValidateUpdateDescriptorSets(uint32_t write_count,const VkWriteDescriptorSet * p_wds,uint32_t copy_count,const VkCopyDescriptorSet * p_cds,const char * func_name)1690 bool CoreChecks::ValidateUpdateDescriptorSets(uint32_t write_count, const VkWriteDescriptorSet *p_wds, uint32_t copy_count,
1691                                               const VkCopyDescriptorSet *p_cds, const char *func_name) {
1692     bool skip = false;
1693     // Validate Write updates
1694     for (uint32_t i = 0; i < write_count; i++) {
1695         auto dest_set = p_wds[i].dstSet;
1696         auto set_node = GetSetNode(dest_set);
1697         if (!set_node) {
1698             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
1699                             HandleToUint64(dest_set), kVUID_Core_DrawState_InvalidDescriptorSet,
1700                             "Cannot call %s on %s that has not been allocated.", func_name,
1701                             report_data->FormatHandle(dest_set).c_str());
1702         } else {
1703             std::string error_code;
1704             std::string error_str;
1705             if (!ValidateWriteUpdate(set_node, &p_wds[i], func_name, &error_code, &error_str)) {
1706                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
1707                                 HandleToUint64(dest_set), error_code, "%s failed write update validation for %s with error: %s.",
1708                                 func_name, report_data->FormatHandle(dest_set).c_str(), error_str.c_str());
1709             }
1710         }
1711     }
1712     // Now validate copy updates
1713     for (uint32_t i = 0; i < copy_count; ++i) {
1714         auto dst_set = p_cds[i].dstSet;
1715         auto src_set = p_cds[i].srcSet;
1716         auto src_node = GetSetNode(src_set);
1717         auto dst_node = GetSetNode(dst_set);
1718         // Object_tracker verifies that src & dest descriptor set are valid
1719         assert(src_node);
1720         assert(dst_node);
1721         std::string error_code;
1722         std::string error_str;
1723         if (!ValidateCopyUpdate(&p_cds[i], dst_node, src_node, func_name, &error_code, &error_str)) {
1724             skip |=
1725                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
1726                         HandleToUint64(dst_set), error_code, "%s failed copy update from %s to %s with error: %s.", func_name,
1727                         report_data->FormatHandle(src_set).c_str(), report_data->FormatHandle(dst_set).c_str(), error_str.c_str());
1728         }
1729     }
1730     return skip;
1731 }
1732 // This is a helper function that iterates over a set of Write and Copy updates, pulls the DescriptorSet* for updated
1733 //  sets, and then calls their respective Perform[Write|Copy]Update functions.
1734 // Prerequisite : ValidateUpdateDescriptorSets() should be called and return "false" prior to calling PerformUpdateDescriptorSets()
1735 //  with the same set of updates.
1736 // This is split from the validate code to allow validation prior to calling down the chain, and then update after
1737 //  calling down the chain.
PerformUpdateDescriptorSets(ValidationStateTracker * dev_data,uint32_t write_count,const VkWriteDescriptorSet * p_wds,uint32_t copy_count,const VkCopyDescriptorSet * p_cds)1738 void cvdescriptorset::PerformUpdateDescriptorSets(ValidationStateTracker *dev_data, uint32_t write_count,
1739                                                   const VkWriteDescriptorSet *p_wds, uint32_t copy_count,
1740                                                   const VkCopyDescriptorSet *p_cds) {
1741     // Write updates first
1742     uint32_t i = 0;
1743     for (i = 0; i < write_count; ++i) {
1744         auto dest_set = p_wds[i].dstSet;
1745         auto set_node = dev_data->GetSetNode(dest_set);
1746         if (set_node) {
1747             set_node->PerformWriteUpdate(&p_wds[i]);
1748         }
1749     }
1750     // Now copy updates
1751     for (i = 0; i < copy_count; ++i) {
1752         auto dst_set = p_cds[i].dstSet;
1753         auto src_set = p_cds[i].srcSet;
1754         auto src_node = dev_data->GetSetNode(src_set);
1755         auto dst_node = dev_data->GetSetNode(dst_set);
1756         if (src_node && dst_node) {
1757             dst_node->PerformCopyUpdate(&p_cds[i], src_node);
1758         }
1759     }
1760 }
1761 
DecodedTemplateUpdate(const ValidationStateTracker * device_data,VkDescriptorSet descriptorSet,const TEMPLATE_STATE * template_state,const void * pData,VkDescriptorSetLayout push_layout)1762 cvdescriptorset::DecodedTemplateUpdate::DecodedTemplateUpdate(const ValidationStateTracker *device_data,
1763                                                               VkDescriptorSet descriptorSet, const TEMPLATE_STATE *template_state,
1764                                                               const void *pData, VkDescriptorSetLayout push_layout) {
1765     auto const &create_info = template_state->create_info;
1766     inline_infos.resize(create_info.descriptorUpdateEntryCount);  // Make sure we have one if we need it
1767     desc_writes.reserve(create_info.descriptorUpdateEntryCount);  // emplaced, so reserved without initialization
1768     VkDescriptorSetLayout effective_dsl = create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
1769                                               ? create_info.descriptorSetLayout
1770                                               : push_layout;
1771     auto layout_obj = GetDescriptorSetLayout(device_data, effective_dsl);
1772 
1773     // Create a WriteDescriptorSet struct for each template update entry
1774     for (uint32_t i = 0; i < create_info.descriptorUpdateEntryCount; i++) {
1775         auto binding_count = layout_obj->GetDescriptorCountFromBinding(create_info.pDescriptorUpdateEntries[i].dstBinding);
1776         auto binding_being_updated = create_info.pDescriptorUpdateEntries[i].dstBinding;
1777         auto dst_array_element = create_info.pDescriptorUpdateEntries[i].dstArrayElement;
1778 
1779         desc_writes.reserve(desc_writes.size() + create_info.pDescriptorUpdateEntries[i].descriptorCount);
1780         for (uint32_t j = 0; j < create_info.pDescriptorUpdateEntries[i].descriptorCount; j++) {
1781             desc_writes.emplace_back();
1782             auto &write_entry = desc_writes.back();
1783 
1784             size_t offset = create_info.pDescriptorUpdateEntries[i].offset + j * create_info.pDescriptorUpdateEntries[i].stride;
1785             char *update_entry = (char *)(pData) + offset;
1786 
1787             if (dst_array_element >= binding_count) {
1788                 dst_array_element = 0;
1789                 binding_being_updated = layout_obj->GetNextValidBinding(binding_being_updated);
1790             }
1791 
1792             write_entry.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1793             write_entry.pNext = NULL;
1794             write_entry.dstSet = descriptorSet;
1795             write_entry.dstBinding = binding_being_updated;
1796             write_entry.dstArrayElement = dst_array_element;
1797             write_entry.descriptorCount = 1;
1798             write_entry.descriptorType = create_info.pDescriptorUpdateEntries[i].descriptorType;
1799 
1800             switch (create_info.pDescriptorUpdateEntries[i].descriptorType) {
1801                 case VK_DESCRIPTOR_TYPE_SAMPLER:
1802                 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
1803                 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1804                 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
1805                 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
1806                     write_entry.pImageInfo = reinterpret_cast<VkDescriptorImageInfo *>(update_entry);
1807                     break;
1808 
1809                 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1810                 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1811                 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
1812                 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
1813                     write_entry.pBufferInfo = reinterpret_cast<VkDescriptorBufferInfo *>(update_entry);
1814                     break;
1815 
1816                 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1817                 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1818                     write_entry.pTexelBufferView = reinterpret_cast<VkBufferView *>(update_entry);
1819                     break;
1820                 case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
1821                     VkWriteDescriptorSetInlineUniformBlockEXT *inline_info = &inline_infos[i];
1822                     inline_info->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT;
1823                     inline_info->pNext = nullptr;
1824                     inline_info->dataSize = create_info.pDescriptorUpdateEntries[i].descriptorCount;
1825                     inline_info->pData = update_entry;
1826                     write_entry.pNext = inline_info;
1827                     // descriptorCount must match the dataSize member of the VkWriteDescriptorSetInlineUniformBlockEXT structure
1828                     write_entry.descriptorCount = inline_info->dataSize;
1829                     // skip the rest of the array, they just represent bytes in the update
1830                     j = create_info.pDescriptorUpdateEntries[i].descriptorCount;
1831                     break;
1832                 }
1833                 default:
1834                     assert(0);
1835                     break;
1836             }
1837             dst_array_element++;
1838         }
1839     }
1840 }
1841 // These helper functions carry out the validate and record descriptor updates peformed via update templates. They decode
1842 // the templatized data and leverage the non-template UpdateDescriptor helper functions.
ValidateUpdateDescriptorSetsWithTemplateKHR(VkDescriptorSet descriptorSet,const TEMPLATE_STATE * template_state,const void * pData)1843 bool CoreChecks::ValidateUpdateDescriptorSetsWithTemplateKHR(VkDescriptorSet descriptorSet, const TEMPLATE_STATE *template_state,
1844                                                              const void *pData) {
1845     // Translate the templated update into a normal update for validation...
1846     cvdescriptorset::DecodedTemplateUpdate decoded_update(this, descriptorSet, template_state, pData);
1847     return ValidateUpdateDescriptorSets(static_cast<uint32_t>(decoded_update.desc_writes.size()), decoded_update.desc_writes.data(),
1848                                         0, NULL, "vkUpdateDescriptorSetWithTemplate()");
1849 }
1850 
PerformUpdateDescriptorSetsWithTemplateKHR(VkDescriptorSet descriptorSet,const TEMPLATE_STATE * template_state,const void * pData)1851 void ValidationStateTracker::PerformUpdateDescriptorSetsWithTemplateKHR(VkDescriptorSet descriptorSet,
1852                                                                         const TEMPLATE_STATE *template_state, const void *pData) {
1853     // Translate the templated update into a normal update for validation...
1854     cvdescriptorset::DecodedTemplateUpdate decoded_update(this, descriptorSet, template_state, pData);
1855     cvdescriptorset::PerformUpdateDescriptorSets(this, static_cast<uint32_t>(decoded_update.desc_writes.size()),
1856                                                  decoded_update.desc_writes.data(), 0, NULL);
1857 }
1858 
StringifySetAndLayout() const1859 std::string cvdescriptorset::DescriptorSet::StringifySetAndLayout() const {
1860     std::string out;
1861     auto layout_handle = p_layout_->GetDescriptorSetLayout();
1862     if (IsPushDescriptor()) {
1863         string_sprintf(&out, "Push Descriptors defined with VkDescriptorSetLayout %s",
1864                        state_data_->report_data->FormatHandle(layout_handle).c_str());
1865     } else {
1866         string_sprintf(&out, "VkDescriptorSet %s allocated with VkDescriptorSetLayout %s",
1867                        state_data_->report_data->FormatHandle(set_).c_str(),
1868                        state_data_->report_data->FormatHandle(layout_handle).c_str());
1869     }
1870     return out;
1871 };
1872 
1873 // Loop through the write updates to validate for a push descriptor set, ignoring dstSet
ValidatePushDescriptorsUpdate(const DescriptorSet * push_set,uint32_t write_count,const VkWriteDescriptorSet * p_wds,const char * func_name)1874 bool CoreChecks::ValidatePushDescriptorsUpdate(const DescriptorSet *push_set, uint32_t write_count,
1875                                                const VkWriteDescriptorSet *p_wds, const char *func_name) {
1876     assert(push_set->IsPushDescriptor());
1877     bool skip = false;
1878     for (uint32_t i = 0; i < write_count; i++) {
1879         std::string error_code;
1880         std::string error_str;
1881         if (!ValidateWriteUpdate(push_set, &p_wds[i], func_name, &error_code, &error_str)) {
1882             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
1883                             HandleToUint64(push_set->GetDescriptorSetLayout()), error_code, "%s failed update validation: %s.",
1884                             func_name, error_str.c_str());
1885         }
1886     }
1887     return skip;
1888 }
1889 
1890 // For the given buffer, verify that its creation parameters are appropriate for the given type
1891 //  If there's an error, update the error_msg string with details and return false, else return true
ValidateBufferUsage(BUFFER_STATE const * buffer_node,VkDescriptorType type,std::string * error_code,std::string * error_msg)1892 bool cvdescriptorset::ValidateBufferUsage(BUFFER_STATE const *buffer_node, VkDescriptorType type, std::string *error_code,
1893                                           std::string *error_msg) {
1894     // Verify that usage bits set correctly for given type
1895     auto usage = buffer_node->createInfo.usage;
1896     const char *error_usage_bit = nullptr;
1897     switch (type) {
1898         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1899             if (!(usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) {
1900                 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00334";
1901                 error_usage_bit = "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT";
1902             }
1903             break;
1904         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1905             if (!(usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
1906                 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00335";
1907                 error_usage_bit = "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT";
1908             }
1909             break;
1910         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1911         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
1912             if (!(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) {
1913                 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00330";
1914                 error_usage_bit = "VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT";
1915             }
1916             break;
1917         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1918         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
1919             if (!(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) {
1920                 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00331";
1921                 error_usage_bit = "VK_BUFFER_USAGE_STORAGE_BUFFER_BIT";
1922             }
1923             break;
1924         default:
1925             break;
1926     }
1927     if (error_usage_bit) {
1928         std::stringstream error_str;
1929         error_str << "Buffer (" << buffer_node->buffer << ") with usage mask " << std::hex << std::showbase << usage
1930                   << " being used for a descriptor update of type " << string_VkDescriptorType(type) << " does not have "
1931                   << error_usage_bit << " set.";
1932         *error_msg = error_str.str();
1933         return false;
1934     }
1935     return true;
1936 }
1937 // For buffer descriptor updates, verify the buffer usage and VkDescriptorBufferInfo struct which includes:
1938 //  1. buffer is valid
1939 //  2. buffer was created with correct usage flags
1940 //  3. offset is less than buffer size
1941 //  4. range is either VK_WHOLE_SIZE or falls in (0, (buffer size - offset)]
1942 //  5. range and offset are within the device's limits
1943 // If there's an error, update the error_msg string with details and return false, else return true
ValidateBufferUpdate(VkDescriptorBufferInfo const * buffer_info,VkDescriptorType type,const char * func_name,std::string * error_code,std::string * error_msg)1944 bool CoreChecks::ValidateBufferUpdate(VkDescriptorBufferInfo const *buffer_info, VkDescriptorType type, const char *func_name,
1945                                       std::string *error_code, std::string *error_msg) {
1946     // First make sure that buffer is valid
1947     auto buffer_node = GetBufferState(buffer_info->buffer);
1948     // Any invalid buffer should already be caught by object_tracker
1949     assert(buffer_node);
1950     if (ValidateMemoryIsBoundToBuffer(buffer_node, func_name, "VUID-VkWriteDescriptorSet-descriptorType-00329")) {
1951         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00329";
1952         *error_msg = "No memory bound to buffer.";
1953         return false;
1954     }
1955     // Verify usage bits
1956     if (!cvdescriptorset::ValidateBufferUsage(buffer_node, type, error_code, error_msg)) {
1957         // error_msg will have been updated by ValidateBufferUsage()
1958         return false;
1959     }
1960     // offset must be less than buffer size
1961     if (buffer_info->offset >= buffer_node->createInfo.size) {
1962         *error_code = "VUID-VkDescriptorBufferInfo-offset-00340";
1963         std::stringstream error_str;
1964         error_str << "VkDescriptorBufferInfo offset of " << buffer_info->offset << " is greater than or equal to buffer "
1965                   << buffer_node->buffer << " size of " << buffer_node->createInfo.size;
1966         *error_msg = error_str.str();
1967         return false;
1968     }
1969     if (buffer_info->range != VK_WHOLE_SIZE) {
1970         // Range must be VK_WHOLE_SIZE or > 0
1971         if (!buffer_info->range) {
1972             *error_code = "VUID-VkDescriptorBufferInfo-range-00341";
1973             std::stringstream error_str;
1974             error_str << "VkDescriptorBufferInfo range is not VK_WHOLE_SIZE and is zero, which is not allowed.";
1975             *error_msg = error_str.str();
1976             return false;
1977         }
1978         // Range must be VK_WHOLE_SIZE or <= (buffer size - offset)
1979         if (buffer_info->range > (buffer_node->createInfo.size - buffer_info->offset)) {
1980             *error_code = "VUID-VkDescriptorBufferInfo-range-00342";
1981             std::stringstream error_str;
1982             error_str << "VkDescriptorBufferInfo range is " << buffer_info->range << " which is greater than buffer size ("
1983                       << buffer_node->createInfo.size << ") minus requested offset of " << buffer_info->offset;
1984             *error_msg = error_str.str();
1985             return false;
1986         }
1987     }
1988     // Check buffer update sizes against device limits
1989     const auto &limits = phys_dev_props.limits;
1990     if (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER == type || VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == type) {
1991         auto max_ub_range = limits.maxUniformBufferRange;
1992         if (buffer_info->range != VK_WHOLE_SIZE && buffer_info->range > max_ub_range) {
1993             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00332";
1994             std::stringstream error_str;
1995             error_str << "VkDescriptorBufferInfo range is " << buffer_info->range
1996                       << " which is greater than this device's maxUniformBufferRange (" << max_ub_range << ")";
1997             *error_msg = error_str.str();
1998             return false;
1999         } else if (buffer_info->range == VK_WHOLE_SIZE && (buffer_node->createInfo.size - buffer_info->offset) > max_ub_range) {
2000             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00332";
2001             std::stringstream error_str;
2002             error_str << "VkDescriptorBufferInfo range is VK_WHOLE_SIZE but effective range "
2003                       << "(" << (buffer_node->createInfo.size - buffer_info->offset) << ") is greater than this device's "
2004                       << "maxUniformBufferRange (" << max_ub_range << ")";
2005             *error_msg = error_str.str();
2006             return false;
2007         }
2008     } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == type || VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == type) {
2009         auto max_sb_range = limits.maxStorageBufferRange;
2010         if (buffer_info->range != VK_WHOLE_SIZE && buffer_info->range > max_sb_range) {
2011             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00333";
2012             std::stringstream error_str;
2013             error_str << "VkDescriptorBufferInfo range is " << buffer_info->range
2014                       << " which is greater than this device's maxStorageBufferRange (" << max_sb_range << ")";
2015             *error_msg = error_str.str();
2016             return false;
2017         } else if (buffer_info->range == VK_WHOLE_SIZE && (buffer_node->createInfo.size - buffer_info->offset) > max_sb_range) {
2018             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00333";
2019             std::stringstream error_str;
2020             error_str << "VkDescriptorBufferInfo range is VK_WHOLE_SIZE but effective range "
2021                       << "(" << (buffer_node->createInfo.size - buffer_info->offset) << ") is greater than this device's "
2022                       << "maxStorageBufferRange (" << max_sb_range << ")";
2023             *error_msg = error_str.str();
2024             return false;
2025         }
2026     }
2027     return true;
2028 }
2029 // Verify that the contents of the update are ok, but don't perform actual update
VerifyCopyUpdateContents(const VkCopyDescriptorSet * update,const DescriptorSet * src_set,VkDescriptorType type,uint32_t index,const char * func_name,std::string * error_code,std::string * error_msg)2030 bool CoreChecks::VerifyCopyUpdateContents(const VkCopyDescriptorSet *update, const DescriptorSet *src_set, VkDescriptorType type,
2031                                           uint32_t index, const char *func_name, std::string *error_code, std::string *error_msg) {
2032     // Note : Repurposing some Write update error codes here as specific details aren't called out for copy updates like they are
2033     // for write updates
2034     using DescriptorClass = cvdescriptorset::DescriptorClass;
2035     using BufferDescriptor = cvdescriptorset::BufferDescriptor;
2036     using ImageDescriptor = cvdescriptorset::ImageDescriptor;
2037     using ImageSamplerDescriptor = cvdescriptorset::ImageSamplerDescriptor;
2038     using SamplerDescriptor = cvdescriptorset::SamplerDescriptor;
2039     using TexelDescriptor = cvdescriptorset::TexelDescriptor;
2040 
2041     auto device_data = this;
2042     switch (src_set->GetDescriptorFromGlobalIndex(index)->descriptor_class) {
2043         case DescriptorClass::PlainSampler: {
2044             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2045                 const auto src_desc = src_set->GetDescriptorFromGlobalIndex(index + di);
2046                 if (!src_desc->updated) continue;
2047                 if (!src_desc->IsImmutableSampler()) {
2048                     auto update_sampler = static_cast<const SamplerDescriptor *>(src_desc)->GetSampler();
2049                     if (!ValidateSampler(update_sampler)) {
2050                         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00325";
2051                         std::stringstream error_str;
2052                         error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
2053                         *error_msg = error_str.str();
2054                         return false;
2055                     }
2056                 } else {
2057                     // TODO : Warn here
2058                 }
2059             }
2060             break;
2061         }
2062         case DescriptorClass::ImageSampler: {
2063             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2064                 const auto src_desc = src_set->GetDescriptorFromGlobalIndex(index + di);
2065                 if (!src_desc->updated) continue;
2066                 auto img_samp_desc = static_cast<const ImageSamplerDescriptor *>(src_desc);
2067                 // First validate sampler
2068                 if (!img_samp_desc->IsImmutableSampler()) {
2069                     auto update_sampler = img_samp_desc->GetSampler();
2070                     if (!ValidateSampler(update_sampler)) {
2071                         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00325";
2072                         std::stringstream error_str;
2073                         error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
2074                         *error_msg = error_str.str();
2075                         return false;
2076                     }
2077                 } else {
2078                     // TODO : Warn here
2079                 }
2080                 // Validate image
2081                 auto image_view = img_samp_desc->GetImageView();
2082                 auto image_layout = img_samp_desc->GetImageLayout();
2083                 if (!ValidateImageUpdate(image_view, image_layout, type, func_name, error_code, error_msg)) {
2084                     std::stringstream error_str;
2085                     error_str << "Attempted copy update to combined image sampler descriptor failed due to: " << error_msg->c_str();
2086                     *error_msg = error_str.str();
2087                     return false;
2088                 }
2089             }
2090             break;
2091         }
2092         case DescriptorClass::Image: {
2093             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2094                 const auto src_desc = src_set->GetDescriptorFromGlobalIndex(index + di);
2095                 if (!src_desc->updated) continue;
2096                 auto img_desc = static_cast<const ImageDescriptor *>(src_desc);
2097                 auto image_view = img_desc->GetImageView();
2098                 auto image_layout = img_desc->GetImageLayout();
2099                 if (!ValidateImageUpdate(image_view, image_layout, type, func_name, error_code, error_msg)) {
2100                     std::stringstream error_str;
2101                     error_str << "Attempted copy update to image descriptor failed due to: " << error_msg->c_str();
2102                     *error_msg = error_str.str();
2103                     return false;
2104                 }
2105             }
2106             break;
2107         }
2108         case DescriptorClass::TexelBuffer: {
2109             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2110                 const auto src_desc = src_set->GetDescriptorFromGlobalIndex(index + di);
2111                 if (!src_desc->updated) continue;
2112                 auto buffer_view = static_cast<const TexelDescriptor *>(src_desc)->GetBufferView();
2113                 auto bv_state = device_data->GetBufferViewState(buffer_view);
2114                 if (!bv_state) {
2115                     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00323";
2116                     std::stringstream error_str;
2117                     error_str << "Attempted copy update to texel buffer descriptor with invalid buffer view: " << buffer_view;
2118                     *error_msg = error_str.str();
2119                     return false;
2120                 }
2121                 auto buffer = bv_state->create_info.buffer;
2122                 if (!cvdescriptorset::ValidateBufferUsage(GetBufferState(buffer), type, error_code, error_msg)) {
2123                     std::stringstream error_str;
2124                     error_str << "Attempted copy update to texel buffer descriptor failed due to: " << error_msg->c_str();
2125                     *error_msg = error_str.str();
2126                     return false;
2127                 }
2128             }
2129             break;
2130         }
2131         case DescriptorClass::GeneralBuffer: {
2132             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2133                 const auto src_desc = src_set->GetDescriptorFromGlobalIndex(index + di);
2134                 if (!src_desc->updated) continue;
2135                 auto buffer = static_cast<const BufferDescriptor *>(src_desc)->GetBuffer();
2136                 if (!cvdescriptorset::ValidateBufferUsage(GetBufferState(buffer), type, error_code, error_msg)) {
2137                     std::stringstream error_str;
2138                     error_str << "Attempted copy update to buffer descriptor failed due to: " << error_msg->c_str();
2139                     *error_msg = error_str.str();
2140                     return false;
2141                 }
2142             }
2143             break;
2144         }
2145         case DescriptorClass::InlineUniform:
2146         case DescriptorClass::AccelerationStructure:
2147             break;
2148         default:
2149             assert(0);  // We've already verified update type so should never get here
2150             break;
2151     }
2152     // All checks passed so update contents are good
2153     return true;
2154 }
2155 // Update the common AllocateDescriptorSetsData
UpdateAllocateDescriptorSetsData(const VkDescriptorSetAllocateInfo * p_alloc_info,cvdescriptorset::AllocateDescriptorSetsData * ds_data)2156 void CoreChecks::UpdateAllocateDescriptorSetsData(const VkDescriptorSetAllocateInfo *p_alloc_info,
2157                                                   cvdescriptorset::AllocateDescriptorSetsData *ds_data) {
2158     for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
2159         auto layout = GetDescriptorSetLayout(this, p_alloc_info->pSetLayouts[i]);
2160         if (layout) {
2161             ds_data->layout_nodes[i] = layout;
2162             // Count total descriptors required per type
2163             for (uint32_t j = 0; j < layout->GetBindingCount(); ++j) {
2164                 const auto &binding_layout = layout->GetDescriptorSetLayoutBindingPtrFromIndex(j);
2165                 uint32_t typeIndex = static_cast<uint32_t>(binding_layout->descriptorType);
2166                 ds_data->required_descriptors_by_type[typeIndex] += binding_layout->descriptorCount;
2167             }
2168         }
2169         // Any unknown layouts will be flagged as errors during ValidateAllocateDescriptorSets() call
2170     }
2171 }
2172 // Verify that the state at allocate time is correct, but don't actually allocate the sets yet
ValidateAllocateDescriptorSets(const VkDescriptorSetAllocateInfo * p_alloc_info,const cvdescriptorset::AllocateDescriptorSetsData * ds_data)2173 bool CoreChecks::ValidateAllocateDescriptorSets(const VkDescriptorSetAllocateInfo *p_alloc_info,
2174                                                 const cvdescriptorset::AllocateDescriptorSetsData *ds_data) {
2175     bool skip = false;
2176     auto pool_state = GetDescriptorPoolState(p_alloc_info->descriptorPool);
2177 
2178     for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
2179         auto layout = GetDescriptorSetLayout(this, p_alloc_info->pSetLayouts[i]);
2180         if (layout) {  // nullptr layout indicates no valid layout handle for this device, validated/logged in object_tracker
2181             if (layout->IsPushDescriptor()) {
2182                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
2183                                 HandleToUint64(p_alloc_info->pSetLayouts[i]), "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-00308",
2184                                 "%s specified at pSetLayouts[%" PRIu32
2185                                 "] in vkAllocateDescriptorSets() was created with invalid flag %s set.",
2186                                 report_data->FormatHandle(p_alloc_info->pSetLayouts[i]).c_str(), i,
2187                                 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR");
2188             }
2189             if (layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT &&
2190                 !(pool_state->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT)) {
2191                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
2192                                 0, "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-03044",
2193                                 "Descriptor set layout create flags and pool create flags mismatch for index (%d)", i);
2194             }
2195         }
2196     }
2197     if (!device_extensions.vk_khr_maintenance1) {
2198         // Track number of descriptorSets allowable in this pool
2199         if (pool_state->availableSets < p_alloc_info->descriptorSetCount) {
2200             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
2201                             HandleToUint64(pool_state->pool), "VUID-VkDescriptorSetAllocateInfo-descriptorSetCount-00306",
2202                             "Unable to allocate %u descriptorSets from %s"
2203                             ". This pool only has %d descriptorSets remaining.",
2204                             p_alloc_info->descriptorSetCount, report_data->FormatHandle(pool_state->pool).c_str(),
2205                             pool_state->availableSets);
2206         }
2207         // Determine whether descriptor counts are satisfiable
2208         for (auto it = ds_data->required_descriptors_by_type.begin(); it != ds_data->required_descriptors_by_type.end(); ++it) {
2209             if (ds_data->required_descriptors_by_type.at(it->first) > pool_state->availableDescriptorTypeCount[it->first]) {
2210                 skip |= log_msg(
2211                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
2212                     HandleToUint64(pool_state->pool), "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307",
2213                     "Unable to allocate %u descriptors of type %s from %s"
2214                     ". This pool only has %d descriptors of this type remaining.",
2215                     ds_data->required_descriptors_by_type.at(it->first), string_VkDescriptorType(VkDescriptorType(it->first)),
2216                     report_data->FormatHandle(pool_state->pool).c_str(), pool_state->availableDescriptorTypeCount[it->first]);
2217             }
2218         }
2219     }
2220 
2221     const auto *count_allocate_info = lvl_find_in_chain<VkDescriptorSetVariableDescriptorCountAllocateInfoEXT>(p_alloc_info->pNext);
2222 
2223     if (count_allocate_info) {
2224         if (count_allocate_info->descriptorSetCount != 0 &&
2225             count_allocate_info->descriptorSetCount != p_alloc_info->descriptorSetCount) {
2226             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, 0,
2227                             "VUID-VkDescriptorSetVariableDescriptorCountAllocateInfoEXT-descriptorSetCount-03045",
2228                             "VkDescriptorSetAllocateInfo::descriptorSetCount (%d) != "
2229                             "VkDescriptorSetVariableDescriptorCountAllocateInfoEXT::descriptorSetCount (%d)",
2230                             p_alloc_info->descriptorSetCount, count_allocate_info->descriptorSetCount);
2231         }
2232         if (count_allocate_info->descriptorSetCount == p_alloc_info->descriptorSetCount) {
2233             for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
2234                 auto layout = GetDescriptorSetLayout(this, p_alloc_info->pSetLayouts[i]);
2235                 if (count_allocate_info->pDescriptorCounts[i] > layout->GetDescriptorCountFromBinding(layout->GetMaxBinding())) {
2236                     skip |= log_msg(
2237                         report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, 0,
2238                         "VUID-VkDescriptorSetVariableDescriptorCountAllocateInfoEXT-pSetLayouts-03046",
2239                         "pDescriptorCounts[%d] = (%d), binding's descriptorCount = (%d)", i,
2240                         count_allocate_info->pDescriptorCounts[i], layout->GetDescriptorCountFromBinding(layout->GetMaxBinding()));
2241                 }
2242             }
2243         }
2244     }
2245 
2246     return skip;
2247 }
2248 // Decrement allocated sets from the pool and insert new sets into set_map
PerformAllocateDescriptorSets(const VkDescriptorSetAllocateInfo * p_alloc_info,const VkDescriptorSet * descriptor_sets,const cvdescriptorset::AllocateDescriptorSetsData * ds_data)2249 void ValidationStateTracker::PerformAllocateDescriptorSets(const VkDescriptorSetAllocateInfo *p_alloc_info,
2250                                                            const VkDescriptorSet *descriptor_sets,
2251                                                            const cvdescriptorset::AllocateDescriptorSetsData *ds_data) {
2252     auto pool_state = descriptorPoolMap[p_alloc_info->descriptorPool].get();
2253     // Account for sets and individual descriptors allocated from pool
2254     pool_state->availableSets -= p_alloc_info->descriptorSetCount;
2255     for (auto it = ds_data->required_descriptors_by_type.begin(); it != ds_data->required_descriptors_by_type.end(); ++it) {
2256         pool_state->availableDescriptorTypeCount[it->first] -= ds_data->required_descriptors_by_type.at(it->first);
2257     }
2258 
2259     const auto *variable_count_info = lvl_find_in_chain<VkDescriptorSetVariableDescriptorCountAllocateInfoEXT>(p_alloc_info->pNext);
2260     bool variable_count_valid = variable_count_info && variable_count_info->descriptorSetCount == p_alloc_info->descriptorSetCount;
2261 
2262     // Create tracking object for each descriptor set; insert into global map and the pool's set.
2263     for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
2264         uint32_t variable_count = variable_count_valid ? variable_count_info->pDescriptorCounts[i] : 0;
2265 
2266         std::unique_ptr<cvdescriptorset::DescriptorSet> new_ds(new cvdescriptorset::DescriptorSet(
2267             descriptor_sets[i], p_alloc_info->descriptorPool, ds_data->layout_nodes[i], variable_count, this));
2268         pool_state->sets.insert(new_ds.get());
2269         new_ds->in_use.store(0);
2270         setMap[descriptor_sets[i]] = std::move(new_ds);
2271     }
2272 }
2273 
FilteredMap(const CMD_BUFFER_STATE & cb_state,const PIPELINE_STATE & pipeline)2274 const BindingReqMap &cvdescriptorset::PrefilterBindRequestMap::FilteredMap(const CMD_BUFFER_STATE &cb_state,
2275                                                                            const PIPELINE_STATE &pipeline) {
2276     if (IsManyDescriptors()) {
2277         filtered_map_.reset(new std::map<uint32_t, descriptor_req>());
2278         descriptor_set_.FilterBindingReqs(cb_state, pipeline, orig_map_, filtered_map_.get());
2279         return *filtered_map_;
2280     }
2281     return orig_map_;
2282 }
2283 
2284 // Starting at offset descriptor of given binding, parse over update_count
2285 //  descriptor updates and verify that for any binding boundaries that are crossed, the next binding(s) are all consistent
2286 //  Consistency means that their type, stage flags, and whether or not they use immutable samplers matches
2287 //  If so, return true. If not, fill in error_msg and return false
VerifyUpdateConsistency(DescriptorSetLayout::ConstBindingIterator current_binding,uint32_t offset,uint32_t update_count,const char * type,const VkDescriptorSet set,std::string * error_msg)2288 bool cvdescriptorset::VerifyUpdateConsistency(DescriptorSetLayout::ConstBindingIterator current_binding, uint32_t offset,
2289                                               uint32_t update_count, const char *type, const VkDescriptorSet set,
2290                                               std::string *error_msg) {
2291     // Verify consecutive bindings match (if needed)
2292     auto orig_binding = current_binding;
2293     // Track count of descriptors in the current_bindings that are remaining to be updated
2294     auto binding_remaining = current_binding.GetDescriptorCount();
2295     // First, it's legal to offset beyond your own binding so handle that case
2296     //  Really this is just searching for the binding in which the update begins and adjusting offset accordingly
2297     while (offset >= binding_remaining && !current_binding.AtEnd()) {
2298         // Advance to next binding, decrement offset by binding size
2299         offset -= binding_remaining;
2300         ++current_binding;
2301         binding_remaining = current_binding.GetDescriptorCount();  // Accessors are safe if AtEnd
2302     }
2303     assert(!current_binding.AtEnd());  // As written assumes range check has been made before calling
2304     binding_remaining -= offset;
2305     while (update_count > binding_remaining) {  // While our updates overstep current binding
2306         // Verify next consecutive binding matches type, stage flags & immutable sampler use
2307         auto next_binding = current_binding.Next();
2308         if (!current_binding.IsConsistent(next_binding)) {
2309             std::stringstream error_str;
2310             error_str << "Attempting " << type;
2311             if (current_binding.Layout()->IsPushDescriptor()) {
2312                 error_str << " push descriptors";
2313             } else {
2314                 error_str << " descriptor set " << set;
2315             }
2316             error_str << " binding #" << orig_binding.Binding() << " with #" << update_count
2317                       << " descriptors being updated but this update oversteps the bounds of this binding and the next binding is "
2318                          "not consistent with current binding so this update is invalid.";
2319             *error_msg = error_str.str();
2320             return false;
2321         }
2322         current_binding = next_binding;
2323         // For sake of this check consider the bindings updated and grab count for next binding
2324         update_count -= binding_remaining;
2325         binding_remaining = current_binding.GetDescriptorCount();
2326     }
2327     return true;
2328 }
2329 
2330 // Validate the state for a given write update but don't actually perform the update
2331 //  If an error would occur for this update, return false and fill in details in error_msg string
ValidateWriteUpdate(const DescriptorSet * dest_set,const VkWriteDescriptorSet * update,const char * func_name,std::string * error_code,std::string * error_msg)2332 bool CoreChecks::ValidateWriteUpdate(const DescriptorSet *dest_set, const VkWriteDescriptorSet *update, const char *func_name,
2333                                      std::string *error_code, std::string *error_msg) {
2334     const auto dest_layout = dest_set->GetLayout();
2335 
2336     // Verify dst layout still valid
2337     if (dest_layout->IsDestroyed()) {
2338         *error_code = "VUID-VkWriteDescriptorSet-dstSet-00320";
2339         string_sprintf(error_msg, "Cannot call %s to perform write update on %s which has been destroyed", func_name,
2340                        dest_set->StringifySetAndLayout().c_str());
2341         return false;
2342     }
2343     // Verify dst binding exists
2344     if (!dest_layout->HasBinding(update->dstBinding)) {
2345         *error_code = "VUID-VkWriteDescriptorSet-dstBinding-00315";
2346         std::stringstream error_str;
2347         error_str << dest_set->StringifySetAndLayout() << " does not have binding " << update->dstBinding;
2348         *error_msg = error_str.str();
2349         return false;
2350     }
2351 
2352     DescriptorSetLayout::ConstBindingIterator dest(dest_layout.get(), update->dstBinding);
2353     // Make sure binding isn't empty
2354     if (0 == dest.GetDescriptorCount()) {
2355         *error_code = "VUID-VkWriteDescriptorSet-dstBinding-00316";
2356         std::stringstream error_str;
2357         error_str << dest_set->StringifySetAndLayout() << " cannot updated binding " << update->dstBinding
2358                   << " that has 0 descriptors";
2359         *error_msg = error_str.str();
2360         return false;
2361     }
2362 
2363     // Verify idle ds
2364     if (dest_set->in_use.load() && !(dest.GetDescriptorBindingFlags() & (VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT |
2365                                                                          VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT))) {
2366         // TODO : Re-using Free Idle error code, need write update idle error code
2367         *error_code = "VUID-vkFreeDescriptorSets-pDescriptorSets-00309";
2368         std::stringstream error_str;
2369         error_str << "Cannot call " << func_name << " to perform write update on " << dest_set->StringifySetAndLayout()
2370                   << " that is in use by a command buffer";
2371         *error_msg = error_str.str();
2372         return false;
2373     }
2374     // We know that binding is valid, verify update and do update on each descriptor
2375     auto start_idx = dest.GetGlobalIndexRange().start + update->dstArrayElement;
2376     auto type = dest.GetType();
2377     if (type != update->descriptorType) {
2378         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00319";
2379         std::stringstream error_str;
2380         error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2381                   << " with type " << string_VkDescriptorType(type) << " but update type is "
2382                   << string_VkDescriptorType(update->descriptorType);
2383         *error_msg = error_str.str();
2384         return false;
2385     }
2386     auto total_descriptors = dest_layout->GetTotalDescriptorCount();
2387     if (update->descriptorCount > (total_descriptors - start_idx)) {
2388         *error_code = "VUID-VkWriteDescriptorSet-dstArrayElement-00321";
2389         std::stringstream error_str;
2390         error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2391                   << " with " << total_descriptors - start_idx
2392                   << " descriptors in that binding and all successive bindings of the set, but update of "
2393                   << update->descriptorCount << " descriptors combined with update array element offset of "
2394                   << update->dstArrayElement << " oversteps the available number of consecutive descriptors";
2395         *error_msg = error_str.str();
2396         return false;
2397     }
2398     if (type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
2399         if ((update->dstArrayElement % 4) != 0) {
2400             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02219";
2401             std::stringstream error_str;
2402             error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2403                       << " with "
2404                       << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
2405             *error_msg = error_str.str();
2406             return false;
2407         }
2408         if ((update->descriptorCount % 4) != 0) {
2409             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02220";
2410             std::stringstream error_str;
2411             error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2412                       << " with "
2413                       << "descriptorCount  " << update->descriptorCount << " not a multiple of 4";
2414             *error_msg = error_str.str();
2415             return false;
2416         }
2417         const auto *write_inline_info = lvl_find_in_chain<VkWriteDescriptorSetInlineUniformBlockEXT>(update->pNext);
2418         if (!write_inline_info || write_inline_info->dataSize != update->descriptorCount) {
2419             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02221";
2420             std::stringstream error_str;
2421             if (!write_inline_info) {
2422                 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #"
2423                           << update->dstBinding << " with "
2424                           << "VkWriteDescriptorSetInlineUniformBlockEXT missing";
2425             } else {
2426                 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #"
2427                           << update->dstBinding << " with "
2428                           << "VkWriteDescriptorSetInlineUniformBlockEXT dataSize " << write_inline_info->dataSize
2429                           << " not equal to "
2430                           << "VkWriteDescriptorSet descriptorCount " << update->descriptorCount;
2431             }
2432             *error_msg = error_str.str();
2433             return false;
2434         }
2435         // This error is probably unreachable due to the previous two errors
2436         if (write_inline_info && (write_inline_info->dataSize % 4) != 0) {
2437             *error_code = "VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-02222";
2438             std::stringstream error_str;
2439             error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2440                       << " with "
2441                       << "VkWriteDescriptorSetInlineUniformBlockEXT dataSize " << write_inline_info->dataSize
2442                       << " not a multiple of 4";
2443             *error_msg = error_str.str();
2444             return false;
2445         }
2446     }
2447     // Verify consecutive bindings match (if needed)
2448     if (!VerifyUpdateConsistency(DescriptorSetLayout::ConstBindingIterator(dest_layout.get(), update->dstBinding),
2449                                  update->dstArrayElement, update->descriptorCount, "write update to", dest_set->GetSet(),
2450                                  error_msg)) {
2451         // TODO : Should break out "consecutive binding updates" language into valid usage statements
2452         *error_code = "VUID-VkWriteDescriptorSet-dstArrayElement-00321";
2453         return false;
2454     }
2455     // Update is within bounds and consistent so last step is to validate update contents
2456     if (!VerifyWriteUpdateContents(dest_set, update, start_idx, func_name, error_code, error_msg)) {
2457         std::stringstream error_str;
2458         error_str << "Write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2459                   << " failed with error message: " << error_msg->c_str();
2460         *error_msg = error_str.str();
2461         return false;
2462     }
2463     // All checks passed, update is clean
2464     return true;
2465 }
2466 
2467 // Verify that the contents of the update are ok, but don't perform actual update
VerifyWriteUpdateContents(const DescriptorSet * dest_set,const VkWriteDescriptorSet * update,const uint32_t index,const char * func_name,std::string * error_code,std::string * error_msg)2468 bool CoreChecks::VerifyWriteUpdateContents(const DescriptorSet *dest_set, const VkWriteDescriptorSet *update, const uint32_t index,
2469                                            const char *func_name, std::string *error_code, std::string *error_msg) {
2470     using ImageSamplerDescriptor = cvdescriptorset::ImageSamplerDescriptor;
2471     using SamplerDescriptor = cvdescriptorset::SamplerDescriptor;
2472 
2473     switch (update->descriptorType) {
2474         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
2475             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2476                 // Validate image
2477                 auto image_view = update->pImageInfo[di].imageView;
2478                 auto image_layout = update->pImageInfo[di].imageLayout;
2479                 if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, func_name, error_code, error_msg)) {
2480                     std::stringstream error_str;
2481                     error_str << "Attempted write update to combined image sampler descriptor failed due to: "
2482                               << error_msg->c_str();
2483                     *error_msg = error_str.str();
2484                     return false;
2485                 }
2486                 if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
2487                     ImageSamplerDescriptor *desc = (ImageSamplerDescriptor *)dest_set->GetDescriptorFromGlobalIndex(index + di);
2488                     if (desc->IsImmutableSampler()) {
2489                         auto sampler_state = GetSamplerState(desc->GetSampler());
2490                         auto iv_state = GetImageViewState(image_view);
2491                         if (iv_state && sampler_state) {
2492                             if (iv_state->samplerConversion != sampler_state->samplerConversion) {
2493                                 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-01948";
2494                                 std::stringstream error_str;
2495                                 error_str << "Attempted write update to combined image sampler and image view and sampler ycbcr "
2496                                              "conversions are not identical, sampler: "
2497                                           << desc->GetSampler() << " image view: " << iv_state->image_view << ".";
2498                                 *error_msg = error_str.str();
2499                                 return false;
2500                             }
2501                         }
2502                     } else {
2503                         auto iv_state = GetImageViewState(image_view);
2504                         if (iv_state && (iv_state->samplerConversion != VK_NULL_HANDLE)) {
2505                             *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02738";
2506                             std::stringstream error_str;
2507                             error_str << "Because dstSet (" << update->dstSet << ") is bound to image view ("
2508                                       << iv_state->image_view
2509                                       << ") that includes a YCBCR conversion, it must have been allocated with a layout that "
2510                                          "includes an immutable sampler.";
2511                             *error_msg = error_str.str();
2512                             return false;
2513                         }
2514                     }
2515                 }
2516             }
2517         }
2518         // fall through
2519         case VK_DESCRIPTOR_TYPE_SAMPLER: {
2520             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2521                 SamplerDescriptor *desc = (SamplerDescriptor *)dest_set->GetDescriptorFromGlobalIndex(index + di);
2522                 if (!desc->IsImmutableSampler()) {
2523                     if (!ValidateSampler(update->pImageInfo[di].sampler)) {
2524                         *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00325";
2525                         std::stringstream error_str;
2526                         error_str << "Attempted write update to sampler descriptor with invalid sampler: "
2527                                   << update->pImageInfo[di].sampler << ".";
2528                         *error_msg = error_str.str();
2529                         return false;
2530                     }
2531                 } else {
2532                     // TODO : Warn here
2533                 }
2534             }
2535             break;
2536         }
2537         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2538         case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2539         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
2540             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2541                 auto image_view = update->pImageInfo[di].imageView;
2542                 auto image_layout = update->pImageInfo[di].imageLayout;
2543                 if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, func_name, error_code, error_msg)) {
2544                     std::stringstream error_str;
2545                     error_str << "Attempted write update to image descriptor failed due to: " << error_msg->c_str();
2546                     *error_msg = error_str.str();
2547                     return false;
2548                 }
2549             }
2550             break;
2551         }
2552         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2553         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
2554             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2555                 auto buffer_view = update->pTexelBufferView[di];
2556                 auto bv_state = GetBufferViewState(buffer_view);
2557                 if (!bv_state) {
2558                     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00323";
2559                     std::stringstream error_str;
2560                     error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: " << buffer_view;
2561                     *error_msg = error_str.str();
2562                     return false;
2563                 }
2564                 auto buffer = bv_state->create_info.buffer;
2565                 auto buffer_state = GetBufferState(buffer);
2566                 // Verify that buffer underlying the view hasn't been destroyed prematurely
2567                 if (!buffer_state) {
2568                     *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00323";
2569                     std::stringstream error_str;
2570                     error_str << "Attempted write update to texel buffer descriptor failed because underlying buffer (" << buffer
2571                               << ") has been destroyed: " << error_msg->c_str();
2572                     *error_msg = error_str.str();
2573                     return false;
2574                 } else if (!cvdescriptorset::ValidateBufferUsage(buffer_state, update->descriptorType, error_code, error_msg)) {
2575                     std::stringstream error_str;
2576                     error_str << "Attempted write update to texel buffer descriptor failed due to: " << error_msg->c_str();
2577                     *error_msg = error_str.str();
2578                     return false;
2579                 }
2580             }
2581             break;
2582         }
2583         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2584         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
2585         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2586         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
2587             for (uint32_t di = 0; di < update->descriptorCount; ++di) {
2588                 if (!ValidateBufferUpdate(update->pBufferInfo + di, update->descriptorType, func_name, error_code, error_msg)) {
2589                     std::stringstream error_str;
2590                     error_str << "Attempted write update to buffer descriptor failed due to: " << error_msg->c_str();
2591                     *error_msg = error_str.str();
2592                     return false;
2593                 }
2594             }
2595             break;
2596         }
2597         case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
2598             break;
2599         case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
2600             // XXX TODO
2601             break;
2602         default:
2603             assert(0);  // We've already verified update type so should never get here
2604             break;
2605     }
2606     // All checks passed so update contents are good
2607     return true;
2608 }
2609