blob: 279c09af588efa3d7e7ddb195ac81a39986b31bc [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) {
117 for (const auto *layout : layouts) {
118 if (layout) {
119 return layout->push_constant_ranges;
120 }
121 }
122 return {};
123}
124
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700125static PIPELINE_LAYOUT_STATE::SetLayoutVector GetSetLayouts(ValidationStateTracker *dev_data,
126 const VkPipelineLayoutCreateInfo *pCreateInfo) {
127 PIPELINE_LAYOUT_STATE::SetLayoutVector set_layouts(pCreateInfo->setLayoutCount);
128
129 for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
130 set_layouts[i] = dev_data->Get<cvdescriptorset::DescriptorSetLayout>(pCreateInfo->pSetLayouts[i]);
131 }
132 return set_layouts;
133}
134
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700135static PIPELINE_LAYOUT_STATE::SetLayoutVector GetSetLayouts(const layer_data::span<const PIPELINE_LAYOUT_STATE *const> &layouts) {
136 PIPELINE_LAYOUT_STATE::SetLayoutVector set_layouts;
137 size_t num_layouts = 0;
138 for (const auto &layout : layouts) {
139 if (layout && (layout->set_layouts.size() > num_layouts)) {
140 num_layouts = layout->set_layouts.size();
141 }
142 }
143
144 if (!num_layouts) {
145 return {};
146 }
147
148 // TODO is this done correctly?
149 set_layouts.reserve(num_layouts);
150 for (size_t i = 0; i < num_layouts; ++i) {
Nathaniel Cesario0faaeb32022-02-22 10:22:33 -0700151 const PIPELINE_LAYOUT_STATE *used_layout = nullptr;
152 for (const auto *layout : layouts) {
153 if (layout) {
Nathaniel Cesario82433032022-03-14 23:10:35 -0600154 if (layout->set_layouts.size() > i) {
155 // This _could_ be the layout we're looking for
156 used_layout = layout;
157
158 if ((layout->set_layouts[i]) && (layout->set_layouts[i]->GetBindingCount() > 0)) {
159 // This is the layout we're looking for. Any subsequent ones that match must be identical to this one.
160 break;
161 }
Nathaniel Cesario0faaeb32022-02-22 10:22:33 -0700162 }
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700163 }
164 }
Nathaniel Cesario0faaeb32022-02-22 10:22:33 -0700165 set_layouts.emplace_back(used_layout->set_layouts[i]);
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700166 }
167 return set_layouts;
168}
169
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700170static std::vector<PipelineLayoutCompatId> GetCompatForSet(const PIPELINE_LAYOUT_STATE::SetLayoutVector &set_layouts,
171 const PushConstantRangesId &push_constant_ranges) {
172 PipelineLayoutSetLayoutsDef set_layout_ids(set_layouts.size());
173 for (size_t i = 0; i < set_layouts.size(); i++) {
Nathaniel Cesario4153f0c2022-02-25 18:12:08 -0700174 if (set_layouts[i]) {
175 set_layout_ids[i] = set_layouts[i]->GetLayoutId();
176 }
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -0700177 }
178 auto set_layouts_id = pipeline_layout_set_layouts_dict.look_up(set_layout_ids);
179
180 std::vector<PipelineLayoutCompatId> compat_for_set;
181 compat_for_set.reserve(set_layouts.size());
182
183 for (uint32_t i = 0; i < set_layouts.size(); i++) {
184 compat_for_set.emplace_back(GetCanonicalId(i, push_constant_ranges, set_layouts_id));
185 }
186 return compat_for_set;
187}
188
189PIPELINE_LAYOUT_STATE::PIPELINE_LAYOUT_STATE(ValidationStateTracker *dev_data, VkPipelineLayout l,
190 const VkPipelineLayoutCreateInfo *pCreateInfo)
191 : BASE_NODE(l, kVulkanObjectTypePipelineLayout),
192 set_layouts(GetSetLayouts(dev_data, pCreateInfo)),
193 push_constant_ranges(GetCanonicalId(pCreateInfo)),
194 compat_for_set(GetCompatForSet(set_layouts, push_constant_ranges)) {}
Nathaniel Cesario81257cb2022-02-16 17:15:58 -0700195
196PIPELINE_LAYOUT_STATE::PIPELINE_LAYOUT_STATE(const layer_data::span<const PIPELINE_LAYOUT_STATE *const> &layouts)
197 : BASE_NODE(static_cast<VkPipelineLayout>(VK_NULL_HANDLE), kVulkanObjectTypePipelineLayout),
198 set_layouts(GetSetLayouts(layouts)),
199 push_constant_ranges(GetPushConstantRangesFromLayouts(layouts)), // TODO is this correct?
200 compat_for_set(GetCompatForSet(set_layouts, push_constant_ranges)) {}