• 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 #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