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