Nathaniel Cesario | 2e8dc80 | 2022-02-15 14:54:04 -0700 | [diff] [blame^] | 1 | #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 |
| 6 | static PipelineLayoutSetLayoutsDict pipeline_layout_set_layouts_dict; |
| 7 | |
| 8 | // Dictionary of canonical form of the "compatible for set" records |
| 9 | static PipelineLayoutCompatDict pipeline_layout_compat_dict; |
| 10 | |
| 11 | static PushConstantRangesDict push_constant_ranges_dict; |
| 12 | |
| 13 | size_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 | |
| 24 | bool 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 | |
| 47 | static 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 |
| 53 | struct 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 | |
| 67 | static 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 | |
| 87 | static 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 | |
| 97 | static 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 | |
| 114 | PIPELINE_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)) {} |