blob: 7f0fd4f4a42a454c2318ceca2a7b7f59a7885877 [file] [log] [blame]
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06001/* 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#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#pragma once
45#include "core_validation_error_enums.h"
46#include "vk_layer_logging.h"
47#include "vk_safe_struct.h"
48#include "vulkan/vk_layer.h"
49#include <unordered_map>
50#include <vector>
51
52// Descriptor Data structures
53
54/*
55 * DescriptorSetLayout class
56 *
57 * Overview - This class encapsulates the Vulkan VkDescriptorSetLayout data (layout).
58 * A layout consists of some number of bindings, each of which has a binding#, a
59 * type, descriptor count, stage flags, and pImmutableSamplers.
60 *
61 * Index vs Binding - A layout is created with an array of VkDescriptorSetLayoutBinding
62 * where each array index will have a corresponding binding# that is defined in that struct.
63 * This class, therefore, provides utility functions where you can retrieve data for
64 * layout bindings based on either the original index into the pBindings array, or based
65 * on the binding#.
66 * Typically if you want to cover all of the bindings in a layout, you can do that by
67 * iterating over GetBindingCount() bindings and using the Get*FromIndex() functions.
68 * Otherwise, you can use the Get*FromBinding() functions to just grab binding info
69 * for a particular binding#.
70 *
71 * Global Index - The "Index" referenced above is the index into the original pBindings
72 * array. So there are as many indices as there are bindings.
73 * This class also has the concept of a Global Index. For the global index functions,
74 * there are as many global indices as there are descriptors in the layout.
75 * For the global index, consider all of the bindings to be a flat array where
76 * descriptor 0 of pBinding[0] is index 0 and each descriptor in the layout increments
77 * from there. So if pBinding[0] in this example had descriptorCount of 10, then
78 * the GlobalStartIndex of pBinding[1] will be 10 where 0-9 are the global indices
79 * for pBinding[0].
80 */
81class DescriptorSetLayout {
82 public:
83 // Constructors and destructor
84 DescriptorSetLayout();
85 DescriptorSetLayout(debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *p_create_info,
86 const VkDescriptorSetLayout layout);
87 ~DescriptorSetLayout();
88 // Straightforward Get functions
89 VkDescriptorSetLayout GetDescriptorSetLayout() { return layout_; };
90 uint32_t GetTotalDescriptorCount() { return descriptor_count_; };
91 uint32_t GetDynamicDescriptorCount() { return dynamic_descriptor_count_; };
92 uint32_t GetBindingCount() { return binding_count_; };
93 // Return true if given binding is present in this layout
94 bool HasBinding(const uint32_t binding) { return binding_to_index_map_.count(binding); };
95 // Return true if this layout is compatible with passed in layout,
96 // else return false and update error_msg with description of incompatibility
97 bool IsCompatible(DescriptorSetLayout *, string *error_msg);
98 // Various Get functions that can either be passed a binding#, which will
99 // be automatically translated into the appropriate index from the original
100 // pBindings array, or the index# can be passed in directly
101 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t);
102 VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t);
103 uint32_t GetDescriptorCountFromBinding(const uint32_t);
104 uint32_t GetDescriptorCountFromIndex(const uint32_t);
105 VkDescriptorType GetTypeFromBinding(const uint32_t);
106 VkDescriptorType GetTypeFromIndex(const uint32_t);
Tobin Ehlis660aba42016-04-26 13:09:51 -0600107 VkDescriptorType GetTypeFromGlobalIndex(const uint32_t);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600108 VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t);
109 VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t);
110 // For a particular binding, get the global index
111 uint32_t GetGlobalStartIndexFromBinding(const uint32_t);
112 uint32_t GetGlobalEndIndexFromBinding(const uint32_t);
113
114 private:
115 VkDescriptorSetLayout layout_;
116 unordered_map<uint32_t, uint32_t> binding_to_index_map_;
117 unordered_map<uint32_t, uint32_t> binding_to_global_start_index_map_;
118 unordered_map<uint32_t, uint32_t> binding_to_global_end_index_map_;
119 VkDescriptorSetLayoutCreateFlags flags_;
120 uint32_t binding_count_; // # of bindings in this layout
Tobin Ehlis546326f2016-04-26 11:06:05 -0600121 vector<safe_VkDescriptorSetLayoutBinding *> bindings_;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600122 uint32_t descriptor_count_; // total # descriptors in this layout
123 uint32_t dynamic_descriptor_count_;
124};
125DescriptorSetLayout::DescriptorSetLayout()
126 : layout_(VK_NULL_HANDLE), flags_(0), binding_count_(0), descriptor_count_(0), dynamic_descriptor_count_(0) {}
127// Construct DescriptorSetLayout instance from given create info
128DescriptorSetLayout::DescriptorSetLayout(debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *p_create_info,
129 const VkDescriptorSetLayout layout)
130 : layout_(layout), flags_(p_create_info->flags), binding_count_(p_create_info->bindingCount), descriptor_count_(0),
131 dynamic_descriptor_count_(0) {
132 uint32_t global_index = 0;
133 for (uint32_t i = 0; i < binding_count_; ++i) {
134 descriptor_count_ += p_create_info->pBindings[i].descriptorCount;
135 if (!binding_to_index_map_.emplace(p_create_info->pBindings[i].binding, i).second) {
136 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
137 reinterpret_cast<uint64_t &>(layout_), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
138 "duplicated binding number in "
139 "VkDescriptorSetLayoutBinding");
140 }
141 binding_to_global_start_index_map_[p_create_info->pBindings[i].binding] = global_index;
142 global_index += p_create_info->pBindings[i].descriptorCount ? p_create_info->pBindings[i].descriptorCount - 1 : 0;
143 binding_to_global_end_index_map_[p_create_info->pBindings[i].binding] = global_index;
144 global_index++;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600145 bindings_.push_back(new safe_VkDescriptorSetLayoutBinding(&p_create_info->pBindings[i]));
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600146 // In cases where we should ignore pImmutableSamplers make sure it's NULL
147 if ((p_create_info->pBindings[i].pImmutableSamplers) &&
148 ((p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) &&
149 (p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))) {
Tobin Ehlis546326f2016-04-26 11:06:05 -0600150 bindings_.back()->pImmutableSamplers = nullptr;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600151 }
152 if (p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
153 p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
154 dynamic_descriptor_count_++;
155 }
156 }
157}
158DescriptorSetLayout::~DescriptorSetLayout() {
Tobin Ehlis546326f2016-04-26 11:06:05 -0600159 for (auto binding : bindings_)
160 delete binding;
161};
162
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600163VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) {
164 if (!binding_to_index_map_.count(binding))
165 return nullptr;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600166 return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(bindings_[binding_to_index_map_[binding]]);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600167}
168VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) {
169 if (index >= bindings_.size())
170 return nullptr;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600171 return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(bindings_[index]);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600172}
173// Return descriptorCount for given binding, 0 if index is unavailable
174uint32_t DescriptorSetLayout::GetDescriptorCountFromBinding(const uint32_t binding) {
175 if (!binding_to_index_map_.count(binding))
176 return 0;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600177 return bindings_[binding_to_index_map_[binding]]->descriptorCount;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600178}
179// Return descriptorCount for given index, 0 if index is unavailable
180uint32_t DescriptorSetLayout::GetDescriptorCountFromIndex(const uint32_t index) {
181 if (index >= bindings_.size())
182 return 0;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600183 return bindings_[index]->descriptorCount;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600184}
185// For the given binding, return descriptorType
186VkDescriptorType DescriptorSetLayout::GetTypeFromBinding(const uint32_t binding) {
187 assert(binding_to_index_map_.count(binding));
Tobin Ehlis546326f2016-04-26 11:06:05 -0600188 return bindings_[binding_to_index_map_[binding]]->descriptorType;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600189}
190// For the given index, return descriptorType
191VkDescriptorType DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) {
192 assert(index < bindings_.size());
Tobin Ehlis546326f2016-04-26 11:06:05 -0600193 return bindings_[index]->descriptorType;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600194}
Tobin Ehlis660aba42016-04-26 13:09:51 -0600195// For the given global index, return descriptorType
196// Currently just counting up through bindings_, may improve this in future
197VkDescriptorType DescriptorSetLayout::GetTypeFromGlobalIndex(const uint32_t index) {
198 auto global_offset = 0;
199 for (auto binding : bindings_) {
200 global_offset += binding->descriptorCount;
201 if (index < global_offset)
202 return binding->descriptorType;
203 }
204 assert(0); // requested global index is out of bounds
205}
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600206// For the given binding, return stageFlags
207VkShaderStageFlags DescriptorSetLayout::GetStageFlagsFromBinding(const uint32_t binding) {
208 assert(binding_to_index_map_.count(binding));
Tobin Ehlis546326f2016-04-26 11:06:05 -0600209 return bindings_[binding_to_index_map_[binding]]->stageFlags;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600210}
211// For the given binding, return start index
212uint32_t DescriptorSetLayout::GetGlobalStartIndexFromBinding(const uint32_t binding) {
213 assert(binding_to_global_start_index_map_.count(binding));
214 return binding_to_global_start_index_map_[binding];
215}
216// For the given binding, return end index
217uint32_t DescriptorSetLayout::GetGlobalEndIndexFromBinding(const uint32_t binding) {
218 assert(binding_to_global_end_index_map_.count(binding));
219 return binding_to_global_end_index_map_[binding];
220}
221//
222VkSampler const *DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) {
223 assert(binding_to_index_map_.count(binding));
Tobin Ehlis546326f2016-04-26 11:06:05 -0600224 return bindings_[binding_to_index_map_[binding]]->pImmutableSamplers;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600225}
226// If our layout is compatible with rh_sd_layout, return true,
227// else return false and fill in error_msg will description of what causes incompatibility
228bool DescriptorSetLayout::IsCompatible(DescriptorSetLayout *rh_ds_layout, string *error_msg) {
229 // Trivial case
230 if (layout_ == rh_ds_layout->GetDescriptorSetLayout())
231 return true;
232 if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
233 stringstream error_str;
234 error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
235 << rh_ds_layout->GetDescriptorSetLayout() << " has " << rh_ds_layout->descriptor_count_ << " descriptors.";
236 *error_msg = error_str.str();
237 return false; // trivial fail case
238 }
239 // Descriptor counts match so need to go through bindings one-by-one
240 // and verify that type and stageFlags match
241 for (auto binding : bindings_) {
242 // TODO : Do we also need to check immutable samplers?
243 // VkDescriptorSetLayoutBinding *rh_binding;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600244 // rh_ds_layout->FillDescriptorSetLayoutBindingStructFromBinding(binding->binding, rh_binding);
245 if (binding->descriptorCount != rh_ds_layout->GetTotalDescriptorCount()) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600246 stringstream error_str;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600247 error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
248 << binding->descriptorCount << " but binding " << binding->binding << " for DescriptorSetLayout "
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600249 << rh_ds_layout->GetDescriptorSetLayout() << " has a descriptorCount of "
250 << rh_ds_layout->GetTotalDescriptorCount();
251 *error_msg = error_str.str();
252 return false;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600253 } else if (binding->descriptorType != rh_ds_layout->GetTypeFromBinding(binding->binding)) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600254 stringstream error_str;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600255 error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " is type '"
256 << string_VkDescriptorType(binding->descriptorType) << "' but binding " << binding->binding
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600257 << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout() << " is type '"
Tobin Ehlis546326f2016-04-26 11:06:05 -0600258 << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding->binding)) << "'";
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600259 *error_msg = error_str.str();
260 return false;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600261 } else if (binding->stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding->binding)) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600262 stringstream error_str;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600263 error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
264 << binding->stageFlags << " but binding " << binding->binding << " for DescriptorSetLayout "
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600265 << rh_ds_layout->GetDescriptorSetLayout() << " has stageFlags "
Tobin Ehlis546326f2016-04-26 11:06:05 -0600266 << rh_ds_layout->GetStageFlagsFromBinding(binding->binding);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600267 *error_msg = error_str.str();
268 return false;
269 }
270 }
271 return true;
272}
273#endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_