blob: e1d2621b2cb46358770b0d6696a1307e11817314 [file] [log] [blame]
John Zulauf86ce1cf2020-01-23 12:27:01 -07001/* Copyright (c) 2019-2020 The Khronos Group Inc.
2 * Copyright (c) 2019-2020 Valve Corporation
3 * Copyright (c) 2019-2020 LunarG, Inc.
4 * Copyright (C) 2019-2020 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#ifdef SPARSE_CONTAINER_UNIT_TEST
22#include "image_layout_map.h"
23#else
John Zulauf11211402019-11-15 14:02:36 -070024#include "core_validation_types.h"
25#include "chassis.h"
26#include "descriptor_sets.h"
John Zulauf5823c622019-11-25 13:33:44 -070027#endif
John Zulauf11211402019-11-15 14:02:36 -070028
29namespace image_layout_map {
30// Storage for the static state
31const ImageSubresourceLayoutMap::ConstIterator ImageSubresourceLayoutMap::end_iterator = ImageSubresourceLayoutMap::ConstIterator();
32
John Zulauf81408f12019-11-27 16:40:27 -070033using InitialLayoutStates = ImageSubresourceLayoutMap::InitialLayoutStates;
34
35template <typename StatesMap>
John Zulaufb58415b2019-12-09 15:02:32 -070036static inline InitialLayoutState* UpdateInitialLayoutStateImpl(StatesMap* initial_layout_state_map,
37 InitialLayoutStates* states_storage, const IndexRange& range,
38 InitialLayoutState* initial_state, const CMD_BUFFER_STATE& cb_state,
39 const IMAGE_VIEW_STATE* view_state) {
John Zulauf81408f12019-11-27 16:40:27 -070040 auto& initial_layout_states = *states_storage;
41 if (!initial_state) {
42 // Allocate on demand... initial_layout_states_ holds ownership as a unique_ptr, while
43 // each subresource has a non-owning copy of the plain pointer.
44 initial_state = new InitialLayoutState(cb_state, view_state);
45 initial_layout_states.emplace_back(initial_state);
46 }
47 assert(initial_state);
48 sparse_container::update_range_value(*initial_layout_state_map, range, initial_state, WritePolicy::prefer_dest);
49 return initial_state;
50}
51
John Zulauf11211402019-11-15 14:02:36 -070052InitialLayoutState::InitialLayoutState(const CMD_BUFFER_STATE& cb_state_, const IMAGE_VIEW_STATE* view_state_)
53 : image_view(VK_NULL_HANDLE), aspect_mask(0), label(cb_state_.debug_label) {
54 if (view_state_) {
55 image_view = view_state_->image_view;
56 aspect_mask = view_state_->create_info.subresourceRange.aspectMask;
57 }
58}
59bool ImageSubresourceLayoutMap::SubresourceLayout::operator==(const ImageSubresourceLayoutMap::SubresourceLayout& rhs) const {
60 bool is_equal =
61 (current_layout == rhs.current_layout) && (initial_layout == rhs.initial_layout) && (subresource == rhs.subresource);
62 return is_equal;
63}
64ImageSubresourceLayoutMap::ImageSubresourceLayoutMap(const IMAGE_STATE& image_state)
John Zulaufb58415b2019-12-09 15:02:32 -070065 : image_state_(image_state),
66 encoder_(image_state.range_encoder),
John Zulauf81408f12019-11-27 16:40:27 -070067 layouts_(encoder_.SubresourceCount()),
John Zulauf11211402019-11-15 14:02:36 -070068 initial_layout_states_(),
John Zulauf81408f12019-11-27 16:40:27 -070069 initial_layout_state_map_(encoder_.SubresourceCount()) {}
John Zulauf11211402019-11-15 14:02:36 -070070
71ImageSubresourceLayoutMap::ConstIterator ImageSubresourceLayoutMap::Begin(bool always_get_initial) const {
72 return Find(image_state_.full_range, /* skip_invalid */ true, always_get_initial);
73}
John Zulauf81408f12019-11-27 16:40:27 -070074
75// Use the unwrapped maps from the BothMap in the actual implementation
76template <typename LayoutMap, typename InitialStateMap>
77static bool SetSubresourceRangeLayoutImpl(LayoutMap* current_layouts, LayoutMap* initial_layouts,
78 InitialStateMap* initial_state_map, InitialLayoutStates* initial_layout_states,
79 RangeGenerator* range_gen_arg, const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
80 VkImageLayout expected_layout) {
81 bool updated = false;
82 auto& range_gen = *range_gen_arg;
83 InitialLayoutState* initial_state = nullptr;
84 // Empty range are the range tombstones
85 for (; range_gen->non_empty(); ++range_gen) {
86 // In order to track whether we've changed anything, we'll do this in a slightly convoluted way...
87 // We'll traverse the range looking for values different from ours, then overwrite the range.
88 bool updated_current =
89 sparse_container::update_range_value(*current_layouts, *range_gen, layout, WritePolicy::prefer_source);
90 if (updated_current) {
91 updated = true;
92 bool updated_init =
93 sparse_container::update_range_value(*initial_layouts, *range_gen, expected_layout, WritePolicy::prefer_dest);
94 if (updated_init) {
95 initial_state = UpdateInitialLayoutStateImpl(initial_state_map, initial_layout_states, *range_gen, initial_state,
96 cb_state, nullptr);
97 }
98 }
99 }
100 return updated;
101}
102
John Zulauf11211402019-11-15 14:02:36 -0700103bool ImageSubresourceLayoutMap::SetSubresourceRangeLayout(const CMD_BUFFER_STATE& cb_state, const VkImageSubresourceRange& range,
104 VkImageLayout layout, VkImageLayout expected_layout) {
John Zulauf11211402019-11-15 14:02:36 -0700105 if (expected_layout == kInvalidLayout) {
106 // Set the initial layout to the set layout as we had no other layout to reference
107 expected_layout = layout;
108 }
109 if (!InRange(range)) return false; // Don't even try to track bogus subreources
110
John Zulauf11211402019-11-15 14:02:36 -0700111 RangeGenerator range_gen(encoder_, range);
John Zulauf81408f12019-11-27 16:40:27 -0700112 if (layouts_.initial.SmallMode()) {
113 return SetSubresourceRangeLayoutImpl(&layouts_.current.GetSmallMap(), &layouts_.initial.GetSmallMap(),
114 &initial_layout_state_map_.GetSmallMap(), &initial_layout_states_, &range_gen,
115 cb_state, layout, expected_layout);
116 } else {
117 assert(!layouts_.initial.Tristate());
118 return SetSubresourceRangeLayoutImpl(&layouts_.current.GetBigMap(), &layouts_.initial.GetBigMap(),
119 &initial_layout_state_map_.GetBigMap(), &initial_layout_states_, &range_gen, cb_state,
120 layout, expected_layout);
121 }
122}
123
124// Use the unwrapped maps from the BothMap in the actual implementation
125template <typename LayoutMap, typename InitialStateMap>
126static bool SetSubresourceRangeInitialLayoutImpl(LayoutMap* initial_layouts, InitialStateMap* initial_state_map,
127 InitialLayoutStates* initial_layout_states, RangeGenerator* range_gen_arg,
128 const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
129 const IMAGE_VIEW_STATE* view_state) {
130 bool updated = false;
131 InitialLayoutState* initial_state = nullptr;
132 auto& range_gen = *range_gen_arg;
133
John Zulauf11211402019-11-15 14:02:36 -0700134 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf81408f12019-11-27 16:40:27 -0700135 bool updated_range = sparse_container::update_range_value(*initial_layouts, *range_gen, layout, WritePolicy::prefer_dest);
136 if (updated_range) {
137 initial_state = UpdateInitialLayoutStateImpl(initial_state_map, initial_layout_states, *range_gen, initial_state,
138 cb_state, view_state);
John Zulauf11211402019-11-15 14:02:36 -0700139 updated = true;
John Zulauf11211402019-11-15 14:02:36 -0700140 }
141 }
142 return updated;
143}
John Zulauf81408f12019-11-27 16:40:27 -0700144
145// Unwrap the BothMaps entry here as this is a performance hotspot.
John Zulauf11211402019-11-15 14:02:36 -0700146bool ImageSubresourceLayoutMap::SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state,
147 const VkImageSubresourceRange& range, VkImageLayout layout,
148 const IMAGE_VIEW_STATE* view_state) {
John Zulauf11211402019-11-15 14:02:36 -0700149 if (!InRange(range)) return false; // Don't even try to track bogus subreources
150
John Zulauf11211402019-11-15 14:02:36 -0700151 RangeGenerator range_gen(encoder_, range);
John Zulauf81408f12019-11-27 16:40:27 -0700152 assert(layouts_.initial.GetMode() == initial_layout_state_map_.GetMode());
153 if (layouts_.initial.SmallMode()) {
154 return SetSubresourceRangeInitialLayoutImpl(&layouts_.initial.GetSmallMap(), &initial_layout_state_map_.GetSmallMap(),
155 &initial_layout_states_, &range_gen, cb_state, layout, view_state);
156 } else {
157 assert(!layouts_.initial.Tristate());
158 return SetSubresourceRangeInitialLayoutImpl(&layouts_.initial.GetBigMap(), &initial_layout_state_map_.GetBigMap(),
159 &initial_layout_states_, &range_gen, cb_state, layout, view_state);
John Zulauf11211402019-11-15 14:02:36 -0700160 }
John Zulauf11211402019-11-15 14:02:36 -0700161}
162
John Zulaufb58415b2019-12-09 15:02:32 -0700163// Unwrap the BothMaps entry here as this is a performance hotspot.
164bool ImageSubresourceLayoutMap::SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
165 const IMAGE_VIEW_STATE& view_state) {
166 RangeGenerator range_gen(view_state.range_generator);
167 assert(layouts_.initial.GetMode() == initial_layout_state_map_.GetMode());
168 if (layouts_.initial.SmallMode()) {
169 return SetSubresourceRangeInitialLayoutImpl(&layouts_.initial.GetSmallMap(), &initial_layout_state_map_.GetSmallMap(),
170 &initial_layout_states_, &range_gen, cb_state, layout, &view_state);
171 } else {
172 assert(!layouts_.initial.Tristate());
173 return SetSubresourceRangeInitialLayoutImpl(&layouts_.initial.GetBigMap(), &initial_layout_state_map_.GetBigMap(),
174 &initial_layout_states_, &range_gen, cb_state, layout, &view_state);
175 }
176}
177
John Zulauf11211402019-11-15 14:02:36 -0700178static VkImageLayout FindInMap(IndexType index, const ImageSubresourceLayoutMap::RangeMap& map) {
179 auto found = map.find(index);
180 VkImageLayout value = kInvalidLayout;
181 if (found != map.end()) {
182 value = found->second;
183 }
184 return value;
185}
186VkImageLayout ImageSubresourceLayoutMap::GetSubresourceLayout(const VkImageSubresource& subresource) const {
187 IndexType index = encoder_.Encode(subresource);
188 return FindInMap(index, layouts_.current);
189}
190
191VkImageLayout ImageSubresourceLayoutMap::GetSubresourceInitialLayout(const VkImageSubresource& subresource) const {
192 IndexType index = encoder_.Encode(subresource);
193 return FindInMap(index, layouts_.initial);
194}
195
196// Saves an encode to fetch both in the same call
197ImageSubresourceLayoutMap::Layouts ImageSubresourceLayoutMap::GetSubresourceLayouts(const VkImageSubresource& subresource,
198 bool always_get_initial) const {
199 IndexType index = encoder_.Encode(subresource);
200 Layouts layouts{FindInMap(index, layouts_.current), kInvalidLayout};
201 if (always_get_initial || (layouts.current_layout != kInvalidLayout)) {
202 layouts.initial_layout = FindInMap(index, layouts_.initial);
203 }
204 return layouts;
205}
206
John Zulauf2076e812020-01-08 14:55:54 -0700207const InitialLayoutState* ImageSubresourceLayoutMap::GetSubresourceInitialLayoutState(const IndexType index) const {
John Zulauf11211402019-11-15 14:02:36 -0700208 const auto found = initial_layout_state_map_.find(index);
209 if (found != initial_layout_state_map_.end()) {
210 return found->second;
211 }
212 return nullptr;
213}
214
John Zulauf2076e812020-01-08 14:55:54 -0700215const InitialLayoutState* ImageSubresourceLayoutMap::GetSubresourceInitialLayoutState(const VkImageSubresource& subresource) const {
216 if (!InRange(subresource)) return nullptr;
217 const auto index = encoder_.Encode(subresource);
218 return GetSubresourceInitialLayoutState(index);
219}
220
John Zulauf11211402019-11-15 14:02:36 -0700221// TODO: make sure this paranoia check is sufficient and not too much.
222uintptr_t ImageSubresourceLayoutMap::CompatibilityKey() const {
Mike Schuchardte5c15cf2020-04-06 22:57:13 -0700223 return (reinterpret_cast<uintptr_t>(&image_state_) ^ encoder_.AspectMask());
John Zulauf11211402019-11-15 14:02:36 -0700224}
225
226bool ImageSubresourceLayoutMap::UpdateFrom(const ImageSubresourceLayoutMap& other) {
John Zulauf81408f12019-11-27 16:40:27 -0700227 using Arbiter = sparse_container::value_precedence;
John Zulauf11211402019-11-15 14:02:36 -0700228
229 using sparse_container::range;
230 // Must be from matching images for the reinterpret cast to be valid
231 assert(CompatibilityKey() == other.CompatibilityKey());
232 if (CompatibilityKey() != other.CompatibilityKey()) return false;
233
234 bool updated = false;
235 updated |= sparse_container::splice(&layouts_.initial, other.layouts_.initial, Arbiter::prefer_dest);
236 updated |= sparse_container::splice(&layouts_.current, other.layouts_.current, Arbiter::prefer_source);
237 // NOTE -- we are copying plain pointers from 'other' which owns them as unique_ptr. This works because
238 // currently this function is only used to import from secondary command buffers, destruction of which
239 // invalidate the referencing primary command buffer, meaning that the dangling pointer will either be
240 // cleaned up in invalidation, on not referenced by validation code.
241 sparse_container::splice(&initial_layout_state_map_, other.initial_layout_state_map_, Arbiter::prefer_dest);
242
243 return updated;
244}
John Zulauf11211402019-11-15 14:02:36 -0700245
John Zulauf11211402019-11-15 14:02:36 -0700246// This is the same constant value range, subreource position advance logic as ForRange above, but suitable for use with
247// an Increment operator.
248void ImageSubresourceLayoutMap::ConstIterator::UpdateRangeAndValue() {
249 bool not_found = true;
250 while (range_gen_->non_empty() && not_found) {
251 if (!parallel_it_->range.includes(current_index_)) { // NOTE: empty ranges can't include anything
252 parallel_it_.seek(current_index_);
253 }
254 if (parallel_it_->range.empty() && skip_invalid_) {
255 // We're past the end of mapped data, and we aren't interested, so we're done
256 // Set end condtion....
257 ForceEndCondition();
258 }
259 // Search within the current range_ for a constant valid constant value interval
260 // The while condition allows the parallel iterator to advance constant value ranges as needed.
261 while (range_gen_->includes(current_index_) && not_found) {
262 pos_.current_layout = kInvalidLayout;
263 pos_.initial_layout = kInvalidLayout;
264 constant_value_bound_ = range_gen_->end;
265 // The generated range can validly traverse past the end of stored data
266 if (!parallel_it_->range.empty()) {
267 pos_.current_layout = sparse_container::evaluate(parallel_it_->pos_A, kInvalidLayout);
268 if (pos_.current_layout == kInvalidLayout || always_get_initial_) {
269 pos_.initial_layout = sparse_container::evaluate(parallel_it_->pos_B, kInvalidLayout);
270 }
271 // The constant value bound marks the end of contiguous (w.r.t. range_gen_) indices with the same value, allowing
272 // Increment (for example) to forgo this logic until finding a new range is needed.
273 constant_value_bound_ = std::min(parallel_it_->range.end, constant_value_bound_);
274 }
275 if (!skip_invalid_ || (pos_.current_layout != kInvalidLayout) || (pos_.initial_layout != kInvalidLayout)) {
276 // we found it ... set the position and exit condition.
John Zulauf2ea823e2019-11-19 08:54:59 -0700277 pos_.subresource = range_gen_.GetSubresource();
John Zulauf11211402019-11-15 14:02:36 -0700278 not_found = false;
279 } else {
280 // We're skipping this constant value range, set the index to the exclusive end and look again
John Zulaufdd18b3a2019-11-20 08:30:23 -0700281 // Note that we ONLY need to Seek the Subresource generator on a skip condition.
282 range_gen_.GetSubresourceGenerator().Seek(
John Zulauf11211402019-11-15 14:02:36 -0700283 constant_value_bound_); // Move the subresource to the end of the skipped range
284 current_index_ = constant_value_bound_;
285
286 // Advance the parallel it if needed and possible
287 // NOTE: We don't need to seek, as current_index_ can only be in the current or next constant value range
288 if (!parallel_it_->range.empty() && !parallel_it_->range.includes(current_index_)) {
289 ++parallel_it_;
290 }
291 }
292 }
293
294 if (not_found) {
295 // ++range_gen will update subres_gen.
296 ++range_gen_;
297 current_index_ = range_gen_->begin;
298 }
299 }
300
301 if (range_gen_->empty()) {
302 ForceEndCondition();
303 }
304}
305
306void ImageSubresourceLayoutMap::ConstIterator::Increment() {
307 ++current_index_;
John Zulauf2ea823e2019-11-19 08:54:59 -0700308 ++(range_gen_.GetSubresourceGenerator());
John Zulauf11211402019-11-15 14:02:36 -0700309 if (constant_value_bound_ <= current_index_) {
310 UpdateRangeAndValue();
311 } else {
John Zulauf2ea823e2019-11-19 08:54:59 -0700312 pos_.subresource = range_gen_.GetSubresource();
John Zulauf11211402019-11-15 14:02:36 -0700313 }
314}
315ImageSubresourceLayoutMap::ConstIterator::ConstIterator(const RangeMap& current, const RangeMap& initial, const Encoder& encoder,
316 const VkImageSubresourceRange& subres, bool skip_invalid,
317 bool always_get_initial)
318 : range_gen_(encoder, subres),
319 parallel_it_(current, initial, range_gen_->begin),
320 skip_invalid_(skip_invalid),
321 always_get_initial_(always_get_initial),
322 pos_(),
323 current_index_(range_gen_->begin),
324 constant_value_bound_() {
325 UpdateRangeAndValue();
326}
327
328} // namespace image_layout_map