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 #ifndef CORE_VALIDATION_DESCRIPTOR_SETS_H_ 22 #define CORE_VALIDATION_DESCRIPTOR_SETS_H_ 23 24 #include "hash_vk_types.h" 25 #include "vk_layer_logging.h" 26 #include "vk_layer_utils.h" 27 #include "vk_safe_struct.h" 28 #include "vulkan/vk_layer.h" 29 #include "vk_object_types.h" 30 #include <map> 31 #include <memory> 32 #include <set> 33 #include <unordered_map> 34 #include <unordered_set> 35 #include <vector> 36 37 class CoreChecks; 38 class ValidationStateTracker; 39 40 // Descriptor Data structures 41 namespace cvdescriptorset { 42 43 // Utility structs/classes/types 44 // Index range for global indices below, end is exclusive, i.e. [start,end) 45 struct IndexRange { IndexRangeIndexRange46 IndexRange(uint32_t start_in, uint32_t end_in) : start(start_in), end(end_in) {} 47 IndexRange() = default; 48 uint32_t start; 49 uint32_t end; 50 }; 51 52 /* 53 * DescriptorSetLayoutDef/DescriptorSetLayout classes 54 * 55 * Overview - These two classes encapsulate the Vulkan VkDescriptorSetLayout data (layout). 56 * A layout consists of some number of bindings, each of which has a binding#, a 57 * type, descriptor count, stage flags, and pImmutableSamplers. 58 59 * The DescriptorSetLayoutDef represents a canonicalization of the input data and contains 60 * neither per handle or per device state. It is possible for different handles on 61 * different devices to share a common def. This is used and useful for quick compatibiltiy 62 * validation. The DescriptorSetLayout refers to a DescriptorSetLayoutDef and contains 63 * all per handle state. 64 * 65 * Index vs Binding - A layout is created with an array of VkDescriptorSetLayoutBinding 66 * where each array index will have a corresponding binding# that is defined in that struct. 67 * The binding#, then, is decoupled from VkDescriptorSetLayoutBinding index, which allows 68 * bindings to be defined out-of-order. This DescriptorSetLayout class, however, stores 69 * the bindings internally in-order. This is useful for operations which may "roll over" 70 * from a single binding to the next consecutive binding. 71 * 72 * Note that although the bindings are stored in-order, there still may be "gaps" in the 73 * binding#. For example, if the binding creation order is 8, 7, 10, 3, 4, then the 74 * internal binding array will have five entries stored in binding order 3, 4, 7, 8, 10. 75 * To process all of the bindings in a layout you can iterate from 0 to GetBindingCount() 76 * and use the Get*FromIndex() functions for each index. To just process a single binding, 77 * use the Get*FromBinding() functions. 78 * 79 * Global Index - The binding vector index has as many indices as there are bindings. 80 * This class also has the concept of a Global Index. For the global index functions, 81 * there are as many global indices as there are descriptors in the layout. 82 * For the global index, consider all of the bindings to be a flat array where 83 * descriptor 0 of of the lowest binding# is index 0 and each descriptor in the layout 84 * increments from there. So if the lowest binding# in this example had descriptorCount of 85 * 10, then the GlobalStartIndex of the 2nd lowest binding# will be 10 where 0-9 are the 86 * global indices for the lowest binding#. 87 */ 88 class DescriptorSetLayoutDef { 89 public: 90 // Constructors and destructor 91 DescriptorSetLayoutDef(const VkDescriptorSetLayoutCreateInfo *p_create_info); 92 size_t hash() const; 93 GetTotalDescriptorCount()94 uint32_t GetTotalDescriptorCount() const { return descriptor_count_; }; GetDynamicDescriptorCount()95 uint32_t GetDynamicDescriptorCount() const { return dynamic_descriptor_count_; }; GetCreateFlags()96 VkDescriptorSetLayoutCreateFlags GetCreateFlags() const { return flags_; } 97 // For a given binding, return the number of descriptors in that binding and all successive bindings GetBindingCount()98 uint32_t GetBindingCount() const { return binding_count_; }; 99 // Non-empty binding numbers in order GetSortedBindingSet()100 const std::set<uint32_t> &GetSortedBindingSet() const { return non_empty_bindings_; } 101 // Return true if given binding is present in this layout HasBinding(const uint32_t binding)102 bool HasBinding(const uint32_t binding) const { return binding_to_index_map_.count(binding) > 0; }; 103 // Return true if binding 1 beyond given exists and has same type, stageFlags & immutable sampler use 104 bool IsNextBindingConsistent(const uint32_t) const; 105 uint32_t GetIndexFromBinding(uint32_t binding) const; 106 // Various Get functions that can either be passed a binding#, which will 107 // be automatically translated into the appropriate index, or the index# can be passed in directly GetMaxBinding()108 uint32_t GetMaxBinding() const { return bindings_[bindings_.size() - 1].binding; } 109 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t) const; GetDescriptorSetLayoutBindingPtrFromBinding(uint32_t binding)110 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(uint32_t binding) const { 111 return GetDescriptorSetLayoutBindingPtrFromIndex(GetIndexFromBinding(binding)); 112 } GetBindings()113 const std::vector<safe_VkDescriptorSetLayoutBinding> &GetBindings() const { return bindings_; } GetBindingFlags()114 const std::vector<VkDescriptorBindingFlagsEXT> &GetBindingFlags() const { return binding_flags_; } 115 uint32_t GetDescriptorCountFromIndex(const uint32_t) const; GetDescriptorCountFromBinding(const uint32_t binding)116 uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const { 117 return GetDescriptorCountFromIndex(GetIndexFromBinding(binding)); 118 } 119 VkDescriptorType GetTypeFromIndex(const uint32_t) const; GetTypeFromBinding(const uint32_t binding)120 VkDescriptorType GetTypeFromBinding(const uint32_t binding) const { return GetTypeFromIndex(GetIndexFromBinding(binding)); } 121 VkShaderStageFlags GetStageFlagsFromIndex(const uint32_t) const; GetStageFlagsFromBinding(const uint32_t binding)122 VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t binding) const { 123 return GetStageFlagsFromIndex(GetIndexFromBinding(binding)); 124 } 125 VkDescriptorBindingFlagsEXT GetDescriptorBindingFlagsFromIndex(const uint32_t) const; GetDescriptorBindingFlagsFromBinding(const uint32_t binding)126 VkDescriptorBindingFlagsEXT GetDescriptorBindingFlagsFromBinding(const uint32_t binding) const { 127 return GetDescriptorBindingFlagsFromIndex(GetIndexFromBinding(binding)); 128 } 129 VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t) const; 130 VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t) const; 131 // For a given binding and array index, return the corresponding index into the dynamic offset array GetDynamicOffsetIndexFromBinding(uint32_t binding)132 int32_t GetDynamicOffsetIndexFromBinding(uint32_t binding) const { 133 auto dyn_off = binding_to_dynamic_array_idx_map_.find(binding); 134 if (dyn_off == binding_to_dynamic_array_idx_map_.end()) { 135 assert(0); // Requesting dyn offset for invalid binding/array idx pair 136 return -1; 137 } 138 return dyn_off->second; 139 } 140 // For a particular binding, get the global index range 141 // This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists 142 const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t) const; 143 const cvdescriptorset::IndexRange &GetGlobalIndexRangeFromIndex(uint32_t index) const; 144 145 // Helper function to get the next valid binding for a descriptor 146 uint32_t GetNextValidBinding(const uint32_t) const; IsPushDescriptor()147 bool IsPushDescriptor() const { return GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR; }; 148 149 struct BindingTypeStats { 150 uint32_t dynamic_buffer_count; 151 uint32_t non_dynamic_buffer_count; 152 uint32_t image_sampler_count; 153 }; GetBindingTypeStats()154 const BindingTypeStats &GetBindingTypeStats() const { return binding_type_stats_; } 155 156 private: 157 // Only the first three data members are used for hash and equality checks, the other members are derived from them, and are 158 // used to speed up the various lookups/queries/validations 159 VkDescriptorSetLayoutCreateFlags flags_; 160 std::vector<safe_VkDescriptorSetLayoutBinding> bindings_; 161 std::vector<VkDescriptorBindingFlagsEXT> binding_flags_; 162 163 // Convenience data structures for rapid lookup of various descriptor set layout properties 164 std::set<uint32_t> non_empty_bindings_; // Containing non-emtpy bindings in numerical order 165 std::unordered_map<uint32_t, uint32_t> binding_to_index_map_; 166 // The following map allows an non-iterative lookup of a binding from a global index... 167 std::vector<IndexRange> global_index_range_; // range is exclusive of .end 168 // For a given binding map to associated index in the dynamic offset array 169 std::unordered_map<uint32_t, uint32_t> binding_to_dynamic_array_idx_map_; 170 171 uint32_t binding_count_; // # of bindings in this layout 172 uint32_t descriptor_count_; // total # descriptors in this layout 173 uint32_t dynamic_descriptor_count_; 174 BindingTypeStats binding_type_stats_; 175 }; 176 177 static inline bool operator==(const DescriptorSetLayoutDef &lhs, const DescriptorSetLayoutDef &rhs) { 178 bool result = (lhs.GetCreateFlags() == rhs.GetCreateFlags()) && (lhs.GetBindings() == rhs.GetBindings()) && 179 (lhs.GetBindingFlags() == rhs.GetBindingFlags()); 180 return result; 181 } 182 183 // Canonical dictionary of DSL definitions -- independent of device or handle 184 using DescriptorSetLayoutDict = hash_util::Dictionary<DescriptorSetLayoutDef, hash_util::HasHashMember<DescriptorSetLayoutDef>>; 185 using DescriptorSetLayoutId = DescriptorSetLayoutDict::Id; 186 187 class DescriptorSetLayout { 188 public: 189 // Constructors and destructor 190 DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *p_create_info, const VkDescriptorSetLayout layout); HasBinding(const uint32_t binding)191 bool HasBinding(const uint32_t binding) const { return layout_id_->HasBinding(binding); } 192 // Return true if this layout is compatible with passed in layout from a pipelineLayout, 193 // else return false and update error_msg with description of incompatibility 194 // Return true if this layout is compatible with passed in layout 195 bool IsCompatible(DescriptorSetLayout const *rh_ds_layout) const; 196 // Straightforward Get functions GetDescriptorSetLayout()197 VkDescriptorSetLayout GetDescriptorSetLayout() const { return layout_; }; IsDestroyed()198 bool IsDestroyed() const { return layout_destroyed_; } MarkDestroyed()199 void MarkDestroyed() { layout_destroyed_ = true; } GetLayoutDef()200 const DescriptorSetLayoutDef *GetLayoutDef() const { return layout_id_.get(); } GetLayoutId()201 DescriptorSetLayoutId GetLayoutId() const { return layout_id_; } GetTotalDescriptorCount()202 uint32_t GetTotalDescriptorCount() const { return layout_id_->GetTotalDescriptorCount(); }; GetDynamicDescriptorCount()203 uint32_t GetDynamicDescriptorCount() const { return layout_id_->GetDynamicDescriptorCount(); }; GetBindingCount()204 uint32_t GetBindingCount() const { return layout_id_->GetBindingCount(); }; GetCreateFlags()205 VkDescriptorSetLayoutCreateFlags GetCreateFlags() const { return layout_id_->GetCreateFlags(); } 206 bool IsNextBindingConsistent(const uint32_t) const; GetIndexFromBinding(uint32_t binding)207 uint32_t GetIndexFromBinding(uint32_t binding) const { return layout_id_->GetIndexFromBinding(binding); } 208 // Various Get functions that can either be passed a binding#, which will 209 // be automatically translated into the appropriate index, or the index# can be passed in directly GetMaxBinding()210 uint32_t GetMaxBinding() const { return layout_id_->GetMaxBinding(); } GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index)211 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) const { 212 return layout_id_->GetDescriptorSetLayoutBindingPtrFromIndex(index); 213 } GetDescriptorSetLayoutBindingPtrFromBinding(uint32_t binding)214 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(uint32_t binding) const { 215 return layout_id_->GetDescriptorSetLayoutBindingPtrFromBinding(binding); 216 } GetBindings()217 const std::vector<safe_VkDescriptorSetLayoutBinding> &GetBindings() const { return layout_id_->GetBindings(); } GetSortedBindingSet()218 const std::set<uint32_t> &GetSortedBindingSet() const { return layout_id_->GetSortedBindingSet(); } GetDescriptorCountFromIndex(const uint32_t index)219 uint32_t GetDescriptorCountFromIndex(const uint32_t index) const { return layout_id_->GetDescriptorCountFromIndex(index); } GetDescriptorCountFromBinding(const uint32_t binding)220 uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const { 221 return layout_id_->GetDescriptorCountFromBinding(binding); 222 } GetTypeFromIndex(const uint32_t index)223 VkDescriptorType GetTypeFromIndex(const uint32_t index) const { return layout_id_->GetTypeFromIndex(index); } GetTypeFromBinding(const uint32_t binding)224 VkDescriptorType GetTypeFromBinding(const uint32_t binding) const { return layout_id_->GetTypeFromBinding(binding); } GetStageFlagsFromIndex(const uint32_t index)225 VkShaderStageFlags GetStageFlagsFromIndex(const uint32_t index) const { return layout_id_->GetStageFlagsFromIndex(index); } GetStageFlagsFromBinding(const uint32_t binding)226 VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t binding) const { 227 return layout_id_->GetStageFlagsFromBinding(binding); 228 } GetDescriptorBindingFlagsFromIndex(const uint32_t index)229 VkDescriptorBindingFlagsEXT GetDescriptorBindingFlagsFromIndex(const uint32_t index) const { 230 return layout_id_->GetDescriptorBindingFlagsFromIndex(index); 231 } GetDescriptorBindingFlagsFromBinding(const uint32_t binding)232 VkDescriptorBindingFlagsEXT GetDescriptorBindingFlagsFromBinding(const uint32_t binding) const { 233 return layout_id_->GetDescriptorBindingFlagsFromBinding(binding); 234 } GetImmutableSamplerPtrFromBinding(const uint32_t binding)235 VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t binding) const { 236 return layout_id_->GetImmutableSamplerPtrFromBinding(binding); 237 } GetImmutableSamplerPtrFromIndex(const uint32_t index)238 VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t index) const { 239 return layout_id_->GetImmutableSamplerPtrFromIndex(index); 240 } 241 // For a given binding and array index, return the corresponding index into the dynamic offset array GetDynamicOffsetIndexFromBinding(uint32_t binding)242 int32_t GetDynamicOffsetIndexFromBinding(uint32_t binding) const { 243 return layout_id_->GetDynamicOffsetIndexFromBinding(binding); 244 } 245 // For a particular binding, get the global index range 246 // This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists GetGlobalIndexRangeFromBinding(const uint32_t binding)247 const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t binding) const { 248 return layout_id_->GetGlobalIndexRangeFromBinding(binding); 249 } GetGlobalIndexRangeFromIndex(uint32_t index)250 const IndexRange &GetGlobalIndexRangeFromIndex(uint32_t index) const { return layout_id_->GetGlobalIndexRangeFromIndex(index); } 251 252 // Helper function to get the next valid binding for a descriptor GetNextValidBinding(const uint32_t binding)253 uint32_t GetNextValidBinding(const uint32_t binding) const { return layout_id_->GetNextValidBinding(binding); } IsPushDescriptor()254 bool IsPushDescriptor() const { return layout_id_->IsPushDescriptor(); } IsVariableDescriptorCountFromIndex(uint32_t index)255 bool IsVariableDescriptorCountFromIndex(uint32_t index) const { 256 return !!(GetDescriptorBindingFlagsFromIndex(index) & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT); 257 } IsVariableDescriptorCount(uint32_t binding)258 bool IsVariableDescriptorCount(uint32_t binding) const { 259 return IsVariableDescriptorCountFromIndex(GetIndexFromBinding(binding)); 260 } 261 262 using BindingTypeStats = DescriptorSetLayoutDef::BindingTypeStats; GetBindingTypeStats()263 const BindingTypeStats &GetBindingTypeStats() const { return layout_id_->GetBindingTypeStats(); } 264 265 // Binding Iterator 266 class ConstBindingIterator { 267 public: 268 ConstBindingIterator() = delete; 269 ConstBindingIterator(const ConstBindingIterator &other) = default; 270 ConstBindingIterator &operator=(const ConstBindingIterator &rhs) = default; 271 ConstBindingIterator(const DescriptorSetLayout * layout)272 ConstBindingIterator(const DescriptorSetLayout *layout) : layout_(layout), index_(0) { assert(layout); } ConstBindingIterator(const DescriptorSetLayout * layout,uint32_t binding)273 ConstBindingIterator(const DescriptorSetLayout *layout, uint32_t binding) : ConstBindingIterator(layout) { 274 index_ = layout->GetIndexFromBinding(binding); 275 } 276 GetDescriptorSetLayoutBindingPtr()277 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtr() const { 278 return layout_->GetDescriptorSetLayoutBindingPtrFromIndex(index_); 279 } GetDescriptorCount()280 uint32_t GetDescriptorCount() const { return layout_->GetDescriptorCountFromIndex(index_); } GetType()281 VkDescriptorType GetType() const { return layout_->GetTypeFromIndex(index_); } GetStageFlags()282 VkShaderStageFlags GetStageFlags() const { return layout_->GetStageFlagsFromIndex(index_); } 283 GetDescriptorBindingFlags()284 VkDescriptorBindingFlagsEXT GetDescriptorBindingFlags() const { 285 return layout_->GetDescriptorBindingFlagsFromIndex(index_); 286 } 287 IsVariableDescriptorCount()288 bool IsVariableDescriptorCount() const { return layout_->IsVariableDescriptorCountFromIndex(index_); } 289 GetImmutableSamplerPtr()290 VkSampler const *GetImmutableSamplerPtr() const { return layout_->GetImmutableSamplerPtrFromIndex(index_); } GetGlobalIndexRange()291 const IndexRange &GetGlobalIndexRange() const { return layout_->GetGlobalIndexRangeFromIndex(index_); } AtEnd()292 bool AtEnd() const { return index_ == layout_->GetBindingCount(); } 293 294 // Return index into dynamic offset array for given binding GetDynamicOffsetIndex()295 int32_t GetDynamicOffsetIndex() const { 296 return layout_->GetDynamicOffsetIndexFromBinding(Binding()); // There is only binding mapped access in layout_ 297 } 298 299 bool operator==(const ConstBindingIterator &rhs) { return (index_ = rhs.index_) && (layout_ == rhs.layout_); } 300 301 ConstBindingIterator &operator++() { 302 if (!AtEnd()) { 303 index_++; 304 } 305 return *this; 306 } 307 IsConsistent(const ConstBindingIterator & other)308 bool IsConsistent(const ConstBindingIterator &other) const { 309 if (AtEnd() || other.AtEnd()) { 310 return false; 311 } 312 const auto *binding_ci = GetDescriptorSetLayoutBindingPtr(); 313 const auto *other_binding_ci = other.GetDescriptorSetLayoutBindingPtr(); 314 assert((binding_ci != nullptr) && (other_binding_ci != nullptr)); 315 316 if ((binding_ci->descriptorType != other_binding_ci->descriptorType) || 317 (binding_ci->stageFlags != other_binding_ci->stageFlags) || 318 (!hash_util::similar_for_nullity(binding_ci->pImmutableSamplers, other_binding_ci->pImmutableSamplers)) || 319 (GetDescriptorBindingFlags() != other.GetDescriptorBindingFlags())) { 320 return false; 321 } 322 return true; 323 } 324 Layout()325 const DescriptorSetLayout *Layout() const { return layout_; } Binding()326 uint32_t Binding() const { return layout_->GetBindings()[index_].binding; } Next()327 ConstBindingIterator Next() { 328 ConstBindingIterator next(*this); 329 ++next; 330 return next; 331 } 332 333 private: 334 const DescriptorSetLayout *layout_; 335 uint32_t index_; 336 }; end()337 ConstBindingIterator end() const { return ConstBindingIterator(this, GetBindingCount()); } 338 339 private: 340 VkDescriptorSetLayout layout_; 341 bool layout_destroyed_; 342 DescriptorSetLayoutId layout_id_; 343 }; 344 345 /* 346 * Descriptor classes 347 * Descriptor is an abstract base class from which 5 separate descriptor types are derived. 348 * This allows the WriteUpdate() and CopyUpdate() operations to be specialized per 349 * descriptor type, but all descriptors in a set can be accessed via the common Descriptor*. 350 */ 351 352 // Slightly broader than type, each c++ "class" will has a corresponding "DescriptorClass" 353 enum DescriptorClass { PlainSampler, ImageSampler, Image, TexelBuffer, GeneralBuffer, InlineUniform, AccelerationStructure }; 354 355 class Descriptor { 356 public: ~Descriptor()357 virtual ~Descriptor(){}; 358 virtual void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) = 0; 359 virtual void CopyUpdate(const Descriptor *) = 0; 360 // Create binding between resources of this descriptor and given cb_node 361 virtual void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) = 0; GetClass()362 virtual DescriptorClass GetClass() const { return descriptor_class; }; 363 // Special fast-path check for SamplerDescriptors that are immutable IsImmutableSampler()364 virtual bool IsImmutableSampler() const { return false; }; 365 // Check for dynamic descriptor type IsDynamic()366 virtual bool IsDynamic() const { return false; }; 367 // Check for storage descriptor type IsStorage()368 virtual bool IsStorage() const { return false; }; 369 bool updated; // Has descriptor been updated? 370 DescriptorClass descriptor_class; 371 }; 372 373 // Return true if this layout is compatible with passed in layout from a pipelineLayout, 374 // else return false and update error_msg with description of incompatibility 375 bool VerifySetLayoutCompatibility(DescriptorSetLayout const *lh_ds_layout, DescriptorSetLayout const *rh_ds_layout, 376 std::string *error_msg); 377 bool ValidateDescriptorSetLayoutCreateInfo(const debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *create_info, 378 const bool push_descriptor_ext, const uint32_t max_push_descriptors, 379 const bool descriptor_indexing_ext, 380 const VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features, 381 const VkPhysicalDeviceInlineUniformBlockFeaturesEXT *inline_uniform_block_features, 382 const VkPhysicalDeviceInlineUniformBlockPropertiesEXT *inline_uniform_block_props, 383 const DeviceExtensions *device_extensions); 384 385 class SamplerDescriptor : public Descriptor { 386 public: 387 SamplerDescriptor(const VkSampler *); 388 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override; 389 void CopyUpdate(const Descriptor *) override; 390 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override; IsImmutableSampler()391 virtual bool IsImmutableSampler() const override { return immutable_; }; GetSampler()392 VkSampler GetSampler() const { return sampler_; } 393 394 private: 395 VkSampler sampler_; 396 bool immutable_; 397 }; 398 399 class ImageSamplerDescriptor : public Descriptor { 400 public: 401 ImageSamplerDescriptor(const VkSampler *); 402 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override; 403 void CopyUpdate(const Descriptor *) override; 404 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override; IsImmutableSampler()405 virtual bool IsImmutableSampler() const override { return immutable_; }; GetSampler()406 VkSampler GetSampler() const { return sampler_; } GetImageView()407 VkImageView GetImageView() const { return image_view_; } GetImageLayout()408 VkImageLayout GetImageLayout() const { return image_layout_; } 409 410 private: 411 VkSampler sampler_; 412 bool immutable_; 413 VkImageView image_view_; 414 VkImageLayout image_layout_; 415 }; 416 417 class ImageDescriptor : public Descriptor { 418 public: 419 ImageDescriptor(const VkDescriptorType); 420 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override; 421 void CopyUpdate(const Descriptor *) override; 422 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override; IsStorage()423 virtual bool IsStorage() const override { return storage_; } GetImageView()424 VkImageView GetImageView() const { return image_view_; } GetImageLayout()425 VkImageLayout GetImageLayout() const { return image_layout_; } 426 427 private: 428 bool storage_; 429 VkImageView image_view_; 430 VkImageLayout image_layout_; 431 }; 432 433 class TexelDescriptor : public Descriptor { 434 public: 435 TexelDescriptor(const VkDescriptorType); 436 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override; 437 void CopyUpdate(const Descriptor *) override; 438 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override; IsStorage()439 virtual bool IsStorage() const override { return storage_; } GetBufferView()440 VkBufferView GetBufferView() const { return buffer_view_; } 441 442 private: 443 VkBufferView buffer_view_; 444 bool storage_; 445 }; 446 447 class BufferDescriptor : public Descriptor { 448 public: 449 BufferDescriptor(const VkDescriptorType); 450 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override; 451 void CopyUpdate(const Descriptor *) override; 452 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override; IsDynamic()453 virtual bool IsDynamic() const override { return dynamic_; } IsStorage()454 virtual bool IsStorage() const override { return storage_; } GetBuffer()455 VkBuffer GetBuffer() const { return buffer_; } GetOffset()456 VkDeviceSize GetOffset() const { return offset_; } GetRange()457 VkDeviceSize GetRange() const { return range_; } 458 459 private: 460 bool storage_; 461 bool dynamic_; 462 VkBuffer buffer_; 463 VkDeviceSize offset_; 464 VkDeviceSize range_; 465 }; 466 467 class InlineUniformDescriptor : public Descriptor { 468 public: InlineUniformDescriptor(const VkDescriptorType)469 InlineUniformDescriptor(const VkDescriptorType) { 470 updated = false; 471 descriptor_class = InlineUniform; 472 } WriteUpdate(const VkWriteDescriptorSet *,const uint32_t)473 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override { updated = true; } CopyUpdate(const Descriptor *)474 void CopyUpdate(const Descriptor *) override { updated = true; } UpdateDrawState(ValidationStateTracker *,CMD_BUFFER_STATE *)475 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override {} 476 }; 477 478 class AccelerationStructureDescriptor : public Descriptor { 479 public: AccelerationStructureDescriptor(const VkDescriptorType)480 AccelerationStructureDescriptor(const VkDescriptorType) { 481 updated = false; 482 descriptor_class = AccelerationStructure; 483 } WriteUpdate(const VkWriteDescriptorSet *,const uint32_t)484 void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override { updated = true; } CopyUpdate(const Descriptor *)485 void CopyUpdate(const Descriptor *) override { updated = true; } UpdateDrawState(ValidationStateTracker *,CMD_BUFFER_STATE *)486 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *) override {} 487 }; 488 489 // Structs to contain common elements that need to be shared between Validate* and Perform* calls below 490 struct AllocateDescriptorSetsData { 491 std::map<uint32_t, uint32_t> required_descriptors_by_type; 492 std::vector<std::shared_ptr<DescriptorSetLayout const>> layout_nodes; 493 AllocateDescriptorSetsData(uint32_t); 494 }; 495 // Helper functions for descriptor set functions that cross multiple sets 496 // "Validate" will make sure an update is ok without actually performing it 497 bool ValidateUpdateDescriptorSets(const debug_report_data *, const CoreChecks *, uint32_t, const VkWriteDescriptorSet *, uint32_t, 498 const VkCopyDescriptorSet *, const char *func_name); 499 // "Perform" does the update with the assumption that ValidateUpdateDescriptorSets() has passed for the given update 500 void PerformUpdateDescriptorSets(ValidationStateTracker *, uint32_t, const VkWriteDescriptorSet *, uint32_t, 501 const VkCopyDescriptorSet *); 502 503 // Core Validation specific validation checks using DescriptorSet and DescriptorSetLayoutAccessors 504 // TODO: migrate out of descriptor_set.cpp/h 505 // For a particular binding starting at offset and having update_count descriptors 506 // updated, verify that for any binding boundaries crossed, the update is consistent 507 bool VerifyUpdateConsistency(DescriptorSetLayout::ConstBindingIterator current_binding, uint32_t offset, uint32_t update_count, 508 const char *type, const VkDescriptorSet set, std::string *error_msg); 509 510 // Validate buffer descriptor update info 511 bool ValidateBufferUsage(BUFFER_STATE const *buffer_node, VkDescriptorType type, std::string *error_code, std::string *error_msg); 512 513 // Helper class to encapsulate the descriptor update template decoding logic 514 struct DecodedTemplateUpdate { 515 std::vector<VkWriteDescriptorSet> desc_writes; 516 std::vector<VkWriteDescriptorSetInlineUniformBlockEXT> inline_infos; 517 DecodedTemplateUpdate(const ValidationStateTracker *device_data, VkDescriptorSet descriptorSet, 518 const TEMPLATE_STATE *template_state, const void *pData, 519 VkDescriptorSetLayout push_layout = VK_NULL_HANDLE); 520 }; 521 522 /* 523 * DescriptorSet class 524 * 525 * Overview - This class encapsulates the Vulkan VkDescriptorSet data (set). 526 * A set has an underlying layout which defines the bindings in the set and the 527 * types and numbers of descriptors in each descriptor slot. Most of the layout 528 * interfaces are exposed through identically-named functions in the set class. 529 * Please refer to the DescriptorSetLayout comment above for a description of 530 * index, binding, and global index. 531 * 532 * At construction a vector of Descriptor* is created with types corresponding to the 533 * layout. The primary operation performed on the descriptors is to update them 534 * via write or copy updates, and validate that the update contents are correct. 535 * In order to validate update contents, the DescriptorSet stores a bunch of ptrs 536 * to data maps where various Vulkan objects can be looked up. The management of 537 * those maps is performed externally. The set class relies on their contents to 538 * be correct at the time of update. 539 */ 540 class DescriptorSet : public BASE_NODE { 541 public: 542 using StateTracker = ValidationStateTracker; 543 DescriptorSet(const VkDescriptorSet, const VkDescriptorPool, const std::shared_ptr<DescriptorSetLayout const> &, 544 uint32_t variable_count, StateTracker *); 545 ~DescriptorSet(); 546 // A number of common Get* functions that return data based on layout from which this set was created GetTotalDescriptorCount()547 uint32_t GetTotalDescriptorCount() const { return p_layout_->GetTotalDescriptorCount(); }; GetDynamicDescriptorCount()548 uint32_t GetDynamicDescriptorCount() const { return p_layout_->GetDynamicDescriptorCount(); }; GetBindingCount()549 uint32_t GetBindingCount() const { return p_layout_->GetBindingCount(); }; GetTypeFromIndex(const uint32_t index)550 VkDescriptorType GetTypeFromIndex(const uint32_t index) const { return p_layout_->GetTypeFromIndex(index); }; GetTypeFromBinding(const uint32_t binding)551 VkDescriptorType GetTypeFromBinding(const uint32_t binding) const { return p_layout_->GetTypeFromBinding(binding); }; GetDescriptorCountFromIndex(const uint32_t index)552 uint32_t GetDescriptorCountFromIndex(const uint32_t index) const { return p_layout_->GetDescriptorCountFromIndex(index); }; GetDescriptorCountFromBinding(const uint32_t binding)553 uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const { 554 return p_layout_->GetDescriptorCountFromBinding(binding); 555 }; 556 // Return index into dynamic offset array for given binding GetDynamicOffsetIndexFromBinding(uint32_t binding)557 int32_t GetDynamicOffsetIndexFromBinding(uint32_t binding) const { 558 return p_layout_->GetDynamicOffsetIndexFromBinding(binding); 559 } 560 // Return true if given binding is present in this set HasBinding(const uint32_t binding)561 bool HasBinding(const uint32_t binding) const { return p_layout_->HasBinding(binding); }; 562 563 std::string StringifySetAndLayout() const; 564 565 // Perform a push update whose contents were just validated using ValidatePushDescriptorsUpdate 566 void PerformPushDescriptorsUpdate(uint32_t write_count, const VkWriteDescriptorSet *p_wds); 567 // Perform a WriteUpdate whose contents were just validated using ValidateWriteUpdate 568 void PerformWriteUpdate(const VkWriteDescriptorSet *); 569 // Perform a CopyUpdate whose contents were just validated using ValidateCopyUpdate 570 void PerformCopyUpdate(const VkCopyDescriptorSet *, const DescriptorSet *); 571 GetLayout()572 const std::shared_ptr<DescriptorSetLayout const> GetLayout() const { return p_layout_; }; GetDescriptorSetLayout()573 VkDescriptorSetLayout GetDescriptorSetLayout() const { return p_layout_->GetDescriptorSetLayout(); } GetSet()574 VkDescriptorSet GetSet() const { return set_; }; 575 // Return unordered_set of all command buffers that this set is bound to GetBoundCmdBuffers()576 std::unordered_set<CMD_BUFFER_STATE *> GetBoundCmdBuffers() const { return cb_bindings; } 577 // Bind given cmd_buffer to this descriptor set and 578 // update CB image layout map with image/imagesampler descriptor image layouts 579 void UpdateDrawState(ValidationStateTracker *, CMD_BUFFER_STATE *, const std::map<uint32_t, descriptor_req> &); 580 581 // Track work that has been bound or validated to avoid duplicate work, important when large descriptor arrays 582 // are present 583 typedef std::unordered_set<uint32_t> TrackedBindings; 584 static void FilterOneBindingReq(const BindingReqMap::value_type &binding_req_pair, BindingReqMap *out_req, 585 const TrackedBindings &set, uint32_t limit); 586 void FilterBindingReqs(const CMD_BUFFER_STATE &, const PIPELINE_STATE &, const BindingReqMap &in_req, 587 BindingReqMap *out_req) const; 588 void UpdateValidationCache(const CMD_BUFFER_STATE &cb_state, const PIPELINE_STATE &pipeline, 589 const BindingReqMap &updated_bindings); ClearCachedDynamicDescriptorValidation(CMD_BUFFER_STATE * cb_state)590 void ClearCachedDynamicDescriptorValidation(CMD_BUFFER_STATE *cb_state) { 591 cached_validation_[cb_state].dynamic_buffers.clear(); 592 } ClearCachedValidation(CMD_BUFFER_STATE * cb_state)593 void ClearCachedValidation(CMD_BUFFER_STATE *cb_state) { cached_validation_.erase(cb_state); } 594 // If given cmd_buffer is in the cb_bindings set, remove it RemoveBoundCommandBuffer(CMD_BUFFER_STATE * cb_node)595 void RemoveBoundCommandBuffer(CMD_BUFFER_STATE *cb_node) { 596 cb_bindings.erase(cb_node); 597 ClearCachedValidation(cb_node); 598 } GetImmutableSamplerPtrFromBinding(const uint32_t index)599 VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t index) const { 600 return p_layout_->GetImmutableSamplerPtrFromBinding(index); 601 }; 602 // For a particular binding, get the global index 603 const IndexRange GetGlobalIndexRangeFromBinding(const uint32_t binding, bool actual_length = false) const { 604 if (actual_length && binding == p_layout_->GetMaxBinding() && IsVariableDescriptorCount(binding)) { 605 IndexRange range = p_layout_->GetGlobalIndexRangeFromBinding(binding); 606 auto diff = GetDescriptorCountFromBinding(binding) - GetVariableDescriptorCount(); 607 range.end -= diff; 608 return range; 609 } 610 return p_layout_->GetGlobalIndexRangeFromBinding(binding); 611 }; 612 // Return true if any part of set has ever been updated IsUpdated()613 bool IsUpdated() const { return some_update_; }; IsPushDescriptor()614 bool IsPushDescriptor() const { return p_layout_->IsPushDescriptor(); }; IsVariableDescriptorCount(uint32_t binding)615 bool IsVariableDescriptorCount(uint32_t binding) const { return p_layout_->IsVariableDescriptorCount(binding); } IsUpdateAfterBind(uint32_t binding)616 bool IsUpdateAfterBind(uint32_t binding) const { 617 return !!(p_layout_->GetDescriptorBindingFlagsFromBinding(binding) & VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT); 618 } GetVariableDescriptorCount()619 uint32_t GetVariableDescriptorCount() const { return variable_count_; } GetPoolState()620 DESCRIPTOR_POOL_STATE *GetPoolState() const { return pool_state_; } GetDescriptorFromGlobalIndex(const uint32_t index)621 const Descriptor *GetDescriptorFromGlobalIndex(const uint32_t index) const { return descriptors_[index].get(); } GetChangeCount()622 uint64_t GetChangeCount() const { return change_count_; } 623 624 private: 625 // Private helper to set all bound cmd buffers to INVALID state 626 void InvalidateBoundCmdBuffers(); 627 bool some_update_; // has any part of the set ever been updated? 628 VkDescriptorSet set_; 629 DESCRIPTOR_POOL_STATE *pool_state_; 630 const std::shared_ptr<DescriptorSetLayout const> p_layout_; 631 std::vector<std::unique_ptr<Descriptor>> descriptors_; 632 StateTracker *state_data_; 633 uint32_t variable_count_; 634 uint64_t change_count_; 635 636 // Cached binding and validation support: 637 // 638 // For the lifespan of a given command buffer recording, do lazy evaluation, caching, and dirtying of 639 // expensive validation operation (typically per-draw) 640 typedef std::unordered_map<CMD_BUFFER_STATE *, TrackedBindings> TrackedBindingMap; 641 // Track the validation caching of bindings vs. the command buffer and draw state 642 typedef std::unordered_map<uint32_t, CMD_BUFFER_STATE::ImageLayoutUpdateCount> VersionedBindings; 643 struct CachedValidation { 644 TrackedBindings command_binding_and_usage; // Persistent for the life of the recording 645 TrackedBindings non_dynamic_buffers; // Persistent for the life of the recording 646 TrackedBindings dynamic_buffers; // Dirtied (flushed) each BindDescriptorSet 647 std::unordered_map<const PIPELINE_STATE *, VersionedBindings> image_samplers; // Tested vs. changes to CB's ImageLayout 648 }; 649 typedef std::unordered_map<const CMD_BUFFER_STATE *, CachedValidation> CachedValidationMap; 650 // Image and ImageView bindings are validated per pipeline and not invalidate by repeated binding 651 CachedValidationMap cached_validation_; 652 }; 653 // For the "bindless" style resource usage with many descriptors, need to optimize binding and validation 654 class PrefilterBindRequestMap { 655 public: 656 static const uint32_t kManyDescriptors_ = 64; // TODO base this number on measured data 657 std::unique_ptr<BindingReqMap> filtered_map_; 658 const BindingReqMap &orig_map_; 659 const DescriptorSet &descriptor_set_; 660 PrefilterBindRequestMap(const DescriptorSet & ds,const BindingReqMap & in_map)661 PrefilterBindRequestMap(const DescriptorSet &ds, const BindingReqMap &in_map) 662 : filtered_map_(), orig_map_(in_map), descriptor_set_(ds) {} 663 const BindingReqMap &FilteredMap(const CMD_BUFFER_STATE &cb_state, const PIPELINE_STATE &); IsManyDescriptors()664 bool IsManyDescriptors() const { return descriptor_set_.GetTotalDescriptorCount() > kManyDescriptors_; } 665 }; 666 } // namespace cvdescriptorset 667 #endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_ 668