blob: ad2621c2ea304533b1995b1c19cc4fa34dda1755 [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
120 vector<safe_VkDescriptorSetLayoutBinding> bindings_;
121 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++;
144 bindings_.push_back(safe_VkDescriptorSetLayoutBinding(&p_create_info->pBindings[i]));
145 // 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))) {
149 bindings_.back().pImmutableSamplers = nullptr;
150 }
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() {
158 for (auto binding : bindings_) {
159 if (binding.pImmutableSamplers)
160 delete[] binding.pImmutableSamplers;
161 }
162}
163VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) {
164 if (!binding_to_index_map_.count(binding))
165 return nullptr;
166 return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(&bindings_[binding_to_index_map_[binding]]);
167}
168VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) {
169 if (index >= bindings_.size())
170 return nullptr;
171 return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(&bindings_[index]);
172}
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;
177 return bindings_[binding_to_index_map_[binding]].descriptorCount;
178}
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;
183 return bindings_[index].descriptorCount;
184}
185// For the given binding, return descriptorType
186VkDescriptorType DescriptorSetLayout::GetTypeFromBinding(const uint32_t binding) {
187 assert(binding_to_index_map_.count(binding));
188 return bindings_[binding_to_index_map_[binding]].descriptorType;
189}
190// For the given index, return descriptorType
191VkDescriptorType DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) {
192 assert(index < bindings_.size());
193 return bindings_[index].descriptorType;
194}
195// For the given binding, return stageFlags
196VkShaderStageFlags DescriptorSetLayout::GetStageFlagsFromBinding(const uint32_t binding) {
197 assert(binding_to_index_map_.count(binding));
198 return bindings_[binding_to_index_map_[binding]].stageFlags;
199}
200// For the given binding, return start index
201uint32_t DescriptorSetLayout::GetGlobalStartIndexFromBinding(const uint32_t binding) {
202 assert(binding_to_global_start_index_map_.count(binding));
203 return binding_to_global_start_index_map_[binding];
204}
205// For the given binding, return end index
206uint32_t DescriptorSetLayout::GetGlobalEndIndexFromBinding(const uint32_t binding) {
207 assert(binding_to_global_end_index_map_.count(binding));
208 return binding_to_global_end_index_map_[binding];
209}
210//
211VkSampler const *DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) {
212 assert(binding_to_index_map_.count(binding));
213 return bindings_[binding_to_index_map_[binding]].pImmutableSamplers;
214}
215// If our layout is compatible with rh_sd_layout, return true,
216// else return false and fill in error_msg will description of what causes incompatibility
217bool DescriptorSetLayout::IsCompatible(DescriptorSetLayout *rh_ds_layout, string *error_msg) {
218 // Trivial case
219 if (layout_ == rh_ds_layout->GetDescriptorSetLayout())
220 return true;
221 if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
222 stringstream error_str;
223 error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
224 << rh_ds_layout->GetDescriptorSetLayout() << " has " << rh_ds_layout->descriptor_count_ << " descriptors.";
225 *error_msg = error_str.str();
226 return false; // trivial fail case
227 }
228 // Descriptor counts match so need to go through bindings one-by-one
229 // and verify that type and stageFlags match
230 for (auto binding : bindings_) {
231 // TODO : Do we also need to check immutable samplers?
232 // VkDescriptorSetLayoutBinding *rh_binding;
233 // rh_ds_layout->FillDescriptorSetLayoutBindingStructFromBinding(binding.binding, rh_binding);
234 if (binding.descriptorCount != rh_ds_layout->GetTotalDescriptorCount()) {
235 stringstream error_str;
236 error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
237 << binding.descriptorCount << " but binding " << binding.binding << " for DescriptorSetLayout "
238 << rh_ds_layout->GetDescriptorSetLayout() << " has a descriptorCount of "
239 << rh_ds_layout->GetTotalDescriptorCount();
240 *error_msg = error_str.str();
241 return false;
242 } else if (binding.descriptorType != rh_ds_layout->GetTypeFromBinding(binding.binding)) {
243 stringstream error_str;
244 error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " is type '"
245 << string_VkDescriptorType(binding.descriptorType) << "' but binding " << binding.binding
246 << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout() << " is type '"
247 << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding.binding)) << "'";
248 *error_msg = error_str.str();
249 return false;
250 } else if (binding.stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding.binding)) {
251 stringstream error_str;
252 error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
253 << binding.stageFlags << " but binding " << binding.binding << " for DescriptorSetLayout "
254 << rh_ds_layout->GetDescriptorSetLayout() << " has stageFlags "
255 << rh_ds_layout->GetStageFlagsFromBinding(binding.binding);
256 *error_msg = error_str.str();
257 return false;
258 }
259 }
260 return true;
261}
262#endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_