blob: 8911910a792807a4ae7bda09d7e6f36a14ba4ab6 [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);
107 VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t);
108 VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t);
109 // For a particular binding, get the global index
110 uint32_t GetGlobalStartIndexFromBinding(const uint32_t);
111 uint32_t GetGlobalEndIndexFromBinding(const uint32_t);
112
113 private:
114 VkDescriptorSetLayout layout_;
115 unordered_map<uint32_t, uint32_t> binding_to_index_map_;
116 unordered_map<uint32_t, uint32_t> binding_to_global_start_index_map_;
117 unordered_map<uint32_t, uint32_t> binding_to_global_end_index_map_;
118 VkDescriptorSetLayoutCreateFlags flags_;
119 uint32_t binding_count_; // # of bindings in this layout
Tobin Ehlis546326f2016-04-26 11:06:05 -0600120 vector<safe_VkDescriptorSetLayoutBinding *> bindings_;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600121 uint32_t descriptor_count_; // total # descriptors in this layout
122 uint32_t dynamic_descriptor_count_;
123};
124DescriptorSetLayout::DescriptorSetLayout()
125 : layout_(VK_NULL_HANDLE), flags_(0), binding_count_(0), descriptor_count_(0), dynamic_descriptor_count_(0) {}
126// Construct DescriptorSetLayout instance from given create info
127DescriptorSetLayout::DescriptorSetLayout(debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *p_create_info,
128 const VkDescriptorSetLayout layout)
129 : layout_(layout), flags_(p_create_info->flags), binding_count_(p_create_info->bindingCount), descriptor_count_(0),
130 dynamic_descriptor_count_(0) {
131 uint32_t global_index = 0;
132 for (uint32_t i = 0; i < binding_count_; ++i) {
133 descriptor_count_ += p_create_info->pBindings[i].descriptorCount;
134 if (!binding_to_index_map_.emplace(p_create_info->pBindings[i].binding, i).second) {
135 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
136 reinterpret_cast<uint64_t &>(layout_), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
137 "duplicated binding number in "
138 "VkDescriptorSetLayoutBinding");
139 }
140 binding_to_global_start_index_map_[p_create_info->pBindings[i].binding] = global_index;
141 global_index += p_create_info->pBindings[i].descriptorCount ? p_create_info->pBindings[i].descriptorCount - 1 : 0;
142 binding_to_global_end_index_map_[p_create_info->pBindings[i].binding] = global_index;
143 global_index++;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600144 bindings_.push_back(new safe_VkDescriptorSetLayoutBinding(&p_create_info->pBindings[i]));
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600145 // In cases where we should ignore pImmutableSamplers make sure it's NULL
146 if ((p_create_info->pBindings[i].pImmutableSamplers) &&
147 ((p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) &&
148 (p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))) {
Tobin Ehlis546326f2016-04-26 11:06:05 -0600149 bindings_.back()->pImmutableSamplers = nullptr;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600150 }
151 if (p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
152 p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
153 dynamic_descriptor_count_++;
154 }
155 }
156}
157DescriptorSetLayout::~DescriptorSetLayout() {
Tobin Ehlis546326f2016-04-26 11:06:05 -0600158 for (auto binding : bindings_)
159 delete binding;
160};
161
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600162VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) {
163 if (!binding_to_index_map_.count(binding))
164 return nullptr;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600165 return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(bindings_[binding_to_index_map_[binding]]);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600166}
167VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) {
168 if (index >= bindings_.size())
169 return nullptr;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600170 return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(bindings_[index]);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600171}
172// Return descriptorCount for given binding, 0 if index is unavailable
173uint32_t DescriptorSetLayout::GetDescriptorCountFromBinding(const uint32_t binding) {
174 if (!binding_to_index_map_.count(binding))
175 return 0;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600176 return bindings_[binding_to_index_map_[binding]]->descriptorCount;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600177}
178// Return descriptorCount for given index, 0 if index is unavailable
179uint32_t DescriptorSetLayout::GetDescriptorCountFromIndex(const uint32_t index) {
180 if (index >= bindings_.size())
181 return 0;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600182 return bindings_[index]->descriptorCount;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600183}
184// For the given binding, return descriptorType
185VkDescriptorType DescriptorSetLayout::GetTypeFromBinding(const uint32_t binding) {
186 assert(binding_to_index_map_.count(binding));
Tobin Ehlis546326f2016-04-26 11:06:05 -0600187 return bindings_[binding_to_index_map_[binding]]->descriptorType;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600188}
189// For the given index, return descriptorType
190VkDescriptorType DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) {
191 assert(index < bindings_.size());
Tobin Ehlis546326f2016-04-26 11:06:05 -0600192 return bindings_[index]->descriptorType;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600193}
194// For the given binding, return stageFlags
195VkShaderStageFlags DescriptorSetLayout::GetStageFlagsFromBinding(const uint32_t binding) {
196 assert(binding_to_index_map_.count(binding));
Tobin Ehlis546326f2016-04-26 11:06:05 -0600197 return bindings_[binding_to_index_map_[binding]]->stageFlags;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600198}
199// For the given binding, return start index
200uint32_t DescriptorSetLayout::GetGlobalStartIndexFromBinding(const uint32_t binding) {
201 assert(binding_to_global_start_index_map_.count(binding));
202 return binding_to_global_start_index_map_[binding];
203}
204// For the given binding, return end index
205uint32_t DescriptorSetLayout::GetGlobalEndIndexFromBinding(const uint32_t binding) {
206 assert(binding_to_global_end_index_map_.count(binding));
207 return binding_to_global_end_index_map_[binding];
208}
209//
210VkSampler const *DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) {
211 assert(binding_to_index_map_.count(binding));
Tobin Ehlis546326f2016-04-26 11:06:05 -0600212 return bindings_[binding_to_index_map_[binding]]->pImmutableSamplers;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600213}
214// If our layout is compatible with rh_sd_layout, return true,
215// else return false and fill in error_msg will description of what causes incompatibility
216bool DescriptorSetLayout::IsCompatible(DescriptorSetLayout *rh_ds_layout, string *error_msg) {
217 // Trivial case
218 if (layout_ == rh_ds_layout->GetDescriptorSetLayout())
219 return true;
220 if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
221 stringstream error_str;
222 error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
223 << rh_ds_layout->GetDescriptorSetLayout() << " has " << rh_ds_layout->descriptor_count_ << " descriptors.";
224 *error_msg = error_str.str();
225 return false; // trivial fail case
226 }
227 // Descriptor counts match so need to go through bindings one-by-one
228 // and verify that type and stageFlags match
229 for (auto binding : bindings_) {
230 // TODO : Do we also need to check immutable samplers?
231 // VkDescriptorSetLayoutBinding *rh_binding;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600232 // rh_ds_layout->FillDescriptorSetLayoutBindingStructFromBinding(binding->binding, rh_binding);
233 if (binding->descriptorCount != rh_ds_layout->GetTotalDescriptorCount()) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600234 stringstream error_str;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600235 error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
236 << binding->descriptorCount << " but binding " << binding->binding << " for DescriptorSetLayout "
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600237 << rh_ds_layout->GetDescriptorSetLayout() << " has a descriptorCount of "
238 << rh_ds_layout->GetTotalDescriptorCount();
239 *error_msg = error_str.str();
240 return false;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600241 } else if (binding->descriptorType != rh_ds_layout->GetTypeFromBinding(binding->binding)) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600242 stringstream error_str;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600243 error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " is type '"
244 << string_VkDescriptorType(binding->descriptorType) << "' but binding " << binding->binding
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600245 << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout() << " is type '"
Tobin Ehlis546326f2016-04-26 11:06:05 -0600246 << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding->binding)) << "'";
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600247 *error_msg = error_str.str();
248 return false;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600249 } else if (binding->stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding->binding)) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600250 stringstream error_str;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600251 error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
252 << binding->stageFlags << " but binding " << binding->binding << " for DescriptorSetLayout "
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600253 << rh_ds_layout->GetDescriptorSetLayout() << " has stageFlags "
Tobin Ehlis546326f2016-04-26 11:06:05 -0600254 << rh_ds_layout->GetStageFlagsFromBinding(binding->binding);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -0600255 *error_msg = error_str.str();
256 return false;
257 }
258 }
259 return true;
260}
261#endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_