blob: 4fcc613cd861029c61a8d602ccbce2d7eca91308 [file] [log] [blame]
Nathaniel Cesario2e8dc802022-02-15 14:54:04 -07001#include "pipeline_layout_state.h"
2#include "state_tracker.h"
3#include "descriptor_sets.h"
4
5// Dictionary of canonical form of the pipeline set layout of descriptor set layouts
6static PipelineLayoutSetLayoutsDict pipeline_layout_set_layouts_dict;
7
8// Dictionary of canonical form of the "compatible for set" records
9static PipelineLayoutCompatDict pipeline_layout_compat_dict;
10
11static PushConstantRangesDict push_constant_ranges_dict;
12
13size_t PipelineLayoutCompatDef::hash() const {
14 hash_util::HashCombiner hc;
15 // The set number is integral to the CompatDef's distinctiveness
16 hc << set << push_constant_ranges.get();
17 const auto &descriptor_set_layouts = *set_layouts_id.get();
18 for (uint32_t i = 0; i <= set; i++) {
19 hc << descriptor_set_layouts[i].get();
20 }
21 return hc.Value();
22}
23
24bool PipelineLayoutCompatDef::operator==(const PipelineLayoutCompatDef &other) const {
25 if ((set != other.set) || (push_constant_ranges != other.push_constant_ranges)) {
26 return false;
27 }
28
29 if (set_layouts_id == other.set_layouts_id) {
30 // if it's the same set_layouts_id, then *any* subset will match
31 return true;
32 }
33
34 // They aren't exactly the same PipelineLayoutSetLayouts, so we need to check if the required subsets match
35 const auto &descriptor_set_layouts = *set_layouts_id.get();
36 assert(set < descriptor_set_layouts.size());
37 const auto &other_ds_layouts = *other.set_layouts_id.get();
38 assert(set < other_ds_layouts.size());
39 for (uint32_t i = 0; i <= set; i++) {
40 if (descriptor_set_layouts[i] != other_ds_layouts[i]) {
41 return false;
42 }
43 }
44 return true;
45}
46
47static PipelineLayoutCompatId GetCanonicalId(const uint32_t set_index, const PushConstantRangesId pcr_id,
48 const PipelineLayoutSetLayoutsId set_layouts_id) {
49 return pipeline_layout_compat_dict.look_up(PipelineLayoutCompatDef(set_index, pcr_id, set_layouts_id));
50}
51
52// For repeatable sorting, not very useful for "memory in range" search
53struct PushConstantRangeCompare {
54 bool operator()(const VkPushConstantRange *lhs, const VkPushConstantRange *rhs) const {
55 if (lhs->offset == rhs->offset) {
56 if (lhs->size == rhs->size) {
57 // The comparison is arbitrary, but avoids false aliasing by comparing all fields.
58 return lhs->stageFlags < rhs->stageFlags;
59 }
60 // If the offsets are the same then sorting by the end of range is useful for validation
61 return lhs->size < rhs->size;
62 }
63 return lhs->offset < rhs->offset;
64 }
65};
66
67static PushConstantRangesId GetCanonicalId(const VkPipelineLayoutCreateInfo *info) {
68 if (!info->pPushConstantRanges) {
69 // Hand back the empty entry (creating as needed)...
70 return push_constant_ranges_dict.look_up(PushConstantRanges());
71 }
72
73 // Sort the input ranges to ensure equivalent ranges map to the same id
74 std::set<const VkPushConstantRange *, PushConstantRangeCompare> sorted;
75 for (uint32_t i = 0; i < info->pushConstantRangeCount; i++) {
76 sorted.insert(info->pPushConstantRanges + i);
77 }
78
79 PushConstantRanges ranges;
80 ranges.reserve(sorted.size());
81 for (const auto *range : sorted) {
82 ranges.emplace_back(*range);
83 }
84 return push_constant_ranges_dict.look_up(std::move(ranges));
85}
86
87static PIPELINE_LAYOUT_STATE::SetLayoutVector GetSetLayouts(ValidationStateTracker *dev_data,
88 const VkPipelineLayoutCreateInfo *pCreateInfo) {
89 PIPELINE_LAYOUT_STATE::SetLayoutVector set_layouts(pCreateInfo->setLayoutCount);
90
91 for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
92 set_layouts[i] = dev_data->Get<cvdescriptorset::DescriptorSetLayout>(pCreateInfo->pSetLayouts[i]);
93 }
94 return set_layouts;
95}
96
97static std::vector<PipelineLayoutCompatId> GetCompatForSet(const PIPELINE_LAYOUT_STATE::SetLayoutVector &set_layouts,
98 const PushConstantRangesId &push_constant_ranges) {
99 PipelineLayoutSetLayoutsDef set_layout_ids(set_layouts.size());
100 for (size_t i = 0; i < set_layouts.size(); i++) {
101 set_layout_ids[i] = set_layouts[i]->GetLayoutId();
102 }
103 auto set_layouts_id = pipeline_layout_set_layouts_dict.look_up(set_layout_ids);
104
105 std::vector<PipelineLayoutCompatId> compat_for_set;
106 compat_for_set.reserve(set_layouts.size());
107
108 for (uint32_t i = 0; i < set_layouts.size(); i++) {
109 compat_for_set.emplace_back(GetCanonicalId(i, push_constant_ranges, set_layouts_id));
110 }
111 return compat_for_set;
112}
113
114PIPELINE_LAYOUT_STATE::PIPELINE_LAYOUT_STATE(ValidationStateTracker *dev_data, VkPipelineLayout l,
115 const VkPipelineLayoutCreateInfo *pCreateInfo)
116 : BASE_NODE(l, kVulkanObjectTypePipelineLayout),
117 set_layouts(GetSetLayouts(dev_data, pCreateInfo)),
118 push_constant_ranges(GetCanonicalId(pCreateInfo)),
119 compat_for_set(GetCompatForSet(set_layouts, push_constant_ranges)) {}