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