blob: d4cb9ed2fccca5a2d097ba6f5867d031bceb4f28 [file] [log] [blame]
Nathaniel Cesario9ee6c572022-04-06 10:56:19 -06001/* Copyright (c) 2015-2022 The Khronos Group Inc.
2 * Copyright (c) 2015-2022 Valve Corporation
3 * Copyright (c) 2015-2022 LunarG, Inc.
4 * Copyright (C) 2015-2022 Google Inc.
5 * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * Author: Courtney Goeltzenleuchter <courtneygo@google.com>
20 * Author: Tobin Ehlis <tobine@google.com>
21 * Author: Chris Forbes <chrisf@ijw.co.nz>
22 * Author: Mark Lobodzinski <mark@lunarg.com>
23 * Author: Dave Houlton <daveh@lunarg.com>
24 * Author: John Zulauf <jzulauf@lunarg.com>
25 * Author: Tobias Hector <tobias.hector@amd.com>
26 * Author: Jeremy Gebben <jeremyg@lunarg.com>
27 * Author: Nathaniel Cesario <nathaniel@lunarg.com>
28 */
29
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -070030#include "pipeline_layout_state.h"
31#include "state_tracker.h"
32#include "descriptor_sets.h"
33
34// Dictionary of canonical form of the pipeline set layout of descriptor set layouts
35static PipelineLayoutSetLayoutsDict pipeline_layout_set_layouts_dict;
36
37// Dictionary of canonical form of the "compatible for set" records
38static PipelineLayoutCompatDict pipeline_layout_compat_dict;
39
40static PushConstantRangesDict push_constant_ranges_dict;
41
42size_t PipelineLayoutCompatDef::hash() const {
43 hash_util::HashCombiner hc;
44 // The set number is integral to the CompatDef's distinctiveness
45 hc << set << push_constant_ranges.get();
46 const auto &descriptor_set_layouts = *set_layouts_id.get();
47 for (uint32_t i = 0; i <= set; i++) {
48 hc << descriptor_set_layouts[i].get();
49 }
50 return hc.Value();
51}
52
53bool PipelineLayoutCompatDef::operator==(const PipelineLayoutCompatDef &other) const {
54 if ((set != other.set) || (push_constant_ranges != other.push_constant_ranges)) {
55 return false;
56 }
57
58 if (set_layouts_id == other.set_layouts_id) {
59 // if it's the same set_layouts_id, then *any* subset will match
60 return true;
61 }
62
63 // They aren't exactly the same PipelineLayoutSetLayouts, so we need to check if the required subsets match
64 const auto &descriptor_set_layouts = *set_layouts_id.get();
65 assert(set < descriptor_set_layouts.size());
66 const auto &other_ds_layouts = *other.set_layouts_id.get();
67 assert(set < other_ds_layouts.size());
68 for (uint32_t i = 0; i <= set; i++) {
69 if (descriptor_set_layouts[i] != other_ds_layouts[i]) {
70 return false;
71 }
72 }
73 return true;
74}
75
76static PipelineLayoutCompatId GetCanonicalId(const uint32_t set_index, const PushConstantRangesId pcr_id,
77 const PipelineLayoutSetLayoutsId set_layouts_id) {
78 return pipeline_layout_compat_dict.look_up(PipelineLayoutCompatDef(set_index, pcr_id, set_layouts_id));
79}
80
81// For repeatable sorting, not very useful for "memory in range" search
82struct PushConstantRangeCompare {
83 bool operator()(const VkPushConstantRange *lhs, const VkPushConstantRange *rhs) const {
84 if (lhs->offset == rhs->offset) {
85 if (lhs->size == rhs->size) {
86 // The comparison is arbitrary, but avoids false aliasing by comparing all fields.
87 return lhs->stageFlags < rhs->stageFlags;
88 }
89 // If the offsets are the same then sorting by the end of range is useful for validation
90 return lhs->size < rhs->size;
91 }
92 return lhs->offset < rhs->offset;
93 }
94};
95
96static PushConstantRangesId GetCanonicalId(const VkPipelineLayoutCreateInfo *info) {
97 if (!info->pPushConstantRanges) {
98 // Hand back the empty entry (creating as needed)...
99 return push_constant_ranges_dict.look_up(PushConstantRanges());
100 }
101
102 // Sort the input ranges to ensure equivalent ranges map to the same id
103 std::set<const VkPushConstantRange *, PushConstantRangeCompare> sorted;
104 for (uint32_t i = 0; i < info->pushConstantRangeCount; i++) {
105 sorted.insert(info->pPushConstantRanges + i);
106 }
107
108 PushConstantRanges ranges;
109 ranges.reserve(sorted.size());
110 for (const auto *range : sorted) {
111 ranges.emplace_back(*range);
112 }
113 return push_constant_ranges_dict.look_up(std::move(ranges));
114}
115
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700116static PushConstantRangesId GetPushConstantRangesFromLayouts(const layer_data::span<const PIPELINE_LAYOUT_STATE *const> &layouts) {
Nathaniel Cesario16ba1ec2022-03-16 11:26:47 -0600117 PushConstantRangesId ret{};
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700118 for (const auto *layout : layouts) {
Nathaniel Cesario16ba1ec2022-03-16 11:26:47 -0600119 if (layout && layout->push_constant_ranges) {
120 ret = layout->push_constant_ranges;
121
122 if (ret->size() > 0) {
123 return ret;
124 }
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700125 }
126 }
Nathaniel Cesario16ba1ec2022-03-16 11:26:47 -0600127 return ret;
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700128}
129
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700130static PIPELINE_LAYOUT_STATE::SetLayoutVector GetSetLayouts(ValidationStateTracker *dev_data,
131 const VkPipelineLayoutCreateInfo *pCreateInfo) {
132 PIPELINE_LAYOUT_STATE::SetLayoutVector set_layouts(pCreateInfo->setLayoutCount);
133
134 for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
135 set_layouts[i] = dev_data->Get<cvdescriptorset::DescriptorSetLayout>(pCreateInfo->pSetLayouts[i]);
136 }
137 return set_layouts;
138}
139
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700140static PIPELINE_LAYOUT_STATE::SetLayoutVector GetSetLayouts(const layer_data::span<const PIPELINE_LAYOUT_STATE *const> &layouts) {
141 PIPELINE_LAYOUT_STATE::SetLayoutVector set_layouts;
142 size_t num_layouts = 0;
143 for (const auto &layout : layouts) {
144 if (layout && (layout->set_layouts.size() > num_layouts)) {
145 num_layouts = layout->set_layouts.size();
146 }
147 }
148
149 if (!num_layouts) {
150 return {};
151 }
152
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700153 set_layouts.reserve(num_layouts);
154 for (size_t i = 0; i < num_layouts; ++i) {
Nathaniel Cesario0faaeb32022-02-22 10:22:33 -0700155 const PIPELINE_LAYOUT_STATE *used_layout = nullptr;
156 for (const auto *layout : layouts) {
157 if (layout) {
Nathaniel Cesario82433032022-03-14 23:10:35 -0600158 if (layout->set_layouts.size() > i) {
159 // This _could_ be the layout we're looking for
160 used_layout = layout;
161
Nathaniel Cesario4d03aa12022-06-01 09:22:13 -0600162 if (layout->set_layouts[i]) {
Nathaniel Cesario82433032022-03-14 23:10:35 -0600163 // This is the layout we're looking for. Any subsequent ones that match must be identical to this one.
164 break;
165 }
Nathaniel Cesario0faaeb32022-02-22 10:22:33 -0700166 }
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700167 }
168 }
Nathaniel Cesario0faaeb32022-02-22 10:22:33 -0700169 set_layouts.emplace_back(used_layout->set_layouts[i]);
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700170 }
171 return set_layouts;
172}
173
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700174static std::vector<PipelineLayoutCompatId> GetCompatForSet(const PIPELINE_LAYOUT_STATE::SetLayoutVector &set_layouts,
175 const PushConstantRangesId &push_constant_ranges) {
176 PipelineLayoutSetLayoutsDef set_layout_ids(set_layouts.size());
177 for (size_t i = 0; i < set_layouts.size(); i++) {
Nathaniel Cesario4153f0c2022-02-25 18:12:08 -0700178 if (set_layouts[i]) {
179 set_layout_ids[i] = set_layouts[i]->GetLayoutId();
180 }
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700181 }
182 auto set_layouts_id = pipeline_layout_set_layouts_dict.look_up(set_layout_ids);
183
184 std::vector<PipelineLayoutCompatId> compat_for_set;
185 compat_for_set.reserve(set_layouts.size());
186
187 for (uint32_t i = 0; i < set_layouts.size(); i++) {
188 compat_for_set.emplace_back(GetCanonicalId(i, push_constant_ranges, set_layouts_id));
189 }
190 return compat_for_set;
191}
192
Nathaniel Cesario08ae4bf2022-03-17 11:42:44 -0600193VkPipelineLayoutCreateFlags GetCreateFlags(const layer_data::span<const PIPELINE_LAYOUT_STATE *const> &layouts) {
194 VkPipelineLayoutCreateFlags flags = 0;
195 for (const auto &layout : layouts) {
196 if (layout) {
197 flags |= layout->CreateFlags();
198 }
199 }
200 return flags;
201}
202
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700203PIPELINE_LAYOUT_STATE::PIPELINE_LAYOUT_STATE(ValidationStateTracker *dev_data, VkPipelineLayout l,
204 const VkPipelineLayoutCreateInfo *pCreateInfo)
205 : BASE_NODE(l, kVulkanObjectTypePipelineLayout),
206 set_layouts(GetSetLayouts(dev_data, pCreateInfo)),
207 push_constant_ranges(GetCanonicalId(pCreateInfo)),
Nathaniel Cesario08ae4bf2022-03-17 11:42:44 -0600208 compat_for_set(GetCompatForSet(set_layouts, push_constant_ranges)),
209 create_flags(pCreateInfo->flags) {}
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700210
211PIPELINE_LAYOUT_STATE::PIPELINE_LAYOUT_STATE(const layer_data::span<const PIPELINE_LAYOUT_STATE *const> &layouts)
212 : BASE_NODE(static_cast<VkPipelineLayout>(VK_NULL_HANDLE), kVulkanObjectTypePipelineLayout),
213 set_layouts(GetSetLayouts(layouts)),
214 push_constant_ranges(GetPushConstantRangesFromLayouts(layouts)), // TODO is this correct?
Nathaniel Cesario08ae4bf2022-03-17 11:42:44 -0600215 compat_for_set(GetCompatForSet(set_layouts, push_constant_ranges)),
216 create_flags(GetCreateFlags(layouts)) {}