blob: a0409b9cd9862fef80323f0d8d274ecfa0d7e3d2 [file] [log] [blame]
aitor-lunargb4359602022-02-16 19:54:50 +01001/* Copyright (c) 2019-2022 The Khronos Group Inc.
2 * Copyright (c) 2019-2022 Valve Corporation
3 * Copyright (c) 2019-2022 LunarG, Inc.
4 * Copyright (C) 2019-2022 Google Inc.
John Zulauf11211402019-11-15 14:02:36 -07005 *
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 * John Zulauf <jzulauf@lunarg.com>
19 *
20 */
John Zulauf5823c622019-11-25 13:33:44 -070021#include "image_layout_map.h"
Jeremy Gebben1dfbd172021-05-19 14:00:58 -060022#ifndef SPARSE_CONTAINER_UNIT_TEST
23#include "image_state.h"
Jeremy Gebben159b3cc2021-06-03 09:09:03 -060024#include "cmd_buffer_state.h"
John Zulauf5823c622019-11-25 13:33:44 -070025#endif
John Zulauf11211402019-11-15 14:02:36 -070026
27namespace image_layout_map {
John Zulauf81408f12019-11-27 16:40:27 -070028using InitialLayoutStates = ImageSubresourceLayoutMap::InitialLayoutStates;
Jeremy Gebben53631302021-04-13 16:46:37 -060029using LayoutEntry = ImageSubresourceLayoutMap::LayoutEntry;
John Zulauf81408f12019-11-27 16:40:27 -070030
Jeremy Gebben53631302021-04-13 16:46:37 -060031template <typename LayoutsMap>
32static bool UpdateLayoutStateImpl(LayoutsMap& layouts, InitialLayoutStates& initial_layout_states, const IndexRange& range,
33 LayoutEntry& new_entry, const CMD_BUFFER_STATE& cb_state, const IMAGE_VIEW_STATE* view_state) {
34 using CachedLowerBound = typename sparse_container::cached_lower_bound_impl<LayoutsMap>;
35 CachedLowerBound pos(layouts, range.begin);
36 if (!range.includes(pos->index)) {
37 return false;
John Zulauf81408f12019-11-27 16:40:27 -070038 }
Jeremy Gebben53631302021-04-13 16:46:37 -060039 bool updated_current = false;
40 while (range.includes(pos->index)) {
41 if (!pos->valid) {
42 // Fill in the leading space (or in the case of pos at end the trailing space
43 const auto start = pos->index;
44 auto it = pos->lower_bound;
45 const auto limit = (it != layouts.end()) ? std::min(it->first.begin, range.end) : range.end;
46 if (new_entry.state == nullptr) {
47 // Allocate on demand... initial_layout_states_ holds ownership, while
48 // each subresource has a non-owning copy of the plain pointer.
49 initial_layout_states.emplace_back(cb_state, view_state);
50 new_entry.state = &initial_layout_states.back();
51 }
Jeremy Gebben53585a62021-06-30 14:50:43 -060052 auto insert_result = layouts.insert(it, std::make_pair(IndexRange(start, limit), new_entry));
53 pos.invalidate(insert_result, start);
Jeremy Gebben53631302021-04-13 16:46:37 -060054 pos.seek(limit);
55 updated_current = true;
56 }
57 // Note that after the "fill" operation pos may have become valid so we check again
58 if (pos->valid) {
Jeremy Gebben53585a62021-06-30 14:50:43 -060059 auto intersected_range = pos->lower_bound->first & range;
60 if (!intersected_range.empty() && pos->lower_bound->second.CurrentWillChange(new_entry.current_layout)) {
Jeremy Gebbenf33bcd12022-04-19 08:12:44 -060061 LayoutEntry orig_entry = pos->lower_bound->second; // intentional copy
Jeremy Gebben884579e2021-04-29 14:12:37 -060062 assert(orig_entry.state != nullptr);
63 updated_current |= orig_entry.Update(new_entry);
Jeremy Gebben53585a62021-06-30 14:50:43 -060064 auto overwrite_result = layouts.overwrite_range(pos->lower_bound, std::make_pair(intersected_range, orig_entry));
65 // If we didn't cover the whole range, we'll need to go around again
66 pos.invalidate(overwrite_result, intersected_range.begin);
67 pos.seek(intersected_range.end);
Jeremy Gebben884579e2021-04-29 14:12:37 -060068 } else {
69 // Point just past the end of this section, if it's within the given range, it will get filled next iteration
70 // ++pos could move us past the end of range (which would exit the loop) so we don't use it.
71 pos.seek(pos->lower_bound->first.end);
72 }
Jeremy Gebben53631302021-04-13 16:46:37 -060073 }
74 }
75
76 return updated_current;
John Zulauf81408f12019-11-27 16:40:27 -070077}
78
John Zulauf11211402019-11-15 14:02:36 -070079InitialLayoutState::InitialLayoutState(const CMD_BUFFER_STATE& cb_state_, const IMAGE_VIEW_STATE* view_state_)
80 : image_view(VK_NULL_HANDLE), aspect_mask(0), label(cb_state_.debug_label) {
81 if (view_state_) {
Jeremy Gebben14b0d1a2021-05-15 20:15:41 -060082 image_view = view_state_->image_view();
Jeremy Gebbenb4d17012021-07-08 13:18:15 -060083 aspect_mask = view_state_->normalized_subresource_range.aspectMask;
John Zulauf11211402019-11-15 14:02:36 -070084 }
85}
86bool ImageSubresourceLayoutMap::SubresourceLayout::operator==(const ImageSubresourceLayoutMap::SubresourceLayout& rhs) const {
87 bool is_equal =
88 (current_layout == rhs.current_layout) && (initial_layout == rhs.initial_layout) && (subresource == rhs.subresource);
89 return is_equal;
90}
91ImageSubresourceLayoutMap::ImageSubresourceLayoutMap(const IMAGE_STATE& image_state)
John Zulaufb58415b2019-12-09 15:02:32 -070092 : image_state_(image_state),
locke-lunarg296a3c92020-03-25 01:04:29 -060093 encoder_(image_state.subresource_encoder),
John Zulauf81408f12019-11-27 16:40:27 -070094 layouts_(encoder_.SubresourceCount()),
Jeremy Gebben53631302021-04-13 16:46:37 -060095 initial_layout_states_() {}
John Zulauf11211402019-11-15 14:02:36 -070096
John Zulauf81408f12019-11-27 16:40:27 -070097// Use the unwrapped maps from the BothMap in the actual implementation
Jeremy Gebben53631302021-04-13 16:46:37 -060098template <typename LayoutMap>
99static bool SetSubresourceRangeLayoutImpl(LayoutMap& layouts, InitialLayoutStates& initial_layout_states, RangeGenerator& range_gen,
100 const CMD_BUFFER_STATE& cb_state, VkImageLayout layout, VkImageLayout expected_layout) {
John Zulauf81408f12019-11-27 16:40:27 -0700101 bool updated = false;
Jeremy Gebben53631302021-04-13 16:46:37 -0600102 LayoutEntry entry(expected_layout, layout);
John Zulauf81408f12019-11-27 16:40:27 -0700103 for (; range_gen->non_empty(); ++range_gen) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600104 updated |= UpdateLayoutStateImpl(layouts, initial_layout_states, *range_gen, entry, cb_state, nullptr);
John Zulauf81408f12019-11-27 16:40:27 -0700105 }
106 return updated;
107}
108
John Zulauf11211402019-11-15 14:02:36 -0700109bool ImageSubresourceLayoutMap::SetSubresourceRangeLayout(const CMD_BUFFER_STATE& cb_state, const VkImageSubresourceRange& range,
110 VkImageLayout layout, VkImageLayout expected_layout) {
John Zulauf11211402019-11-15 14:02:36 -0700111 if (expected_layout == kInvalidLayout) {
112 // Set the initial layout to the set layout as we had no other layout to reference
113 expected_layout = layout;
114 }
115 if (!InRange(range)) return false; // Don't even try to track bogus subreources
116
John Zulauf11211402019-11-15 14:02:36 -0700117 RangeGenerator range_gen(encoder_, range);
Jeremy Gebben53631302021-04-13 16:46:37 -0600118 if (layouts_.SmallMode()) {
119 return SetSubresourceRangeLayoutImpl(layouts_.GetSmallMap(), initial_layout_states_, range_gen, cb_state, layout,
120 expected_layout);
John Zulauf81408f12019-11-27 16:40:27 -0700121 } else {
Jeremy Gebben53631302021-04-13 16:46:37 -0600122 assert(!layouts_.Tristate());
123 return SetSubresourceRangeLayoutImpl(layouts_.GetBigMap(), initial_layout_states_, range_gen, cb_state, layout,
124 expected_layout);
John Zulauf81408f12019-11-27 16:40:27 -0700125 }
126}
127
128// Use the unwrapped maps from the BothMap in the actual implementation
Jeremy Gebben53631302021-04-13 16:46:37 -0600129template <typename LayoutMap>
130static void SetSubresourceRangeInitialLayoutImpl(LayoutMap& layouts, InitialLayoutStates& initial_layout_states,
131 RangeGenerator& range_gen, const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
John Zulauf81408f12019-11-27 16:40:27 -0700132 const IMAGE_VIEW_STATE* view_state) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600133 LayoutEntry entry(layout);
John Zulauf11211402019-11-15 14:02:36 -0700134 for (; range_gen->non_empty(); ++range_gen) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600135 UpdateLayoutStateImpl(layouts, initial_layout_states, *range_gen, entry, cb_state, view_state);
John Zulauf11211402019-11-15 14:02:36 -0700136 }
John Zulauf11211402019-11-15 14:02:36 -0700137}
John Zulauf81408f12019-11-27 16:40:27 -0700138
139// Unwrap the BothMaps entry here as this is a performance hotspot.
Jeremy Gebben53631302021-04-13 16:46:37 -0600140void ImageSubresourceLayoutMap::SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state,
141 const VkImageSubresourceRange& range, VkImageLayout layout) {
142 if (!InRange(range)) return; // Don't even try to track bogus subreources
John Zulauf11211402019-11-15 14:02:36 -0700143
John Zulauf11211402019-11-15 14:02:36 -0700144 RangeGenerator range_gen(encoder_, range);
Jeremy Gebben53631302021-04-13 16:46:37 -0600145 if (layouts_.SmallMode()) {
146 SetSubresourceRangeInitialLayoutImpl(layouts_.GetSmallMap(), initial_layout_states_, range_gen, cb_state, layout, nullptr);
John Zulauf81408f12019-11-27 16:40:27 -0700147 } else {
Jeremy Gebben53631302021-04-13 16:46:37 -0600148 assert(!layouts_.Tristate());
149 SetSubresourceRangeInitialLayoutImpl(layouts_.GetBigMap(), initial_layout_states_, range_gen, cb_state, layout, nullptr);
John Zulauf11211402019-11-15 14:02:36 -0700150 }
John Zulauf11211402019-11-15 14:02:36 -0700151}
152
John Zulaufb58415b2019-12-09 15:02:32 -0700153// Unwrap the BothMaps entry here as this is a performance hotspot.
Jeremy Gebben53631302021-04-13 16:46:37 -0600154void ImageSubresourceLayoutMap::SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
John Zulaufb58415b2019-12-09 15:02:32 -0700155 const IMAGE_VIEW_STATE& view_state) {
156 RangeGenerator range_gen(view_state.range_generator);
Jeremy Gebben53631302021-04-13 16:46:37 -0600157 if (layouts_.SmallMode()) {
158 SetSubresourceRangeInitialLayoutImpl(layouts_.GetSmallMap(), initial_layout_states_, range_gen, cb_state, layout,
159 &view_state);
John Zulaufb58415b2019-12-09 15:02:32 -0700160 } else {
Jeremy Gebben53631302021-04-13 16:46:37 -0600161 assert(!layouts_.Tristate());
162 SetSubresourceRangeInitialLayoutImpl(layouts_.GetBigMap(), initial_layout_states_, range_gen, cb_state, layout,
163 &view_state);
John Zulaufb58415b2019-12-09 15:02:32 -0700164 }
165}
166
John Zulauf11211402019-11-15 14:02:36 -0700167// Saves an encode to fetch both in the same call
Jeremy Gebben53631302021-04-13 16:46:37 -0600168const ImageSubresourceLayoutMap::LayoutEntry* ImageSubresourceLayoutMap::GetSubresourceLayouts(
169 const VkImageSubresource& subresource) const {
John Zulauf11211402019-11-15 14:02:36 -0700170 IndexType index = encoder_.Encode(subresource);
Jeremy Gebben53631302021-04-13 16:46:37 -0600171 auto found = layouts_.find(index);
172 if (found != layouts_.end()) {
173 return &found->second;
John Zulauf11211402019-11-15 14:02:36 -0700174 }
Jeremy Gebben53631302021-04-13 16:46:37 -0600175 return nullptr;
John Zulauf11211402019-11-15 14:02:36 -0700176}
177
John Zulauf11211402019-11-15 14:02:36 -0700178// TODO: make sure this paranoia check is sufficient and not too much.
179uintptr_t ImageSubresourceLayoutMap::CompatibilityKey() const {
Mike Schuchardte5c15cf2020-04-06 22:57:13 -0700180 return (reinterpret_cast<uintptr_t>(&image_state_) ^ encoder_.AspectMask());
John Zulauf11211402019-11-15 14:02:36 -0700181}
182
183bool ImageSubresourceLayoutMap::UpdateFrom(const ImageSubresourceLayoutMap& other) {
John Zulauf11211402019-11-15 14:02:36 -0700184 // Must be from matching images for the reinterpret cast to be valid
185 assert(CompatibilityKey() == other.CompatibilityKey());
186 if (CompatibilityKey() != other.CompatibilityKey()) return false;
187
Jeremy Gebben53631302021-04-13 16:46:37 -0600188 // NOTE -- we are copying plain state pointers from 'other' which owns them in a vector. This works because
John Zulauf11211402019-11-15 14:02:36 -0700189 // currently this function is only used to import from secondary command buffers, destruction of which
190 // invalidate the referencing primary command buffer, meaning that the dangling pointer will either be
191 // cleaned up in invalidation, on not referenced by validation code.
Jeremy Gebben53631302021-04-13 16:46:37 -0600192 return sparse_container::splice(layouts_, other.layouts_, LayoutEntry::Updater());
John Zulauf11211402019-11-15 14:02:36 -0700193}
John Zulauf11211402019-11-15 14:02:36 -0700194
John Zulauf11211402019-11-15 14:02:36 -0700195} // namespace image_layout_map