Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
      2  * Copyright (c) 2015-2016 Valve Corporation
      3  * Copyright (c) 2015-2016 LunarG, Inc.
      4  * Copyright (C) 2015-2016 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  */
     20 #ifndef CORE_VALIDATION_DESCRIPTOR_SETS_H_
     21 #define CORE_VALIDATION_DESCRIPTOR_SETS_H_
     22 
     23 // Check for noexcept support
     24 #if defined(__clang__)
     25 #if __has_feature(cxx_noexcept)
     26 #define HAS_NOEXCEPT
     27 #endif
     28 #else
     29 #if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46
     30 #define HAS_NOEXCEPT
     31 #else
     32 #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 && defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS
     33 #define HAS_NOEXCEPT
     34 #endif
     35 #endif
     36 #endif
     37 
     38 #ifdef HAS_NOEXCEPT
     39 #define NOEXCEPT noexcept
     40 #else
     41 #define NOEXCEPT
     42 #endif
     43 
     44 #include "core_validation_error_enums.h"
     45 #include "core_validation_types.h"
     46 #include "vk_layer_logging.h"
     47 #include "vk_layer_utils.h"
     48 #include "vk_safe_struct.h"
     49 #include "vulkan/vk_layer.h"
     50 #include <memory>
     51 #include <unordered_map>
     52 #include <unordered_set>
     53 #include <vector>
     54 
     55 // Descriptor Data structures
     56 
     57 /*
     58  * DescriptorSetLayout class
     59  *
     60  * Overview - This class encapsulates the Vulkan VkDescriptorSetLayout data (layout).
     61  *   A layout consists of some number of bindings, each of which has a binding#, a
     62  *   type, descriptor count, stage flags, and pImmutableSamplers.
     63  *
     64  * Index vs Binding - A layout is created with an array of VkDescriptorSetLayoutBinding
     65  *  where each array index will have a corresponding binding# that is defined in that struct.
     66  *  This class, therefore, provides utility functions where you can retrieve data for
     67  *  layout bindings based on either the original index into the pBindings array, or based
     68  *  on the binding#.
     69  *  Typically if you want to cover all of the bindings in a layout, you can do that by
     70  *   iterating over GetBindingCount() bindings and using the Get*FromIndex() functions.
     71  *  Otherwise, you can use the Get*FromBinding() functions to just grab binding info
     72  *   for a particular binding#.
     73  *
     74  * Global Index - The "Index" referenced above is the index into the original pBindings
     75  *  array. So there are as many indices as there are bindings.
     76  *  This class also has the concept of a Global Index. For the global index functions,
     77  *  there are as many global indices as there are descriptors in the layout.
     78  *  For the global index, consider all of the bindings to be a flat array where
     79  *  descriptor 0 of pBinding[0] is index 0 and each descriptor in the layout increments
     80  *  from there. So if pBinding[0] in this example had descriptorCount of 10, then
     81  *  the GlobalStartIndex of pBinding[1] will be 10 where 0-9 are the global indices
     82  *  for pBinding[0].
     83  */
     84 namespace cvdescriptorset {
     85 class DescriptorSetLayout {
     86   public:
     87     // Constructors and destructor
     88     DescriptorSetLayout(debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *p_create_info,
     89                         const VkDescriptorSetLayout layout);
     90     // Straightforward Get functions
     91     VkDescriptorSetLayout GetDescriptorSetLayout() const { return layout_; };
     92     uint32_t GetTotalDescriptorCount() const { return descriptor_count_; };
     93     uint32_t GetDynamicDescriptorCount() const { return dynamic_descriptor_count_; };
     94     uint32_t GetBindingCount() const { return binding_count_; };
     95     // Fill passed-in set with bindings
     96     void FillBindingSet(std::unordered_set<uint32_t> *) const;
     97     // Return true if given binding is present in this layout
     98     bool HasBinding(const uint32_t binding) const { return binding_to_index_map_.count(binding) > 0; };
     99     // Return true if this layout is compatible with passed in layout,
    100     //   else return false and update error_msg with description of incompatibility
    101     bool IsCompatible(const DescriptorSetLayout *, std::string *) const;
    102     // Return true if binding 1 beyond given exists and has same type, stageFlags & immutable sampler use
    103     bool IsNextBindingConsistent(const uint32_t) const;
    104     // Various Get functions that can either be passed a binding#, which will
    105     //  be automatically translated into the appropriate index from the original
    106     //  pBindings array, or the index# can be passed in directly
    107     VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t) const;
    108     VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t) const;
    109     uint32_t GetDescriptorCountFromBinding(const uint32_t) const;
    110     uint32_t GetDescriptorCountFromIndex(const uint32_t) const;
    111     VkDescriptorType GetTypeFromBinding(const uint32_t) const;
    112     VkDescriptorType GetTypeFromIndex(const uint32_t) const;
    113     VkDescriptorType GetTypeFromGlobalIndex(const uint32_t) const;
    114     VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t) const;
    115     VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t) const;
    116     VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t) const;
    117     // For a particular binding, get the global index
    118     uint32_t GetGlobalStartIndexFromBinding(const uint32_t) const;
    119     uint32_t GetGlobalEndIndexFromBinding(const uint32_t) const;
    120     // For a particular binding starting at offset and having update_count descriptors
    121     //  updated, verify that for any binding boundaries crossed, the update is consistent
    122     bool VerifyUpdateConsistency(uint32_t, uint32_t, uint32_t, const char *, const VkDescriptorSet, std::string *) const;
    123 
    124   private:
    125     VkDescriptorSetLayout layout_;
    126     std::unordered_map<uint32_t, uint32_t> binding_to_index_map_;
    127     std::unordered_map<uint32_t, uint32_t> binding_to_global_start_index_map_;
    128     std::unordered_map<uint32_t, uint32_t> binding_to_global_end_index_map_;
    129     // VkDescriptorSetLayoutCreateFlags flags_;
    130     uint32_t binding_count_; // # of bindings in this layout
    131     std::vector<safe_VkDescriptorSetLayoutBinding> bindings_;
    132     uint32_t descriptor_count_; // total # descriptors in this layout
    133     uint32_t dynamic_descriptor_count_;
    134 };
    135 
    136 /*
    137  * Descriptor classes
    138  *  Descriptor is an abstract base class from which 5 separate descriptor types are derived.
    139  *   This allows the WriteUpdate() and CopyUpdate() operations to be specialized per
    140  *   descriptor type, but all descriptors in a set can be accessed via the common Descriptor*.
    141  */
    142 
    143 // Slightly broader than type, each c++ "class" will has a corresponding "DescriptorClass"
    144 enum DescriptorClass { PlainSampler, ImageSampler, Image, TexelBuffer, GeneralBuffer };
    145 
    146 class Descriptor {
    147   public:
    148     virtual ~Descriptor(){};
    149     virtual void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) = 0;
    150     virtual void CopyUpdate(const Descriptor *) = 0;
    151     virtual DescriptorClass GetClass() const { return descriptor_class; };
    152     // Special fast-path check for SamplerDescriptors that are immutable
    153     virtual bool IsImmutableSampler() const { return false; };
    154     // Check for dynamic descriptor type
    155     virtual bool IsDynamic() const { return false; };
    156     // Check for storage descriptor type
    157     virtual bool IsStorage() const { return false; };
    158     bool updated; // Has descriptor been updated?
    159     DescriptorClass descriptor_class;
    160 };
    161 // Shared helper functions - These are useful because the shared sampler image descriptor type
    162 //  performs common functions with both sampler and image descriptors so they can share their common functions
    163 bool ValidateSampler(const VkSampler, const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *);
    164 bool ValidateImageUpdate(const VkImageView, const VkImageLayout, const std::unordered_map<VkImageView, VkImageViewCreateInfo> *,
    165                          const std::unordered_map<VkImage, IMAGE_NODE> *, const std::unordered_map<VkImage, VkSwapchainKHR> *,
    166                          const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *, std::string *);
    167 
    168 class SamplerDescriptor : public Descriptor {
    169   public:
    170     SamplerDescriptor();
    171     SamplerDescriptor(const VkSampler *);
    172     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
    173     void CopyUpdate(const Descriptor *) override;
    174     virtual bool IsImmutableSampler() const override { return immutable_; };
    175     VkSampler GetSampler() const { return sampler_; }
    176 
    177   private:
    178     // bool ValidateSampler(const VkSampler) const;
    179     VkSampler sampler_;
    180     bool immutable_;
    181 };
    182 
    183 class ImageSamplerDescriptor : public Descriptor {
    184   public:
    185     ImageSamplerDescriptor();
    186     ImageSamplerDescriptor(const VkSampler *);
    187     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
    188     void CopyUpdate(const Descriptor *) override;
    189     virtual bool IsImmutableSampler() const override { return immutable_; };
    190     VkSampler GetSampler() const { return sampler_; }
    191     VkImageView GetImageView() const { return image_view_; }
    192     VkImageLayout GetImageLayout() const { return image_layout_; }
    193 
    194   private:
    195     VkSampler sampler_;
    196     bool immutable_;
    197     VkImageView image_view_;
    198     VkImageLayout image_layout_;
    199 };
    200 
    201 class ImageDescriptor : public Descriptor {
    202   public:
    203     ImageDescriptor(const VkDescriptorType);
    204     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
    205     void CopyUpdate(const Descriptor *) override;
    206     virtual bool IsStorage() const override { return storage_; }
    207     VkImageView GetImageView() const { return image_view_; }
    208     VkImageLayout GetImageLayout() const { return image_layout_; }
    209 
    210   private:
    211     bool storage_;
    212     VkImageView image_view_;
    213     VkImageLayout image_layout_;
    214 };
    215 
    216 class TexelDescriptor : public Descriptor {
    217   public:
    218     TexelDescriptor(const VkDescriptorType);
    219     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
    220     void CopyUpdate(const Descriptor *) override;
    221     virtual bool IsStorage() const override { return storage_; }
    222     VkBufferView GetBufferView() const { return buffer_view_; }
    223 
    224   private:
    225     VkBufferView buffer_view_;
    226     bool storage_;
    227 };
    228 
    229 class BufferDescriptor : public Descriptor {
    230   public:
    231     BufferDescriptor(const VkDescriptorType);
    232     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
    233     void CopyUpdate(const Descriptor *) override;
    234     virtual bool IsDynamic() const override { return dynamic_; }
    235     virtual bool IsStorage() const override { return storage_; }
    236     VkBuffer GetBuffer() const { return buffer_; }
    237     VkDeviceSize GetOffset() const { return offset_; }
    238     VkDeviceSize GetRange() const { return range_; }
    239 
    240   private:
    241     bool storage_;
    242     bool dynamic_;
    243     VkBuffer buffer_;
    244     VkDeviceSize offset_;
    245     VkDeviceSize range_;
    246 };
    247 // Helper functions for Updating descriptor sets since it crosses multiple sets
    248 // Validate will make sure an update is ok without actually performing it
    249 bool ValidateUpdateDescriptorSets(const debug_report_data *,
    250                                   const std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> &, uint32_t,
    251                                   const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet *);
    252 // Perform does the update with the assumption that ValidateUpdateDescriptorSets() has passed for the given update
    253 void PerformUpdateDescriptorSets(const std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> &, uint32_t,
    254                                  const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet *);
    255 /*
    256  * DescriptorSet class
    257  *
    258  * Overview - This class encapsulates the Vulkan VkDescriptorSet data (set).
    259  *   A set has an underlying layout which defines the bindings in the set and the
    260  *   types and numbers of descriptors in each descriptor slot. Most of the layout
    261  *   interfaces are exposed through identically-named functions in the set class.
    262  *   Please refer to the DescriptorSetLayout comment above for a description of
    263  *   index, binding, and global index.
    264  *
    265  * At construction a vector of Descriptor* is created with types corresponding to the
    266  *   layout. The primary operation performed on the descriptors is to update them
    267  *   via write or copy updates, and validate that the update contents are correct.
    268  *   In order to validate update contents, the DescriptorSet stores a bunch of ptrs
    269  *   to data maps where various Vulkan objects can be looked up. The management of
    270  *   those maps is performed externally. The set class relies on their contents to
    271  *   be correct at the time of update.
    272  */
    273 class DescriptorSet : public BASE_NODE {
    274   public:
    275     using BASE_NODE::in_use;
    276     DescriptorSet(const VkDescriptorSet, const DescriptorSetLayout *, const std::unordered_map<VkBuffer, BUFFER_NODE> *,
    277                   const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *,
    278                   const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *,
    279                   const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *,
    280                   const std::unordered_map<VkImageView, VkImageViewCreateInfo> *, const std::unordered_map<VkImage, IMAGE_NODE> *,
    281                   const std::unordered_map<VkImage, VkSwapchainKHR> *,
    282                   const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *);
    283     ~DescriptorSet();
    284     // A number of common Get* functions that return data based on layout from which this set was created
    285     uint32_t GetTotalDescriptorCount() const { return p_layout_ ? p_layout_->GetTotalDescriptorCount() : 0; };
    286     uint32_t GetDynamicDescriptorCount() const { return p_layout_ ? p_layout_->GetDynamicDescriptorCount() : 0; };
    287     uint32_t GetBindingCount() const { return p_layout_ ? p_layout_->GetBindingCount() : 0; };
    288     VkDescriptorType GetTypeFromIndex(const uint32_t index) const {
    289         return p_layout_ ? p_layout_->GetTypeFromIndex(index) : VK_DESCRIPTOR_TYPE_MAX_ENUM;
    290     };
    291     VkDescriptorType GetTypeFromGlobalIndex(const uint32_t index) const {
    292         return p_layout_ ? p_layout_->GetTypeFromGlobalIndex(index) : VK_DESCRIPTOR_TYPE_MAX_ENUM;
    293     };
    294     VkDescriptorType GetTypeFromBinding(const uint32_t binding) const {
    295         return p_layout_ ? p_layout_->GetTypeFromBinding(binding) : VK_DESCRIPTOR_TYPE_MAX_ENUM;
    296     };
    297     uint32_t GetDescriptorCountFromIndex(const uint32_t index) const {
    298         return p_layout_ ? p_layout_->GetDescriptorCountFromIndex(index) : 0;
    299     };
    300     uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const {
    301         return p_layout_ ? p_layout_->GetDescriptorCountFromBinding(binding) : 0;
    302     };
    303     // Return true if given binding is present in this set
    304     bool HasBinding(const uint32_t binding) const { return p_layout_->HasBinding(binding); };
    305     // Is this set compatible with the given layout?
    306     bool IsCompatible(const DescriptorSetLayout *, std::string *) const;
    307     // For given bindings validate state at time of draw is correct, returning false on error and writing error details into string*
    308     bool ValidateDrawState(const std::unordered_set<uint32_t> &, const std::vector<uint32_t> &, std::string *) const;
    309     // For given set of bindings, add any buffers and images that will be updated to their respective unordered_sets & return number
    310     // of objects inserted
    311     uint32_t GetStorageUpdates(const std::unordered_set<uint32_t> &, std::unordered_set<VkBuffer> *,
    312                                std::unordered_set<VkImageView> *) const;
    313     // For all descriptors in a set, add any buffers and images that may be updated to their respective unordered_sets & return
    314     // number of objects inserted
    315     uint32_t GetAllStorageUpdates(std::unordered_set<VkBuffer> *, std::unordered_set<VkImageView> *) const;
    316 
    317     // Descriptor Update functions. These functions validate state and perform update separately
    318     // Validate contents of a WriteUpdate
    319     bool ValidateWriteUpdate(const debug_report_data *, const VkWriteDescriptorSet *, std::string *);
    320     // Perform a WriteUpdate whose contents were just validated using ValidateWriteUpdate
    321     void PerformWriteUpdate(const VkWriteDescriptorSet *);
    322     // Validate contents of a CopyUpdate
    323     bool ValidateCopyUpdate(const debug_report_data *, const VkCopyDescriptorSet *, const DescriptorSet *, std::string *);
    324     // Perform a CopyUpdate whose contents were just validated using ValidateCopyUpdate
    325     void PerformCopyUpdate(const VkCopyDescriptorSet *, const DescriptorSet *);
    326 
    327     const DescriptorSetLayout *GetLayout() const { return p_layout_; };
    328     VkDescriptorSet GetSet() const { return set_; };
    329     // Return unordered_set of all command buffers that this set is bound to
    330     std::unordered_set<GLOBAL_CB_NODE *> GetBoundCmdBuffers() const { return bound_cmd_buffers_; }
    331     // Bind given cmd_buffer to this descriptor set
    332     void BindCommandBuffer(GLOBAL_CB_NODE *cb_node) { bound_cmd_buffers_.insert(cb_node); }
    333     // If given cmd_buffer is in the bound_cmd_buffers_ set, remove it
    334     void RemoveBoundCommandBuffer(GLOBAL_CB_NODE *cb_node) { bound_cmd_buffers_.erase(cb_node); }
    335     VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t index) const {
    336         return p_layout_->GetImmutableSamplerPtrFromBinding(index);
    337     };
    338     // For a particular binding, get the global index
    339     uint32_t GetGlobalStartIndexFromBinding(const uint32_t binding) const {
    340         return p_layout_->GetGlobalStartIndexFromBinding(binding);
    341     };
    342     uint32_t GetGlobalEndIndexFromBinding(const uint32_t binding) const {
    343         return p_layout_->GetGlobalEndIndexFromBinding(binding);
    344     };
    345     // Return true if any part of set has ever been updated
    346     bool IsUpdated() const { return some_update_; };
    347 
    348   private:
    349     bool VerifyWriteUpdateContents(const VkWriteDescriptorSet *, const uint32_t, std::string *) const;
    350     bool VerifyCopyUpdateContents(const VkCopyDescriptorSet *, const DescriptorSet *, const uint32_t, std::string *) const;
    351     // Private helper to set all bound cmd buffers to INVALID state
    352     void InvalidateBoundCmdBuffers();
    353     bool some_update_; // has any part of the set ever been updated?
    354     VkDescriptorSet set_;
    355     const DescriptorSetLayout *p_layout_;
    356     std::unordered_set<GLOBAL_CB_NODE *> bound_cmd_buffers_;
    357     std::vector<std::unique_ptr<Descriptor>> descriptors_;
    358     // Ptrs to object containers to verify bound data
    359     const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map_;
    360     const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *memory_map_;
    361     const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *buffer_view_map_;
    362     const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map_;
    363     const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map_;
    364     // TODO : For next 3 maps all we really need (currently) is an image to format mapping
    365     const std::unordered_map<VkImage, IMAGE_NODE> *image_map_;
    366     const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map_;
    367     const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map_;
    368 };
    369 }
    370 #endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_
    371