blob: 600f278de96c180298dc503f0c0567b82d619d52 [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 {
28// Storage for the static state
29const ImageSubresourceLayoutMap::ConstIterator ImageSubresourceLayoutMap::end_iterator = ImageSubresourceLayoutMap::ConstIterator();
30
John Zulauf81408f12019-11-27 16:40:27 -070031using InitialLayoutStates = ImageSubresourceLayoutMap::InitialLayoutStates;
Jeremy Gebben53631302021-04-13 16:46:37 -060032using LayoutEntry = ImageSubresourceLayoutMap::LayoutEntry;
John Zulauf81408f12019-11-27 16:40:27 -070033
Jeremy Gebben53631302021-04-13 16:46:37 -060034template <typename LayoutsMap>
35static bool UpdateLayoutStateImpl(LayoutsMap& layouts, InitialLayoutStates& initial_layout_states, const IndexRange& range,
36 LayoutEntry& new_entry, const CMD_BUFFER_STATE& cb_state, const IMAGE_VIEW_STATE* view_state) {
37 using CachedLowerBound = typename sparse_container::cached_lower_bound_impl<LayoutsMap>;
38 CachedLowerBound pos(layouts, range.begin);
39 if (!range.includes(pos->index)) {
40 return false;
John Zulauf81408f12019-11-27 16:40:27 -070041 }
Jeremy Gebben53631302021-04-13 16:46:37 -060042 bool updated_current = false;
43 while (range.includes(pos->index)) {
44 if (!pos->valid) {
45 // Fill in the leading space (or in the case of pos at end the trailing space
46 const auto start = pos->index;
47 auto it = pos->lower_bound;
48 const auto limit = (it != layouts.end()) ? std::min(it->first.begin, range.end) : range.end;
49 if (new_entry.state == nullptr) {
50 // Allocate on demand... initial_layout_states_ holds ownership, while
51 // each subresource has a non-owning copy of the plain pointer.
52 initial_layout_states.emplace_back(cb_state, view_state);
53 new_entry.state = &initial_layout_states.back();
54 }
Jeremy Gebben53585a62021-06-30 14:50:43 -060055 auto insert_result = layouts.insert(it, std::make_pair(IndexRange(start, limit), new_entry));
56 pos.invalidate(insert_result, start);
Jeremy Gebben53631302021-04-13 16:46:37 -060057 pos.seek(limit);
58 updated_current = true;
59 }
60 // Note that after the "fill" operation pos may have become valid so we check again
61 if (pos->valid) {
Jeremy Gebben53585a62021-06-30 14:50:43 -060062 auto intersected_range = pos->lower_bound->first & range;
63 if (!intersected_range.empty() && pos->lower_bound->second.CurrentWillChange(new_entry.current_layout)) {
Jeremy Gebben884579e2021-04-29 14:12:37 -060064 LayoutEntry orig_entry = pos->lower_bound->second; //intentional copy
65 assert(orig_entry.state != nullptr);
66 updated_current |= orig_entry.Update(new_entry);
Jeremy Gebben53585a62021-06-30 14:50:43 -060067 auto overwrite_result = layouts.overwrite_range(pos->lower_bound, std::make_pair(intersected_range, orig_entry));
68 // If we didn't cover the whole range, we'll need to go around again
69 pos.invalidate(overwrite_result, intersected_range.begin);
70 pos.seek(intersected_range.end);
Jeremy Gebben884579e2021-04-29 14:12:37 -060071 } else {
72 // Point just past the end of this section, if it's within the given range, it will get filled next iteration
73 // ++pos could move us past the end of range (which would exit the loop) so we don't use it.
74 pos.seek(pos->lower_bound->first.end);
75 }
Jeremy Gebben53631302021-04-13 16:46:37 -060076 }
77 }
78
79 return updated_current;
John Zulauf81408f12019-11-27 16:40:27 -070080}
81
John Zulauf11211402019-11-15 14:02:36 -070082InitialLayoutState::InitialLayoutState(const CMD_BUFFER_STATE& cb_state_, const IMAGE_VIEW_STATE* view_state_)
83 : image_view(VK_NULL_HANDLE), aspect_mask(0), label(cb_state_.debug_label) {
84 if (view_state_) {
Jeremy Gebben14b0d1a2021-05-15 20:15:41 -060085 image_view = view_state_->image_view();
Jeremy Gebbenb4d17012021-07-08 13:18:15 -060086 aspect_mask = view_state_->normalized_subresource_range.aspectMask;
John Zulauf11211402019-11-15 14:02:36 -070087 }
88}
89bool ImageSubresourceLayoutMap::SubresourceLayout::operator==(const ImageSubresourceLayoutMap::SubresourceLayout& rhs) const {
90 bool is_equal =
91 (current_layout == rhs.current_layout) && (initial_layout == rhs.initial_layout) && (subresource == rhs.subresource);
92 return is_equal;
93}
94ImageSubresourceLayoutMap::ImageSubresourceLayoutMap(const IMAGE_STATE& image_state)
John Zulaufb58415b2019-12-09 15:02:32 -070095 : image_state_(image_state),
locke-lunarg296a3c92020-03-25 01:04:29 -060096 encoder_(image_state.subresource_encoder),
John Zulauf81408f12019-11-27 16:40:27 -070097 layouts_(encoder_.SubresourceCount()),
Jeremy Gebben53631302021-04-13 16:46:37 -060098 initial_layout_states_() {}
John Zulauf11211402019-11-15 14:02:36 -070099
100ImageSubresourceLayoutMap::ConstIterator ImageSubresourceLayoutMap::Begin(bool always_get_initial) const {
Jeremy Gebben11a68a32021-07-29 11:59:22 -0600101 return ConstIterator(layouts_, encoder_, encoder_.FullRange(), true, always_get_initial);
John Zulauf11211402019-11-15 14:02:36 -0700102}
John Zulauf81408f12019-11-27 16:40:27 -0700103
104// Use the unwrapped maps from the BothMap in the actual implementation
Jeremy Gebben53631302021-04-13 16:46:37 -0600105template <typename LayoutMap>
106static bool SetSubresourceRangeLayoutImpl(LayoutMap& layouts, InitialLayoutStates& initial_layout_states, RangeGenerator& range_gen,
107 const CMD_BUFFER_STATE& cb_state, VkImageLayout layout, VkImageLayout expected_layout) {
John Zulauf81408f12019-11-27 16:40:27 -0700108 bool updated = false;
Jeremy Gebben53631302021-04-13 16:46:37 -0600109 LayoutEntry entry(expected_layout, layout);
John Zulauf81408f12019-11-27 16:40:27 -0700110 for (; range_gen->non_empty(); ++range_gen) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600111 updated |= UpdateLayoutStateImpl(layouts, initial_layout_states, *range_gen, entry, cb_state, nullptr);
John Zulauf81408f12019-11-27 16:40:27 -0700112 }
113 return updated;
114}
115
John Zulauf11211402019-11-15 14:02:36 -0700116bool ImageSubresourceLayoutMap::SetSubresourceRangeLayout(const CMD_BUFFER_STATE& cb_state, const VkImageSubresourceRange& range,
117 VkImageLayout layout, VkImageLayout expected_layout) {
John Zulauf11211402019-11-15 14:02:36 -0700118 if (expected_layout == kInvalidLayout) {
119 // Set the initial layout to the set layout as we had no other layout to reference
120 expected_layout = layout;
121 }
122 if (!InRange(range)) return false; // Don't even try to track bogus subreources
123
John Zulauf11211402019-11-15 14:02:36 -0700124 RangeGenerator range_gen(encoder_, range);
Jeremy Gebben53631302021-04-13 16:46:37 -0600125 if (layouts_.SmallMode()) {
126 return SetSubresourceRangeLayoutImpl(layouts_.GetSmallMap(), initial_layout_states_, range_gen, cb_state, layout,
127 expected_layout);
John Zulauf81408f12019-11-27 16:40:27 -0700128 } else {
Jeremy Gebben53631302021-04-13 16:46:37 -0600129 assert(!layouts_.Tristate());
130 return SetSubresourceRangeLayoutImpl(layouts_.GetBigMap(), initial_layout_states_, range_gen, cb_state, layout,
131 expected_layout);
John Zulauf81408f12019-11-27 16:40:27 -0700132 }
133}
134
135// Use the unwrapped maps from the BothMap in the actual implementation
Jeremy Gebben53631302021-04-13 16:46:37 -0600136template <typename LayoutMap>
137static void SetSubresourceRangeInitialLayoutImpl(LayoutMap& layouts, InitialLayoutStates& initial_layout_states,
138 RangeGenerator& range_gen, const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
John Zulauf81408f12019-11-27 16:40:27 -0700139 const IMAGE_VIEW_STATE* view_state) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600140 LayoutEntry entry(layout);
John Zulauf11211402019-11-15 14:02:36 -0700141 for (; range_gen->non_empty(); ++range_gen) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600142 UpdateLayoutStateImpl(layouts, initial_layout_states, *range_gen, entry, cb_state, view_state);
John Zulauf11211402019-11-15 14:02:36 -0700143 }
John Zulauf11211402019-11-15 14:02:36 -0700144}
John Zulauf81408f12019-11-27 16:40:27 -0700145
146// Unwrap the BothMaps entry here as this is a performance hotspot.
Jeremy Gebben53631302021-04-13 16:46:37 -0600147void ImageSubresourceLayoutMap::SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state,
148 const VkImageSubresourceRange& range, VkImageLayout layout) {
149 if (!InRange(range)) return; // Don't even try to track bogus subreources
John Zulauf11211402019-11-15 14:02:36 -0700150
John Zulauf11211402019-11-15 14:02:36 -0700151 RangeGenerator range_gen(encoder_, range);
Jeremy Gebben53631302021-04-13 16:46:37 -0600152 if (layouts_.SmallMode()) {
153 SetSubresourceRangeInitialLayoutImpl(layouts_.GetSmallMap(), initial_layout_states_, range_gen, cb_state, layout, nullptr);
John Zulauf81408f12019-11-27 16:40:27 -0700154 } else {
Jeremy Gebben53631302021-04-13 16:46:37 -0600155 assert(!layouts_.Tristate());
156 SetSubresourceRangeInitialLayoutImpl(layouts_.GetBigMap(), initial_layout_states_, range_gen, cb_state, layout, nullptr);
John Zulauf11211402019-11-15 14:02:36 -0700157 }
John Zulauf11211402019-11-15 14:02:36 -0700158}
159
John Zulaufb58415b2019-12-09 15:02:32 -0700160// Unwrap the BothMaps entry here as this is a performance hotspot.
Jeremy Gebben53631302021-04-13 16:46:37 -0600161void ImageSubresourceLayoutMap::SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
John Zulaufb58415b2019-12-09 15:02:32 -0700162 const IMAGE_VIEW_STATE& view_state) {
163 RangeGenerator range_gen(view_state.range_generator);
Jeremy Gebben53631302021-04-13 16:46:37 -0600164 if (layouts_.SmallMode()) {
165 SetSubresourceRangeInitialLayoutImpl(layouts_.GetSmallMap(), initial_layout_states_, range_gen, cb_state, layout,
166 &view_state);
John Zulaufb58415b2019-12-09 15:02:32 -0700167 } else {
Jeremy Gebben53631302021-04-13 16:46:37 -0600168 assert(!layouts_.Tristate());
169 SetSubresourceRangeInitialLayoutImpl(layouts_.GetBigMap(), initial_layout_states_, range_gen, cb_state, layout,
170 &view_state);
John Zulaufb58415b2019-12-09 15:02:32 -0700171 }
172}
173
John Zulauf11211402019-11-15 14:02:36 -0700174// Saves an encode to fetch both in the same call
Jeremy Gebben53631302021-04-13 16:46:37 -0600175const ImageSubresourceLayoutMap::LayoutEntry* ImageSubresourceLayoutMap::GetSubresourceLayouts(
176 const VkImageSubresource& subresource) const {
John Zulauf11211402019-11-15 14:02:36 -0700177 IndexType index = encoder_.Encode(subresource);
Jeremy Gebben53631302021-04-13 16:46:37 -0600178 auto found = layouts_.find(index);
179 if (found != layouts_.end()) {
180 return &found->second;
John Zulauf11211402019-11-15 14:02:36 -0700181 }
Jeremy Gebben53631302021-04-13 16:46:37 -0600182 return nullptr;
John Zulauf11211402019-11-15 14:02:36 -0700183}
184
John Zulauf2076e812020-01-08 14:55:54 -0700185const InitialLayoutState* ImageSubresourceLayoutMap::GetSubresourceInitialLayoutState(const IndexType index) const {
Jeremy Gebben53631302021-04-13 16:46:37 -0600186 const auto found = layouts_.find(index);
187 if (found != layouts_.end()) {
188 return found->second.state;
John Zulauf11211402019-11-15 14:02:36 -0700189 }
190 return nullptr;
191}
192
John Zulauf2076e812020-01-08 14:55:54 -0700193const InitialLayoutState* ImageSubresourceLayoutMap::GetSubresourceInitialLayoutState(const VkImageSubresource& subresource) const {
194 if (!InRange(subresource)) return nullptr;
195 const auto index = encoder_.Encode(subresource);
196 return GetSubresourceInitialLayoutState(index);
197}
198
John Zulauf11211402019-11-15 14:02:36 -0700199// TODO: make sure this paranoia check is sufficient and not too much.
200uintptr_t ImageSubresourceLayoutMap::CompatibilityKey() const {
Mike Schuchardte5c15cf2020-04-06 22:57:13 -0700201 return (reinterpret_cast<uintptr_t>(&image_state_) ^ encoder_.AspectMask());
John Zulauf11211402019-11-15 14:02:36 -0700202}
203
204bool ImageSubresourceLayoutMap::UpdateFrom(const ImageSubresourceLayoutMap& other) {
John Zulauf11211402019-11-15 14:02:36 -0700205 // Must be from matching images for the reinterpret cast to be valid
206 assert(CompatibilityKey() == other.CompatibilityKey());
207 if (CompatibilityKey() != other.CompatibilityKey()) return false;
208
Jeremy Gebben53631302021-04-13 16:46:37 -0600209 // 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 -0700210 // currently this function is only used to import from secondary command buffers, destruction of which
211 // invalidate the referencing primary command buffer, meaning that the dangling pointer will either be
212 // cleaned up in invalidation, on not referenced by validation code.
Jeremy Gebben53631302021-04-13 16:46:37 -0600213 return sparse_container::splice(layouts_, other.layouts_, LayoutEntry::Updater());
John Zulauf11211402019-11-15 14:02:36 -0700214}
John Zulauf11211402019-11-15 14:02:36 -0700215
John Zulauf11211402019-11-15 14:02:36 -0700216// This is the same constant value range, subreource position advance logic as ForRange above, but suitable for use with
217// an Increment operator.
218void ImageSubresourceLayoutMap::ConstIterator::UpdateRangeAndValue() {
219 bool not_found = true;
Jeremy Gebben53631302021-04-13 16:46:37 -0600220 if (layouts_ == nullptr || layouts_->empty()) {
221 return;
222 }
223 while (iter_ != layouts_->end() && range_gen_->non_empty() && not_found) {
224 if (!iter_->first.includes(current_index_)) { // NOTE: empty ranges can't include anything
225 iter_ = layouts_->find(current_index_);
John Zulauf11211402019-11-15 14:02:36 -0700226 }
Jeremy Gebben53631302021-04-13 16:46:37 -0600227 if (iter_ == layouts_->end() || (iter_->first.empty() && skip_invalid_)) {
John Zulauf11211402019-11-15 14:02:36 -0700228 // We're past the end of mapped data, and we aren't interested, so we're done
229 // Set end condtion....
230 ForceEndCondition();
231 }
232 // Search within the current range_ for a constant valid constant value interval
Jeremy Gebben53631302021-04-13 16:46:37 -0600233 // The while condition allows the iterator to advance constant value ranges as needed.
234 while (iter_ != layouts_->end() && range_gen_->includes(current_index_) && not_found) {
John Zulauf11211402019-11-15 14:02:36 -0700235 pos_.current_layout = kInvalidLayout;
236 pos_.initial_layout = kInvalidLayout;
237 constant_value_bound_ = range_gen_->end;
238 // The generated range can validly traverse past the end of stored data
Jeremy Gebben53631302021-04-13 16:46:37 -0600239 if (!iter_->first.empty()) {
240 const LayoutEntry& entry = iter_->second;
241 pos_.current_layout = entry.current_layout;
John Zulauf11211402019-11-15 14:02:36 -0700242 if (pos_.current_layout == kInvalidLayout || always_get_initial_) {
Jeremy Gebben53631302021-04-13 16:46:37 -0600243 pos_.initial_layout = entry.initial_layout;
John Zulauf11211402019-11-15 14:02:36 -0700244 }
Jeremy Gebben53631302021-04-13 16:46:37 -0600245
John Zulauf11211402019-11-15 14:02:36 -0700246 // The constant value bound marks the end of contiguous (w.r.t. range_gen_) indices with the same value, allowing
247 // Increment (for example) to forgo this logic until finding a new range is needed.
Jeremy Gebben53631302021-04-13 16:46:37 -0600248 constant_value_bound_ = std::min(iter_->first.end, constant_value_bound_);
John Zulauf11211402019-11-15 14:02:36 -0700249 }
250 if (!skip_invalid_ || (pos_.current_layout != kInvalidLayout) || (pos_.initial_layout != kInvalidLayout)) {
251 // we found it ... set the position and exit condition.
John Zulauf2ea823e2019-11-19 08:54:59 -0700252 pos_.subresource = range_gen_.GetSubresource();
John Zulauf11211402019-11-15 14:02:36 -0700253 not_found = false;
254 } else {
255 // We're skipping this constant value range, set the index to the exclusive end and look again
John Zulaufdd18b3a2019-11-20 08:30:23 -0700256 // Note that we ONLY need to Seek the Subresource generator on a skip condition.
257 range_gen_.GetSubresourceGenerator().Seek(
John Zulauf11211402019-11-15 14:02:36 -0700258 constant_value_bound_); // Move the subresource to the end of the skipped range
259 current_index_ = constant_value_bound_;
260
Jeremy Gebben53631302021-04-13 16:46:37 -0600261 // Advance the iterator it if needed and possible
John Zulauf11211402019-11-15 14:02:36 -0700262 // NOTE: We don't need to seek, as current_index_ can only be in the current or next constant value range
Jeremy Gebben53631302021-04-13 16:46:37 -0600263 if (!iter_->first.empty() && !iter_->first.includes(current_index_)) {
264 ++iter_;
John Zulauf11211402019-11-15 14:02:36 -0700265 }
266 }
267 }
268
269 if (not_found) {
270 // ++range_gen will update subres_gen.
271 ++range_gen_;
272 current_index_ = range_gen_->begin;
273 }
274 }
275
276 if (range_gen_->empty()) {
277 ForceEndCondition();
278 }
279}
280
281void ImageSubresourceLayoutMap::ConstIterator::Increment() {
282 ++current_index_;
John Zulauf2ea823e2019-11-19 08:54:59 -0700283 ++(range_gen_.GetSubresourceGenerator());
John Zulauf11211402019-11-15 14:02:36 -0700284 if (constant_value_bound_ <= current_index_) {
285 UpdateRangeAndValue();
286 } else {
John Zulauf2ea823e2019-11-19 08:54:59 -0700287 pos_.subresource = range_gen_.GetSubresource();
John Zulauf11211402019-11-15 14:02:36 -0700288 }
289}
Tony Barbour55688172020-09-23 15:19:50 -0700290
291void ImageSubresourceLayoutMap::ConstIterator::IncrementInterval() {
292 // constant_value_bound_ is the exclusive upper bound of the constant value range.
293 // When current index is set to point to that, UpdateRangeAndValue skips to the next constant value range,
294 // setting that state as the current position / state for the iterator.
295 current_index_ = constant_value_bound_;
aitor-lunargb4359602022-02-16 19:54:50 +0100296 range_gen_.GetSubresourceGenerator().Seek(current_index_);
Tony Barbour55688172020-09-23 15:19:50 -0700297 UpdateRangeAndValue();
298}
299
Jeremy Gebben53631302021-04-13 16:46:37 -0600300ImageSubresourceLayoutMap::ConstIterator::ConstIterator(const RangeMap& layouts, const Encoder& encoder,
John Zulauf11211402019-11-15 14:02:36 -0700301 const VkImageSubresourceRange& subres, bool skip_invalid,
302 bool always_get_initial)
303 : range_gen_(encoder, subres),
Jeremy Gebben53631302021-04-13 16:46:37 -0600304 layouts_(&layouts),
305 iter_(layouts.begin()),
John Zulauf11211402019-11-15 14:02:36 -0700306 skip_invalid_(skip_invalid),
307 always_get_initial_(always_get_initial),
308 pos_(),
309 current_index_(range_gen_->begin),
310 constant_value_bound_() {
311 UpdateRangeAndValue();
312}
313
314} // namespace image_layout_map