blob: dcd18f0e93a21d74829035013a49dd118f733236 [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 */
21#include <cassert>
22#include "subresource_adapter.h"
locke-lunarg296a3c92020-03-25 01:04:29 -060023#include "vk_format_utils.h"
24#include "state_tracker.h"
25#include "core_validation_types.h"
locke-lunargf9293012020-04-16 17:01:23 -060026#include <cmath>
John Zulauf11211402019-11-15 14:02:36 -070027
28namespace subresource_adapter {
John Zulauf2ea823e2019-11-19 08:54:59 -070029Subresource::Subresource(const RangeEncoder& encoder, const VkImageSubresource& subres)
30 : VkImageSubresource({0, subres.mipLevel, subres.arrayLayer}), aspect_index() {
31 aspect_index = encoder.LowerBoundFromMask(subres.aspectMask);
32 aspectMask = encoder.AspectBit(aspect_index);
33}
34
35IndexType RangeEncoder::Encode1AspectArrayOnly(const Subresource& pos) const { return pos.arrayLayer; }
36IndexType RangeEncoder::Encode1AspectMipArray(const Subresource& pos) const { return pos.arrayLayer + pos.mipLevel * mip_size_; }
37IndexType RangeEncoder::Encode1AspectMipOnly(const Subresource& pos) const { return pos.mipLevel; }
John Zulauf11211402019-11-15 14:02:36 -070038
39IndexType RangeEncoder::EncodeAspectArrayOnly(const Subresource& pos) const {
John Zulauf2ea823e2019-11-19 08:54:59 -070040 return pos.arrayLayer + aspect_base_[pos.aspect_index];
John Zulauf11211402019-11-15 14:02:36 -070041}
42IndexType RangeEncoder::EncodeAspectMipArray(const Subresource& pos) const {
John Zulauf2ea823e2019-11-19 08:54:59 -070043 return pos.arrayLayer + pos.mipLevel * mip_size_ + aspect_base_[pos.aspect_index];
John Zulauf11211402019-11-15 14:02:36 -070044}
John Zulauf2ea823e2019-11-19 08:54:59 -070045IndexType RangeEncoder::EncodeAspectMipOnly(const Subresource& pos) const { return pos.mipLevel + aspect_base_[pos.aspect_index]; }
John Zulauf11211402019-11-15 14:02:36 -070046
John Zulauf2ea823e2019-11-19 08:54:59 -070047uint32_t RangeEncoder::LowerBoundImpl1(VkImageAspectFlags aspect_mask) const {
48 assert(aspect_mask & aspect_bits_[0]);
49 return 0;
50}
51uint32_t RangeEncoder::LowerBoundWithStartImpl1(VkImageAspectFlags aspect_mask, uint32_t start) const {
52 assert(start == 0);
53 if (aspect_mask & aspect_bits_[0]) {
54 return 0;
55 }
56 return limits_.aspect_index;
John Zulauf11211402019-11-15 14:02:36 -070057}
58
John Zulauf2ea823e2019-11-19 08:54:59 -070059uint32_t RangeEncoder::LowerBoundImpl2(VkImageAspectFlags aspect_mask) const {
60 if (aspect_mask & aspect_bits_[0]) {
61 return 0;
62 }
63 assert(aspect_mask & aspect_bits_[1]);
64 return 1;
John Zulauf11211402019-11-15 14:02:36 -070065}
John Zulauf2ea823e2019-11-19 08:54:59 -070066uint32_t RangeEncoder::LowerBoundWithStartImpl2(VkImageAspectFlags aspect_mask, uint32_t start) const {
John Zulauf5823c622019-11-25 13:33:44 -070067 switch (start) {
68 case 0:
69 if (aspect_mask & aspect_bits_[0]) {
70 return 0;
71 }
72 // no break
73 case 1:
74 if (aspect_mask & aspect_bits_[1]) {
75 return 1;
76 }
77 break;
78 default:
79 break;
John Zulauf2ea823e2019-11-19 08:54:59 -070080 }
81 return limits_.aspect_index;
82}
83
84uint32_t RangeEncoder::LowerBoundImpl3(VkImageAspectFlags aspect_mask) const {
85 if (aspect_mask & aspect_bits_[0]) {
86 return 0;
87 } else if (aspect_mask & aspect_bits_[1]) {
88 return 1;
89 } else {
90 assert(aspect_mask & aspect_bits_[2]);
91 return 2;
92 }
93}
94
95uint32_t RangeEncoder::LowerBoundWithStartImpl3(VkImageAspectFlags aspect_mask, uint32_t start) const {
John Zulauf5823c622019-11-25 13:33:44 -070096 switch (start) {
97 case 0:
98 if (aspect_mask & aspect_bits_[0]) {
99 return 0;
100 }
101 // no break
102 case 1:
103 if ((aspect_mask & aspect_bits_[1])) {
104 return 1;
105 }
106 // no break
107 case 2:
108 if ((aspect_mask & aspect_bits_[2])) {
109 return 2;
110 }
111 break;
112 default:
113 break;
John Zulauf2ea823e2019-11-19 08:54:59 -0700114 }
115 return limits_.aspect_index;
116}
117
John Zulauf11211402019-11-15 14:02:36 -0700118void RangeEncoder::PopulateFunctionPointers() {
119 // Select the encode/decode specialists
120 if (limits_.aspect_index == 1) {
121 // One aspect use simplified encode/decode math
John Zulauf2ea823e2019-11-19 08:54:59 -0700122 if (limits_.arrayLayer == 1) { // Same as mip_size_ == 1
John Zulauf11211402019-11-15 14:02:36 -0700123 encode_function_ = &RangeEncoder::Encode1AspectMipOnly;
124 decode_function_ = &RangeEncoder::DecodeAspectMipOnly<1>;
John Zulauf2ea823e2019-11-19 08:54:59 -0700125 } else if (limits_.mipLevel == 1) {
John Zulauf11211402019-11-15 14:02:36 -0700126 encode_function_ = &RangeEncoder::Encode1AspectArrayOnly;
127 decode_function_ = &RangeEncoder::DecodeAspectArrayOnly<1>;
128 } else {
129 encode_function_ = &RangeEncoder::Encode1AspectMipArray;
130 decode_function_ = &RangeEncoder::DecodeAspectMipArray<1>;
131 }
John Zulauf2ea823e2019-11-19 08:54:59 -0700132 lower_bound_function_ = &RangeEncoder::LowerBoundImpl1;
133 lower_bound_with_start_function_ = &RangeEncoder::LowerBoundWithStartImpl1;
John Zulauf11211402019-11-15 14:02:36 -0700134 } else if (limits_.aspect_index == 2) {
135 // Two aspect use simplified encode/decode math
John Zulauf2ea823e2019-11-19 08:54:59 -0700136 if (limits_.arrayLayer == 1) { // Same as mip_size_ == 1
John Zulauf11211402019-11-15 14:02:36 -0700137 encode_function_ = &RangeEncoder::EncodeAspectMipOnly;
138 decode_function_ = &RangeEncoder::DecodeAspectMipOnly<2>;
John Zulauf2ea823e2019-11-19 08:54:59 -0700139 } else if (limits_.mipLevel == 1) {
John Zulauf11211402019-11-15 14:02:36 -0700140 encode_function_ = &RangeEncoder::EncodeAspectArrayOnly;
141 decode_function_ = &RangeEncoder::DecodeAspectArrayOnly<2>;
142 } else {
143 encode_function_ = &RangeEncoder::EncodeAspectMipArray;
144 decode_function_ = &RangeEncoder::DecodeAspectMipArray<2>;
145 }
John Zulauf2ea823e2019-11-19 08:54:59 -0700146 lower_bound_function_ = &RangeEncoder::LowerBoundImpl2;
147 lower_bound_with_start_function_ = &RangeEncoder::LowerBoundWithStartImpl2;
John Zulauf11211402019-11-15 14:02:36 -0700148 } else {
149 encode_function_ = &RangeEncoder::EncodeAspectMipArray;
150 decode_function_ = &RangeEncoder::DecodeAspectMipArray<3>;
John Zulauf2ea823e2019-11-19 08:54:59 -0700151 lower_bound_function_ = &RangeEncoder::LowerBoundImpl3;
152 lower_bound_with_start_function_ = &RangeEncoder::LowerBoundWithStartImpl3;
John Zulauf11211402019-11-15 14:02:36 -0700153 }
154
155 // Initialize the offset array
156 aspect_base_[0] = 0;
157 for (uint32_t i = 1; i < limits_.aspect_index; ++i) {
158 aspect_base_[i] = aspect_base_[i - 1] + aspect_size_;
159 }
160}
John Zulauf11211402019-11-15 14:02:36 -0700161
162RangeEncoder::RangeEncoder(const VkImageSubresourceRange& full_range, const AspectParameters* param)
locke-lunarg296a3c92020-03-25 01:04:29 -0600163 : limits_(param->AspectMask(), full_range.levelCount, full_range.layerCount, param->AspectCount()),
164 full_range_(full_range),
John Zulauf11211402019-11-15 14:02:36 -0700165 mip_size_(full_range.layerCount),
166 aspect_size_(mip_size_ * full_range.levelCount),
167 aspect_bits_(param->AspectBits()),
168 mask_index_function_(param->MaskToIndexFunction()),
169 encode_function_(nullptr),
170 decode_function_(nullptr) {
171 // Only valid to create an encoder for a *whole* image (i.e. base must be zero, and the specified limits_.selected_aspects
172 // *must* be equal to the traits aspect mask. (Encoder range assumes zero bases)
John Zulauf2ea823e2019-11-19 08:54:59 -0700173 assert(full_range.aspectMask == limits_.aspectMask);
John Zulauf11211402019-11-15 14:02:36 -0700174 assert(full_range.baseArrayLayer == 0);
175 assert(full_range.baseMipLevel == 0);
176 // TODO: should be some static assert
177 assert(param->AspectCount() <= kMaxSupportedAspect);
178 PopulateFunctionPointers();
179}
180
locke-lunarg5faaff52020-02-27 14:31:11 -0700181static bool IsValid(const RangeEncoder& encoder, const VkImageSubresourceRange& bounds) {
182 const auto& limits = encoder.Limits();
183 return (((bounds.aspectMask & limits.aspectMask) == bounds.aspectMask) &&
184 (bounds.baseMipLevel + bounds.levelCount <= limits.mipLevel) &&
185 (bounds.baseArrayLayer + bounds.layerCount <= limits.arrayLayer));
186}
187
John Zulauf11211402019-11-15 14:02:36 -0700188// Create an iterator like "generator" that for each increment produces the next index range matching the
189// next contiguous (in index space) section of the VkImageSubresourceRange
190// Ranges will always span the layerCount layers, and if the layerCount is the full range of the image (as known by
191// the encoder) will span the levelCount mip levels as weill.
John Zulauf11211402019-11-15 14:02:36 -0700192RangeGenerator::RangeGenerator(const RangeEncoder& encoder, const VkImageSubresourceRange& subres_range)
193 : encoder_(&encoder), isr_pos_(encoder, subres_range), pos_(), aspect_base_() {
Mark Lobodzinskibb279b92020-05-08 13:03:52 -0600194 assert((((isr_pos_.Limits()).aspectMask & (encoder.Limits()).aspectMask) == (isr_pos_.Limits()).aspectMask) &&
195 ((isr_pos_.Limits()).baseMipLevel + (isr_pos_.Limits()).levelCount <= (encoder.Limits()).mipLevel) &&
196 ((isr_pos_.Limits()).baseArrayLayer + (isr_pos_.Limits()).layerCount <= (encoder.Limits()).arrayLayer));
John Zulauf11211402019-11-15 14:02:36 -0700197
John Zulauf2ea823e2019-11-19 08:54:59 -0700198 // To see if we have a full range special case, need to compare the subres_range against the *encoders* limits
199 const auto& limits = encoder.Limits();
200 if ((subres_range.baseArrayLayer == 0 && subres_range.layerCount == limits.arrayLayer)) {
201 if ((subres_range.baseMipLevel == 0) && (subres_range.levelCount == limits.mipLevel)) {
202 if (subres_range.aspectMask == limits.aspectMask) {
203 // Full range
204 pos_.begin = 0;
205 pos_.end = encoder.AspectSize() * limits.aspect_index;
206 aspect_count_ = 1; // Flag this to never advance aspects.
207 } else {
208 // All mips all layers but not all aspect
209 pos_.begin = encoder.AspectBase(isr_pos_.aspect_index);
210 pos_.end = pos_.begin + encoder.AspectSize();
211 aspect_count_ = limits.aspect_index;
212 }
213 } else {
214 // All array layers, but not all levels
215 pos_.begin = encoder.AspectBase(isr_pos_.aspect_index) + subres_range.baseMipLevel * encoder.MipSize();
216 pos_.end = pos_.begin + subres_range.levelCount * encoder.MipSize();
217 aspect_count_ = limits.aspect_index;
218 }
219
John Zulauf11211402019-11-15 14:02:36 -0700220 // Full set of array layers at a time, thus we can span across all selected mip levels
John Zulauf11211402019-11-15 14:02:36 -0700221 mip_count_ = 1; // we don't ever advance across mips, as we do all of then in one range
222 } else {
223 // Each range covers all included array_layers for each selected mip_level for each given selected aspect
John Zulauf2ea823e2019-11-19 08:54:59 -0700224 // so we'll use the general purpose encode and smallest range size
225 pos_.begin = encoder.Encode(isr_pos_);
226 pos_.end = pos_.begin + subres_range.layerCount;
227
John Zulauf11211402019-11-15 14:02:36 -0700228 // we do have to traverse across mips, though (other than Encode abover), we don't have to know which one we are on.
229 mip_count_ = subres_range.levelCount;
John Zulauf2ea823e2019-11-19 08:54:59 -0700230 aspect_count_ = limits.aspect_index;
John Zulauf11211402019-11-15 14:02:36 -0700231 }
232
John Zulauf2ea823e2019-11-19 08:54:59 -0700233 // To get to the next aspect range we offset from the last base
John Zulauf11211402019-11-15 14:02:36 -0700234 aspect_base_ = pos_;
235 mip_index_ = 0;
John Zulauf2ea823e2019-11-19 08:54:59 -0700236 aspect_index_ = isr_pos_.aspect_index;
John Zulauf11211402019-11-15 14:02:36 -0700237}
238
239RangeGenerator& RangeGenerator::operator++() {
240 mip_index_++;
241 // NOTE: If all selected mip levels are done at once, mip_count_ is set to one, not the number of selected mip_levels
242 if (mip_index_ >= mip_count_) {
John Zulauf2ea823e2019-11-19 08:54:59 -0700243 const auto last_aspect_index = aspect_index_;
244 // Seek the next value aspect (if any)
245 aspect_index_ = encoder_->LowerBoundFromMask(isr_pos_.Limits().aspectMask, aspect_index_ + 1);
246 if (aspect_index_ < aspect_count_) {
247 // Force isr_pos to the beginning of this found aspect
John Zulaufdd18b3a2019-11-20 08:30:23 -0700248 isr_pos_.SeekAspect(aspect_index_);
John Zulauf2ea823e2019-11-19 08:54:59 -0700249 // SubresourceGenerator should never be at tombstones we we aren't
250 assert(isr_pos_.aspectMask != 0);
251
252 // Offset by the distance between the last start of aspect and *this* start of aspect
253 aspect_base_ += (encoder_->AspectBase(isr_pos_.aspect_index) - encoder_->AspectBase(last_aspect_index));
John Zulauf11211402019-11-15 14:02:36 -0700254 pos_ = aspect_base_;
255 mip_index_ = 0;
256 } else {
John Zulauf2ea823e2019-11-19 08:54:59 -0700257 // Tombstone both index range and subresource positions to "At end" convention
John Zulauf11211402019-11-15 14:02:36 -0700258 pos_ = {0, 0};
John Zulauf2ea823e2019-11-19 08:54:59 -0700259 isr_pos_.aspectMask = 0;
John Zulauf11211402019-11-15 14:02:36 -0700260 }
John Zulauf11211402019-11-15 14:02:36 -0700261 } else {
262 // Note: for the layerCount < full_range.layerCount case, because the generated ranges per mip_level are discontinuous
John Zulauf2ea823e2019-11-19 08:54:59 -0700263 // we have to do each individual array of ranges
John Zulauf11211402019-11-15 14:02:36 -0700264 pos_ += encoder_->MipSize();
John Zulaufdd18b3a2019-11-20 08:30:23 -0700265 isr_pos_.SeekMip(isr_pos_.Limits().baseMipLevel + mip_index_);
John Zulauf11211402019-11-15 14:02:36 -0700266 }
267 return *this;
268}
269
locke-lunargae26eac2020-04-16 15:29:05 -0600270ImageRangeEncoder::ImageRangeEncoder(const IMAGE_STATE& image)
271 : ImageRangeEncoder(image, AspectParameters::Get(image.full_range.aspectMask)) {}
locke-lunarg5faaff52020-02-27 14:31:11 -0700272
locke-lunargae26eac2020-04-16 15:29:05 -0600273ImageRangeEncoder::ImageRangeEncoder(const IMAGE_STATE& image, const AspectParameters* param)
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600274 : RangeEncoder(image.full_range, param), image_(&image) {
locke-lunarge3d93b02020-06-22 18:36:28 -0600275 if (image_->createInfo.extent.depth > 1) {
276 limits_.arrayLayer = image_->createInfo.extent.depth;
277 }
locke-lunarg296a3c92020-03-25 01:04:29 -0600278 VkSubresourceLayout layout = {};
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600279 VkImageSubresource subres = {};
locke-lunarg296a3c92020-03-25 01:04:29 -0600280 VkImageSubresourceLayers subres_layers = {limits_.aspectMask, 0, 0, limits_.arrayLayer};
locke-lunarg3f6978b2020-04-16 16:51:35 -0600281 linear_image = false;
282
283 // WORKAROUND for dev_sim and mock_icd not containing valid VkSubresourceLayout yet. Treat it as optimal image.
284 if (image_->createInfo.tiling != VK_IMAGE_TILING_OPTIMAL) {
285 subres = {static_cast<VkImageAspectFlags>(AspectBit(0)), 0, 0};
286 DispatchGetImageSubresourceLayout(image_->store_device_as_workaround, image_->image, &subres, &layout);
287 if (layout.size > 0) {
288 linear_image = true;
289 }
290 }
locke-lunarg5faaff52020-02-27 14:31:11 -0700291
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700292 bool const is_3_d = image_->createInfo.imageType == VK_IMAGE_TYPE_3D;
locke-lunarg296a3c92020-03-25 01:04:29 -0600293 for (uint32_t mip_index = 0; mip_index < limits_.mipLevel; ++mip_index) {
294 subres_layers.mipLevel = mip_index;
locke-lunarg3f6978b2020-04-16 16:51:35 -0600295 subres.mipLevel = mip_index;
locke-lunarg296a3c92020-03-25 01:04:29 -0600296 for (uint32_t aspect_index = 0; aspect_index < limits_.aspect_index; ++aspect_index) {
locke-lunarg3f6978b2020-04-16 16:51:35 -0600297 subres.aspectMask = static_cast<VkImageAspectFlags>(AspectBit(aspect_index));
locke-lunarg20485372020-07-16 01:58:46 -0600298 subres_layers.aspectMask = subres.aspectMask;
299
300 auto subres_extent = GetImageSubresourceExtent(image_, &subres_layers);
301 subres_extents_.push_back(subres_extent);
302
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600303 if (mip_index == 0) {
locke-lunargf9293012020-04-16 17:01:23 -0600304 texel_sizes_.push_back(FormatTexelSize(image.createInfo.format, subres.aspectMask));
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600305 }
locke-lunarg3f6978b2020-04-16 16:51:35 -0600306 if (linear_image) {
307 DispatchGetImageSubresourceLayout(image_->store_device_as_workaround, image_->image, &subres, &layout);
308 subres_layouts_.push_back(layout);
309 } else {
locke-lunarg3f6978b2020-04-16 16:51:35 -0600310 layout.offset += layout.size;
locke-lunarg20485372020-07-16 01:58:46 -0600311 layout.rowPitch = static_cast<VkDeviceSize>(floor(subres_extent.width * texel_sizes_[aspect_index]));
312 layout.arrayPitch = layout.rowPitch * subres_extent.height;
locke-lunarg3f6978b2020-04-16 16:51:35 -0600313 layout.depthPitch = layout.arrayPitch;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700314 if (is_3_d) {
John Zulauf5eb24252020-08-28 17:53:58 -0600315 layout.size = layout.depthPitch * subres_extent.depth;
316 } else {
317 // 2D arrays are not affected by MIP level extent reductions.
318 layout.size = layout.arrayPitch * limits_.arrayLayer;
319 }
locke-lunarg3f6978b2020-04-16 16:51:35 -0600320 subres_layouts_.push_back(layout);
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600321 }
locke-lunarg5faaff52020-02-27 14:31:11 -0700322 }
locke-lunarg5faaff52020-02-27 14:31:11 -0700323 }
locke-lunarg5faaff52020-02-27 14:31:11 -0700324}
325
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600326IndexType ImageRangeEncoder::Encode(const VkImageSubresource& subres, uint32_t layer, VkOffset3D offset) const {
327 const auto& subres_layout = SubresourceLayout(subres);
Mark Young0ec6b062020-11-19 15:32:17 -0700328 return static_cast<IndexType>(floor(static_cast<double>(layer * subres_layout.arrayPitch + offset.z * subres_layout.depthPitch +
329 offset.y * subres_layout.rowPitch) +
330 offset.x * texel_sizes_[LowerBoundFromMask(subres.aspectMask)] +
331 static_cast<double>(subres_layout.offset)));
locke-lunarg296a3c92020-03-25 01:04:29 -0600332}
locke-lunarg5faaff52020-02-27 14:31:11 -0700333
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600334void ImageRangeEncoder::Decode(const VkImageSubresource& subres, const IndexType& encode, uint32_t& out_layer,
335 VkOffset3D& out_offset) const {
336 const auto& subres_layout = SubresourceLayout(subres);
337 IndexType decode = encode - subres_layout.offset;
338 out_layer = static_cast<uint32_t>(decode / subres_layout.arrayPitch);
339 decode -= (out_layer * subres_layout.arrayPitch);
340 out_offset.z = static_cast<int32_t>(decode / subres_layout.depthPitch);
341 decode -= (out_offset.z * subres_layout.depthPitch);
342 out_offset.y = static_cast<int32_t>(decode / subres_layout.rowPitch);
343 decode -= (out_offset.y * subres_layout.rowPitch);
Mark Young0ec6b062020-11-19 15:32:17 -0700344 out_offset.x = static_cast<int32_t>(static_cast<double>(decode) / texel_sizes_[LowerBoundFromMask(subres.aspectMask)]);
locke-lunarg296a3c92020-03-25 01:04:29 -0600345}
346
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600347const VkSubresourceLayout& ImageRangeEncoder::SubresourceLayout(const VkImageSubresource& subres) const {
348 uint32_t subres_layouts_index = subres.mipLevel * limits_.aspect_index + LowerBoundFromMask(subres.aspectMask);
349 return subres_layouts_[subres_layouts_index];
locke-lunarg296a3c92020-03-25 01:04:29 -0600350}
351
locke-lunarg3c038002020-04-30 23:08:08 -0600352inline VkImageSubresourceRange GetRemaining(const VkImageSubresourceRange& full_range, VkImageSubresourceRange subres_range) {
353 if (subres_range.levelCount == VK_REMAINING_MIP_LEVELS) {
354 subres_range.levelCount = full_range.levelCount - subres_range.baseMipLevel;
355 }
356 if (subres_range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
357 subres_range.layerCount = full_range.layerCount - subres_range.baseArrayLayer;
358 }
359 return subres_range;
360}
361
John Zulauf555e88f2020-10-21 15:16:41 -0600362static bool SubresourceRangeIsEmpty(const VkImageSubresourceRange& range) {
363 return (0 == range.aspectMask) || (0 == range.levelCount) || (0 == range.layerCount);
364}
365static bool ExtentIsEmpty(const VkExtent3D& extent) { return (0 == extent.width) || (0 == extent.height) || (0 == extent.width); }
366
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600367ImageRangeGenerator::ImageRangeGenerator(const ImageRangeEncoder& encoder, const VkImageSubresourceRange& subres_range,
locke-lunarg296a3c92020-03-25 01:04:29 -0600368 const VkOffset3D& offset, const VkExtent3D& extent)
locke-lunarg3c038002020-04-30 23:08:08 -0600369 : encoder_(&encoder), subres_range_(GetRemaining(encoder.FullRange(), subres_range)), offset_(offset), extent_(extent) {
370 assert(IsValid(*encoder_, subres_range_));
John Zulauf555e88f2020-10-21 15:16:41 -0600371 if (SubresourceRangeIsEmpty(subres_range) || ExtentIsEmpty(extent)) {
372 // Empty range forces empty position -- no operations other than deref for empty check are valid
373 pos_ = {0, 0};
374 return;
375 }
376
locke-lunarg296a3c92020-03-25 01:04:29 -0600377 mip_level_index_ = 0;
locke-lunarg3c038002020-04-30 23:08:08 -0600378 aspect_index_ = encoder_->LowerBoundFromMask(subres_range_.aspectMask);
locke-lunargc93c4f02020-04-17 01:46:35 -0600379 if ((offset_.z + extent_.depth) == 1) {
locke-lunarg3c038002020-04-30 23:08:08 -0600380 range_arraylayer_base_ = subres_range_.baseArrayLayer;
locke-lunargc93c4f02020-04-17 01:46:35 -0600381 range_layer_count_ = subres_range_.layerCount;
382 } else {
383 range_arraylayer_base_ = offset_.z;
384 range_layer_count_ = extent_.depth;
385 }
locke-lunarg296a3c92020-03-25 01:04:29 -0600386 SetPos();
387}
388
389void ImageRangeGenerator::SetPos() {
locke-lunargc93c4f02020-04-17 01:46:35 -0600390 VkImageSubresource subres = {static_cast<VkImageAspectFlags>(encoder_->AspectBit(aspect_index_)),
locke-lunarg45514ae2020-06-22 16:11:02 -0600391 subres_range_.baseMipLevel + mip_level_index_, subres_range_.baseArrayLayer};
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600392 subres_layout_ = &(encoder_->SubresourceLayout(subres));
locke-lunarg20485372020-07-16 01:58:46 -0600393 const VkExtent3D& subres_extent = encoder_->SubresourceExtent(subres.mipLevel, aspect_index_);
locke-lunargc93c4f02020-04-17 01:46:35 -0600394 Subresource limits = encoder_->Limits();
395
locke-lunarge6def482020-06-30 10:31:43 -0600396 offset_y_count_ = static_cast<int32_t>((extent_.height > subres_extent.height) ? subres_extent.height : extent_.height);
locke-lunargc93c4f02020-04-17 01:46:35 -0600397 layer_count_ = range_layer_count_;
398 mip_count_ = subres_range_.levelCount;
399 aspect_count_ = limits.aspect_index;
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600400 pos_.begin = encoder_->Encode(subres, subres_range_.baseArrayLayer, offset_);
locke-lunargc93c4f02020-04-17 01:46:35 -0600401 pos_.end = pos_.begin;
402
locke-lunarge6def482020-06-30 10:31:43 -0600403 if (offset_.x == 0 && extent_.width >= subres_extent.width) {
404 offset_y_count_ = 1;
405 if (offset_.y == 0 && extent_.height >= subres_extent.height) {
406 layer_count_ = 1;
locke-lunargc93c4f02020-04-17 01:46:35 -0600407 if (range_arraylayer_base_ == 0 && range_layer_count_ == limits.arrayLayer) {
locke-lunarg45514ae2020-06-22 16:11:02 -0600408 mip_count_ = 1;
locke-lunargc93c4f02020-04-17 01:46:35 -0600409 if (subres_range_.baseMipLevel == 0 && subres_range_.levelCount == limits.mipLevel) {
locke-lunargc93c4f02020-04-17 01:46:35 -0600410 for (uint32_t aspect_index = aspect_index_; aspect_index < aspect_count_;) {
411 subres.aspectMask = static_cast<VkImageAspectFlags>(encoder_->AspectBit(aspect_index));
412 for (uint32_t mip_index = 0; mip_index < limits.mipLevel; ++mip_index) {
413 subres.mipLevel = mip_index;
414 const VkSubresourceLayout& subres_layout = encoder_->SubresourceLayout(subres);
415 pos_.end += subres_layout.size;
416 }
417 aspect_index = encoder_->LowerBoundFromMask(subres_range_.aspectMask, aspect_index + 1);
418 }
419 aspect_count_ = 1;
420 } else {
421 for (uint32_t mip_index = mip_level_index_; mip_index < subres_range_.levelCount; ++mip_index) {
422 const VkSubresourceLayout& subres_layout = encoder_->SubresourceLayout(subres);
423 pos_.end += subres_layout.size;
424 subres.mipLevel++;
425 }
426 }
427 } else {
428 pos_.end += subres_layout_->arrayPitch * range_layer_count_;
429 }
430 } else {
431 pos_.end += (subres_layout_->rowPitch * offset_y_count_);
432 }
433 } else {
locke-lunarg12c96872020-07-27 12:42:02 -0600434 pos_.end += static_cast<IndexType>(floor(encoder_->TexelSize(aspect_index_) *
435 ((extent_.width > subres_extent.width) ? subres_extent.width : extent_.width)));
locke-lunargc93c4f02020-04-17 01:46:35 -0600436 }
locke-lunarg296a3c92020-03-25 01:04:29 -0600437 offset_layer_base_ = pos_;
438 offset_offset_y_base_ = pos_;
439 arrayLayer_index_ = 0;
440 offset_y_index_ = 0;
locke-lunarg296a3c92020-03-25 01:04:29 -0600441}
442
443ImageRangeGenerator* ImageRangeGenerator::operator++() {
444 offset_y_index_++;
445
446 if (offset_y_index_ < offset_y_count_) {
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600447 offset_offset_y_base_ += subres_layout_->rowPitch;
locke-lunarg296a3c92020-03-25 01:04:29 -0600448 pos_ = offset_offset_y_base_;
449 } else {
450 offset_y_index_ = 0;
451 arrayLayer_index_++;
452 if (arrayLayer_index_ < layer_count_) {
locke-lunarg5f7d3c62020-04-07 00:10:39 -0600453 offset_layer_base_ += subres_layout_->arrayPitch;
locke-lunarg296a3c92020-03-25 01:04:29 -0600454 offset_offset_y_base_ = offset_layer_base_;
455 pos_ = offset_layer_base_;
locke-lunarg5faaff52020-02-27 14:31:11 -0700456 } else {
locke-lunarg296a3c92020-03-25 01:04:29 -0600457 arrayLayer_index_ = 0;
458 mip_level_index_++;
locke-lunarg45514ae2020-06-22 16:11:02 -0600459 if (mip_level_index_ < mip_count_) {
locke-lunarg296a3c92020-03-25 01:04:29 -0600460 SetPos();
locke-lunarg5faaff52020-02-27 14:31:11 -0700461 } else {
locke-lunarg296a3c92020-03-25 01:04:29 -0600462 mip_level_index_ = 0;
463 aspect_index_ = encoder_->LowerBoundFromMask(subres_range_.aspectMask, aspect_index_ + 1);
464 if (aspect_index_ < aspect_count_) {
465 SetPos();
locke-lunarg5faaff52020-02-27 14:31:11 -0700466 } else {
locke-lunarg296a3c92020-03-25 01:04:29 -0600467 // End
locke-lunarg5faaff52020-02-27 14:31:11 -0700468 pos_ = {0, 0};
locke-lunarg5faaff52020-02-27 14:31:11 -0700469 }
470 }
471 }
locke-lunarg5faaff52020-02-27 14:31:11 -0700472 }
locke-lunarg296a3c92020-03-25 01:04:29 -0600473 return this;
locke-lunarg5faaff52020-02-27 14:31:11 -0700474}
475
John Zulauf11211402019-11-15 14:02:36 -0700476template <typename AspectTraits>
477class AspectParametersImpl : public AspectParameters {
478 public:
479 VkImageAspectFlags AspectMask() const override { return AspectTraits::kAspectMask; }
480 MaskIndexFunc MaskToIndexFunction() const override { return &AspectTraits::MaskIndex; }
481 uint32_t AspectCount() const override { return AspectTraits::kAspectCount; };
482 const VkImageAspectFlagBits* AspectBits() const override { return AspectTraits::AspectBits().data(); }
483};
484
485struct NullAspectTraits {
486 static constexpr uint32_t kAspectCount = 0;
487 static constexpr VkImageAspectFlags kAspectMask = 0;
488 static uint32_t MaskIndex(VkImageAspectFlags mask) { return 0; };
489 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700490 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{};
491 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700492 }
493};
494
495struct ColorAspectTraits {
496 static constexpr uint32_t kAspectCount = 1;
497 static constexpr VkImageAspectFlags kAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
498 static uint32_t MaskIndex(VkImageAspectFlags mask) { return 0; };
499 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700500 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{{VK_IMAGE_ASPECT_COLOR_BIT}};
501 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700502 }
503};
504
505struct DepthAspectTraits {
506 static constexpr uint32_t kAspectCount = 1;
507 static constexpr VkImageAspectFlags kAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
508 static uint32_t MaskIndex(VkImageAspectFlags mask) { return 0; };
509 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700510 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{{VK_IMAGE_ASPECT_DEPTH_BIT}};
511 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700512 }
513};
514
515struct StencilAspectTraits {
516 static constexpr uint32_t kAspectCount = 1;
517 static constexpr VkImageAspectFlags kAspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
518 static uint32_t MaskIndex(VkImageAspectFlags mask) { return 0; };
519 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700520 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{{VK_IMAGE_ASPECT_STENCIL_BIT}};
521 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700522 }
523};
524
525struct DepthStencilAspectTraits {
526 // VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, >> 1 -> 1 -1 -> 0
527 // VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, >> 1 -> 2 -1 = 1
528 static constexpr uint32_t kAspectCount = 2;
529 static constexpr VkImageAspectFlags kAspectMask = (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
530 static uint32_t MaskIndex(VkImageAspectFlags mask) {
531 uint32_t index = (mask >> 1) - 1;
532 assert((index == 0) || (index == 1));
533 return index;
534 };
535 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700536 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{
John Zulauf11211402019-11-15 14:02:36 -0700537 {VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_ASPECT_STENCIL_BIT}};
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700538 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700539 }
540};
541
542struct Multiplane2AspectTraits {
543 // VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, >> 4 - 1 -> 0
544 // VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, >> 4 - 1 -> 1
545 static constexpr uint32_t kAspectCount = 2;
546 static constexpr VkImageAspectFlags kAspectMask = (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
547 static uint32_t MaskIndex(VkImageAspectFlags mask) {
548 uint32_t index = (mask >> 4) - 1;
549 assert((index == 0) || (index == 1));
550 return index;
551 };
552 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700553 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{
John Zulauf11211402019-11-15 14:02:36 -0700554 {VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT}};
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700555 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700556 }
557};
558
559struct Multiplane3AspectTraits {
560 // VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, >> 4 - 1 -> 0
561 // VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, >> 4 - 1 -> 1
562 // VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, >> 4 - 1 -> 3
563 static constexpr uint32_t kAspectCount = 3;
564 static constexpr VkImageAspectFlags kAspectMask =
565 (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT);
566 static uint32_t MaskIndex(VkImageAspectFlags mask) {
567 uint32_t index = (mask >> 4) - 1;
568 index = index > 2 ? 2 : index;
569 assert((index == 0) || (index == 1) || (index == 2));
570 return index;
571 };
572 static const std::array<VkImageAspectFlagBits, kAspectCount>& AspectBits() {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700573 static std::array<VkImageAspectFlagBits, kAspectCount> k_aspect_bits{
John Zulauf11211402019-11-15 14:02:36 -0700574 {VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT}};
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700575 return k_aspect_bits;
John Zulauf11211402019-11-15 14:02:36 -0700576 }
577};
578
579// Create the encoder parameter suitable to the full range aspect mask (*must* be canonical)
580const AspectParameters* AspectParameters::Get(VkImageAspectFlags aspect_mask) {
581 // We need a persitent instance of each specialist containing only a VTABLE each
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700582 static const AspectParametersImpl<ColorAspectTraits> k_color_param;
583 static const AspectParametersImpl<DepthAspectTraits> k_depth_param;
584 static const AspectParametersImpl<StencilAspectTraits> k_stencil_param;
585 static const AspectParametersImpl<DepthStencilAspectTraits> k_depth_stencil_param;
586 static const AspectParametersImpl<Multiplane2AspectTraits> k_mutliplane2_param;
587 static const AspectParametersImpl<Multiplane3AspectTraits> k_mutliplane3_param;
588 static const AspectParametersImpl<NullAspectTraits> k_null_aspect;
John Zulauf11211402019-11-15 14:02:36 -0700589
590 const AspectParameters* param;
591 switch (aspect_mask) {
592 case ColorAspectTraits::kAspectMask:
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700593 param = &k_color_param;
John Zulauf11211402019-11-15 14:02:36 -0700594 break;
595 case DepthAspectTraits::kAspectMask:
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700596 param = &k_depth_param;
John Zulauf11211402019-11-15 14:02:36 -0700597 break;
598 case StencilAspectTraits::kAspectMask:
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700599 param = &k_stencil_param;
John Zulauf11211402019-11-15 14:02:36 -0700600 break;
601 case DepthStencilAspectTraits::kAspectMask:
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700602 param = &k_depth_stencil_param;
John Zulauf11211402019-11-15 14:02:36 -0700603 break;
604 case Multiplane2AspectTraits::kAspectMask:
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700605 param = &k_mutliplane2_param;
John Zulauf11211402019-11-15 14:02:36 -0700606 break;
607 case Multiplane3AspectTraits::kAspectMask:
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700608 param = &k_mutliplane3_param;
John Zulauf11211402019-11-15 14:02:36 -0700609 break;
610 default:
611 assert(false);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700612 param = &k_null_aspect;
John Zulauf11211402019-11-15 14:02:36 -0700613 }
614 return param;
615}
616
617}; // namespace subresource_adapter