blob: e6c8cd723523aad82a83fb71a52d47c79e2b6baf [file] [log] [blame]
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08001/* Copyright (c) 2015-2021 The Khronos Group Inc.
2 * Copyright (c) 2015-2021 Valve Corporation
3 * Copyright (c) 2015-2021 LunarG, Inc.
4 * Copyright (C) 2015-2021 Google Inc.
Tony-LunarG5a066372021-01-21 10:31:34 -07005 * Modifications Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
Mark Lobodzinskid42e4d22017-01-17 14:14:22 -07006 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * Author: Mark Lobodzinski <mark@lunarg.com>
Dave Houlton4eaaf3a2017-03-14 11:31:20 -060020 * Author: Dave Houlton <daveh@lunarg.com>
Shannon McPherson3ea65132018-12-05 10:37:39 -070021 * Shannon McPherson <shannon@lunarg.com>
Tobias Hector6663c9b2020-11-05 10:18:02 +000022 * Author: Tobias Hector <tobias.hector@amd.com>
Mark Lobodzinskid42e4d22017-01-17 14:14:22 -070023 */
24
Dave Houlton0d4ad6f2018-09-05 14:53:34 -060025#include <cmath>
26#include <set>
Mark Lobodzinski90224de2017-01-26 15:23:11 -070027#include <sstream>
Petr Kraus4d718682017-05-18 03:38:41 +020028#include <string>
Mark Lobodzinski90224de2017-01-26 15:23:11 -070029
30#include "vk_enum_string_helper.h"
Petr Kraus5a01b472019-08-10 01:40:28 +020031#include "vk_format_utils.h"
Mark Lobodzinski90224de2017-01-26 15:23:11 -070032#include "vk_layer_data.h"
33#include "vk_layer_utils.h"
34#include "vk_layer_logging.h"
Dave Houltonbd2e2622018-04-10 16:41:14 -060035#include "vk_typemap_helper.h"
Mark Lobodzinski90224de2017-01-26 15:23:11 -070036
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -070037#include "chassis.h"
Mark Lobodzinski76d76662019-02-14 14:38:21 -070038#include "core_validation.h"
39#include "shader_validation.h"
40#include "descriptor_sets.h"
Mark Lobodzinskid42e4d22017-01-17 14:14:22 -070041#include "buffer_validation.h"
Mark Lobodzinski42fe5f72017-01-11 11:36:16 -070042
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070043// All VUID from copy_bufferimage_to_imagebuffer_common.txt
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070044static const char *GetBufferImageCopyCommandVUID(std::string id, bool image_to_buffer, bool copy2) {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070045 // clang-format off
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070046 static const std::map<std::string, std::array<const char *, 4>> copy_imagebuffer_vuid = {
47 {"00193", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070048 "VUID-vkCmdCopyBufferToImage-bufferOffset-00193", // !copy2 & !image_to_buffer
49 "VUID-vkCmdCopyImageToBuffer-bufferOffset-00193", // !copy2 & image_to_buffer
50 "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-00193", // copy2 & !image_to_buffer
51 "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-00193", // copy2 & image_to_buffer
52 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070053 {"01558", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070054 "VUID-vkCmdCopyBufferToImage-bufferOffset-01558",
55 "VUID-vkCmdCopyImageToBuffer-bufferOffset-01558",
56 "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-01558",
57 "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-01558",
58 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070059 {"01559", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070060 "VUID-vkCmdCopyBufferToImage-bufferOffset-01559",
61 "VUID-vkCmdCopyImageToBuffer-bufferOffset-01559",
62 "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-01559",
63 "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-01559",
64 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070065 {"00197", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070066 "VUID-vkCmdCopyBufferToImage-imageOffset-00197",
67 "VUID-vkCmdCopyImageToBuffer-imageOffset-00197",
68 "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-00197",
69 "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00197",
70 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070071 {"00198", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070072 "VUID-vkCmdCopyBufferToImage-imageOffset-00198",
73 "VUID-vkCmdCopyImageToBuffer-imageOffset-00198",
74 "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-00198",
75 "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00198",
76 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070077 {"00199", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070078 "VUID-vkCmdCopyBufferToImage-srcImage-00199",
79 "VUID-vkCmdCopyImageToBuffer-srcImage-00199",
80 "VUID-VkCopyBufferToImageInfo2KHR-srcImage-00199",
81 "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00199",
82 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070083 {"00200", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070084 "VUID-vkCmdCopyBufferToImage-imageOffset-00200",
85 "VUID-vkCmdCopyImageToBuffer-imageOffset-00200",
86 "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-00200",
87 "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00200",
88 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070089 {"00201", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070090 "VUID-vkCmdCopyBufferToImage-srcImage-00201",
91 "VUID-vkCmdCopyImageToBuffer-srcImage-00201",
92 "VUID-VkCopyBufferToImageInfo2KHR-srcImage-00201",
93 "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00201",
94 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -070095 {"00203", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -070096 "VUID-vkCmdCopyBufferToImage-bufferRowLength-00203",
97 "VUID-vkCmdCopyImageToBuffer-bufferRowLength-00203",
98 "VUID-VkCopyBufferToImageInfo2KHR-bufferRowLength-00203",
99 "VUID-VkCopyImageToBufferInfo2KHR-bufferRowLength-00203",
100 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700101 {"00204", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700102 "VUID-vkCmdCopyBufferToImage-bufferImageHeight-00204",
103 "VUID-vkCmdCopyImageToBuffer-bufferImageHeight-00204",
104 "VUID-VkCopyBufferToImageInfo2KHR-bufferImageHeight-00204",
105 "VUID-VkCopyImageToBufferInfo2KHR-bufferImageHeight-00204",
106 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700107 {"00205", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700108 "VUID-vkCmdCopyBufferToImage-imageOffset-00205",
109 "VUID-vkCmdCopyImageToBuffer-imageOffset-00205",
110 "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-00205",
111 "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00205",
112 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700113 {"00206", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700114 "VUID-vkCmdCopyBufferToImage-bufferOffset-00206",
115 "VUID-vkCmdCopyImageToBuffer-bufferOffset-00206",
116 "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-00206",
117 "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-00206",
118 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700119 {"00207", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700120 "VUID-vkCmdCopyBufferToImage-imageExtent-00207",
121 "VUID-vkCmdCopyImageToBuffer-imageExtent-00207",
122 "VUID-VkCopyBufferToImageInfo2KHR-imageExtent-00207",
123 "VUID-VkCopyImageToBufferInfo2KHR-imageExtent-00207",
124 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700125 {"00208", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700126 "VUID-vkCmdCopyBufferToImage-imageExtent-00208",
127 "VUID-vkCmdCopyImageToBuffer-imageExtent-00208",
128 "VUID-VkCopyBufferToImageInfo2KHR-imageExtent-00208",
129 "VUID-VkCopyImageToBufferInfo2KHR-imageExtent-00208",
130 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700131 {"00209", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700132 "VUID-vkCmdCopyBufferToImage-imageExtent-00209",
133 "VUID-vkCmdCopyImageToBuffer-imageExtent-00209",
134 "VUID-VkCopyBufferToImageInfo2KHR-imageExtent-00209",
135 "VUID-VkCopyImageToBufferInfo2KHR-imageExtent-00209",
136 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700137 {"00211", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700138 "VUID-vkCmdCopyBufferToImage-aspectMask-00211",
139 "VUID-vkCmdCopyImageToBuffer-aspectMask-00211",
140 "VUID-VkCopyBufferToImageInfo2KHR-aspectMask-00211",
141 "VUID-VkCopyImageToBufferInfo2KHR-aspectMask-00211",
142 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700143 {"01560", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700144 "VUID-vkCmdCopyBufferToImage-aspectMask-01560",
145 "VUID-vkCmdCopyImageToBuffer-aspectMask-01560",
146 "VUID-VkCopyBufferToImageInfo2KHR-aspectMask-01560",
147 "VUID-VkCopyImageToBufferInfo2KHR-aspectMask-01560",
148 }},
sfricke-samsung2e5b16c2020-10-31 22:14:15 -0700149 {"00213", {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700150 "VUID-vkCmdCopyBufferToImage-baseArrayLayer-00213",
151 "VUID-vkCmdCopyImageToBuffer-baseArrayLayer-00213",
152 "VUID-VkCopyBufferToImageInfo2KHR-baseArrayLayer-00213",
153 "VUID-VkCopyImageToBufferInfo2KHR-baseArrayLayer-00213",
sfricke-samsung8feecc12021-01-23 03:28:38 -0800154 }},
155 {"04052", {
156 "VUID-vkCmdCopyBufferToImage-commandBuffer-04052",
157 "VUID-vkCmdCopyImageToBuffer-commandBuffer-04052",
158 "VUID-VkCopyBufferToImageInfo2KHR-commandBuffer-04052",
159 "VUID-VkCopyImageToBufferInfo2KHR-commandBuffer-04052",
160 }},
161 {"04053", {
162 "VUID-vkCmdCopyBufferToImage-srcImage-04053",
163 "VUID-vkCmdCopyImageToBuffer-srcImage-04053",
164 "VUID-VkCopyBufferToImageInfo2KHR-srcImage-04053",
165 "VUID-VkCopyImageToBufferInfo2KHR-srcImage-04053",
sfricke-samsung88ac6fe2020-10-24 10:00:13 -0700166 }}
167 };
168 // clang-format on
169
170 uint8_t index = 0;
171 index |= (image_to_buffer) ? 0x1 : 0;
172 index |= (copy2) ? 0x2 : 0;
173 return copy_imagebuffer_vuid.at(id).at(index);
174}
175
David McFarland2853f2f2020-11-30 15:50:39 -0400176// Transfer VkImageSubresourceRange into VkImageSubresourceLayers struct
177static VkImageSubresourceLayers LayersFromRange(const VkImageSubresourceRange &subresource_range) {
178 VkImageSubresourceLayers subresource_layers;
179 subresource_layers.aspectMask = subresource_range.aspectMask;
180 subresource_layers.baseArrayLayer = subresource_range.baseArrayLayer;
181 subresource_layers.layerCount = subresource_range.layerCount;
182 subresource_layers.mipLevel = subresource_range.baseMipLevel;
183 return subresource_layers;
184}
185
John Zulauff660ad62019-03-23 07:16:05 -0600186// Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
187static VkImageSubresourceRange RangeFromLayers(const VkImageSubresourceLayers &subresource_layers) {
188 VkImageSubresourceRange subresource_range;
189 subresource_range.aspectMask = subresource_layers.aspectMask;
190 subresource_range.baseArrayLayer = subresource_layers.baseArrayLayer;
191 subresource_range.layerCount = subresource_layers.layerCount;
192 subresource_range.baseMipLevel = subresource_layers.mipLevel;
193 subresource_range.levelCount = 1;
194 return subresource_range;
195}
196
John Zulaufb58415b2019-12-09 15:02:32 -0700197static VkImageSubresourceRange MakeImageFullRange(const VkImageCreateInfo &create_info) {
198 const auto format = create_info.format;
199 VkImageSubresourceRange init_range{0, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
Benjamin Thautd0bc2a92020-08-25 17:09:09 +0200200
201#ifdef VK_USE_PLATFORM_ANDROID_KHR
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700202 const VkExternalFormatANDROID *external_format_android = LvlFindInChain<VkExternalFormatANDROID>(&create_info);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700203 bool is_external_format_conversion = (external_format_android != nullptr && external_format_android->externalFormat != 0);
Benjamin Thautd0bc2a92020-08-25 17:09:09 +0200204#else
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700205 bool is_external_format_conversion = false;
Benjamin Thautd0bc2a92020-08-25 17:09:09 +0200206#endif
207
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700208 if (FormatIsColor(format) || FormatIsMultiplane(format) || is_external_format_conversion) {
John Zulaufb58415b2019-12-09 15:02:32 -0700209 init_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // Normalization will expand this for multiplane
210 } else {
211 init_range.aspectMask =
212 (FormatHasDepth(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (FormatHasStencil(format) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
213 }
214 return NormalizeSubresourceRange(create_info, init_range);
215}
216
locke-lunarg296a3c92020-03-25 01:04:29 -0600217IMAGE_STATE::IMAGE_STATE(VkDevice dev, VkImage img, const VkImageCreateInfo *pCreateInfo)
John Zulauff660ad62019-03-23 07:16:05 -0600218 : image(img),
Tony-LunarGf3278f52020-01-31 09:58:26 -0700219 safe_create_info(pCreateInfo),
220 createInfo(*safe_create_info.ptr()),
John Zulauff660ad62019-03-23 07:16:05 -0600221 valid(false),
222 acquired(false),
223 shared_presentable(false),
224 layout_locked(false),
225 get_sparse_reqs_called(false),
226 sparse_metadata_required(false),
227 sparse_metadata_bound(false),
John Zulauff660ad62019-03-23 07:16:05 -0600228 has_ahb_format(false),
Tony-LunarGe64e4fe2020-02-17 16:21:55 -0700229 is_swapchain_image(false),
John Zulauff660ad62019-03-23 07:16:05 -0600230 ahb_format(0),
John Zulaufb58415b2019-12-09 15:02:32 -0700231 full_range{MakeImageFullRange(createInfo)},
unknown09edc722019-06-21 15:49:38 -0600232 create_from_swapchain(VK_NULL_HANDLE),
233 bind_swapchain(VK_NULL_HANDLE),
unknown08c57af2019-06-21 16:33:35 -0600234 bind_swapchain_imageIndex(0),
John Zulaufb58415b2019-12-09 15:02:32 -0700235 range_encoder(full_range),
sfricke-samsung71bc6572020-04-29 15:49:43 -0700236 disjoint(false),
237 plane0_memory_requirements_checked(false),
238 plane1_memory_requirements_checked(false),
239 plane2_memory_requirements_checked(false),
locke-lunarg296a3c92020-03-25 01:04:29 -0600240 subresource_encoder(full_range),
locke-lunargae26eac2020-04-16 15:29:05 -0600241 fragment_encoder(nullptr),
locke-lunarg296a3c92020-03-25 01:04:29 -0600242 store_device_as_workaround(dev), // TODO REMOVE WHEN encoder can be const
unknown08c57af2019-06-21 16:33:35 -0600243 sparse_requirements{} {
John Zulauff660ad62019-03-23 07:16:05 -0600244 if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700245 uint32_t *queue_family_indices = new uint32_t[createInfo.queueFamilyIndexCount];
John Zulauff660ad62019-03-23 07:16:05 -0600246 for (uint32_t i = 0; i < createInfo.queueFamilyIndexCount; i++) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700247 queue_family_indices[i] = pCreateInfo->pQueueFamilyIndices[i];
John Zulauff660ad62019-03-23 07:16:05 -0600248 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700249 createInfo.pQueueFamilyIndices = queue_family_indices;
John Zulauff660ad62019-03-23 07:16:05 -0600250 }
251
252 if (createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) {
253 sparse = true;
254 }
Locked8af3732019-05-10 09:47:56 -0600255
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700256 auto *external_memory_info = LvlFindInChain<VkExternalMemoryImageCreateInfo>(pCreateInfo->pNext);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700257 if (external_memory_info) {
258 external_memory_handle = external_memory_info->handleTypes;
sfricke-samsunge2441192019-11-06 14:07:57 -0800259 }
John Zulauff660ad62019-03-23 07:16:05 -0600260}
261
unknown2c877272019-07-11 12:56:50 -0600262bool IMAGE_STATE::IsCreateInfoEqual(const VkImageCreateInfo &other_createInfo) const {
263 bool is_equal = (createInfo.sType == other_createInfo.sType) && (createInfo.flags == other_createInfo.flags);
264 is_equal = is_equal && IsImageTypeEqual(other_createInfo) && IsFormatEqual(other_createInfo);
265 is_equal = is_equal && IsMipLevelsEqual(other_createInfo) && IsArrayLayersEqual(other_createInfo);
266 is_equal = is_equal && IsUsageEqual(other_createInfo) && IsInitialLayoutEqual(other_createInfo);
267 is_equal = is_equal && IsExtentEqual(other_createInfo) && IsTilingEqual(other_createInfo);
268 is_equal = is_equal && IsSamplesEqual(other_createInfo) && IsSharingModeEqual(other_createInfo);
Tony-LunarG28b88132020-05-05 11:25:41 -0600269 return is_equal &&
270 ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) ? IsQueueFamilyIndicesEqual(other_createInfo) : true);
unknown2c877272019-07-11 12:56:50 -0600271}
272
Jeff Bolz82f854d2019-09-17 14:56:47 -0500273// Check image compatibility rules for VK_NV_dedicated_allocation_image_aliasing
274bool IMAGE_STATE::IsCreateInfoDedicatedAllocationImageAliasingCompatible(const VkImageCreateInfo &other_createInfo) const {
275 bool is_compatible = (createInfo.sType == other_createInfo.sType) && (createInfo.flags == other_createInfo.flags);
276 is_compatible = is_compatible && IsImageTypeEqual(other_createInfo) && IsFormatEqual(other_createInfo);
277 is_compatible = is_compatible && IsMipLevelsEqual(other_createInfo);
278 is_compatible = is_compatible && IsUsageEqual(other_createInfo) && IsInitialLayoutEqual(other_createInfo);
279 is_compatible = is_compatible && IsSamplesEqual(other_createInfo) && IsSharingModeEqual(other_createInfo);
Tony-LunarG28b88132020-05-05 11:25:41 -0600280 is_compatible = is_compatible &&
281 ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) ? IsQueueFamilyIndicesEqual(other_createInfo) : true);
282 is_compatible = is_compatible && IsTilingEqual(other_createInfo);
Jeff Bolz82f854d2019-09-17 14:56:47 -0500283
284 is_compatible = is_compatible && createInfo.extent.width <= other_createInfo.extent.width &&
285 createInfo.extent.height <= other_createInfo.extent.height &&
286 createInfo.extent.depth <= other_createInfo.extent.depth &&
287 createInfo.arrayLayers <= other_createInfo.arrayLayers;
288 return is_compatible;
289}
290
unknown2c877272019-07-11 12:56:50 -0600291bool IMAGE_STATE::IsCompatibleAliasing(IMAGE_STATE *other_image_state) {
Tony-LunarGe64e4fe2020-02-17 16:21:55 -0700292 if (!is_swapchain_image && !other_image_state->is_swapchain_image &&
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700293 !(createInfo.flags & other_image_state->createInfo.flags & VK_IMAGE_CREATE_ALIAS_BIT)) {
Tony-LunarGe64e4fe2020-02-17 16:21:55 -0700294 return false;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700295 }
locke-lunarg5f59e782019-12-19 10:32:23 -0700296 if ((create_from_swapchain == VK_NULL_HANDLE) && binding.mem_state &&
297 (binding.mem_state == other_image_state->binding.mem_state) && (binding.offset == other_image_state->binding.offset) &&
unknown2c877272019-07-11 12:56:50 -0600298 IsCreateInfoEqual(other_image_state->createInfo)) {
299 return true;
300 }
unknowne1661522019-07-11 13:04:18 -0600301 if ((bind_swapchain == other_image_state->bind_swapchain) && (bind_swapchain != VK_NULL_HANDLE)) {
302 return true;
303 }
unknown2c877272019-07-11 12:56:50 -0600304 return false;
305}
306
Jeff Bolze7fc67b2019-10-04 12:29:31 -0500307IMAGE_VIEW_STATE::IMAGE_VIEW_STATE(const std::shared_ptr<IMAGE_STATE> &im, VkImageView iv, const VkImageViewCreateInfo *ci)
308 : image_view(iv),
309 create_info(*ci),
John Zulaufb58415b2019-12-09 15:02:32 -0700310 normalized_subresource_range(NormalizeSubresourceRange(*im, ci->subresourceRange)),
locke-lunarg296a3c92020-03-25 01:04:29 -0600311 range_generator(im->subresource_encoder, normalized_subresource_range),
Jeff Bolze7fc67b2019-10-04 12:29:31 -0500312 samplerConversion(VK_NULL_HANDLE),
313 image_state(im) {
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700314 auto *conversion_info = LvlFindInChain<VkSamplerYcbcrConversionInfo>(create_info.pNext);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700315 if (conversion_info) samplerConversion = conversion_info->conversion;
John Zulauff660ad62019-03-23 07:16:05 -0600316 if (image_state) {
317 // A light normalization of the createInfo range
318 auto &sub_res_range = create_info.subresourceRange;
319 sub_res_range.levelCount = ResolveRemainingLevels(&sub_res_range, image_state->createInfo.mipLevels);
320 sub_res_range.layerCount = ResolveRemainingLayers(&sub_res_range, image_state->createInfo.arrayLayers);
321
322 // Cache a full normalization (for "full image/whole image" comparisons)
John Zulaufb58415b2019-12-09 15:02:32 -0700323 // normalized_subresource_range = NormalizeSubresourceRange(*image_state, ci->subresourceRange);
Jeff Bolz6cede832019-08-09 23:30:39 -0500324 samples = image_state->createInfo.samples;
Benjamin Thautd0bc2a92020-08-25 17:09:09 +0200325
326 if (image_state->has_ahb_format) {
327 // When the image has a external format the views format must be VK_FORMAT_UNDEFINED and it is required to use a sampler
328 // Ycbcr conversion. Thus we can't extract any meaningful information from the format parameter. As a Sampler Ycbcr
329 // conversion must be used the shader type is always float.
330 descriptor_format_bits = DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT;
331 } else {
332 descriptor_format_bits = DescriptorRequirementsBitsFromFormat(create_info.format);
333 }
John Zulauff660ad62019-03-23 07:16:05 -0600334 }
335}
336
Jeremy Gebben50e0b412021-02-18 10:39:41 -0700337static VkImageLayout NormalizeImageLayout(VkImageLayout layout, VkImageLayout non_normal, VkImageLayout normal) {
338 return (layout == non_normal) ? normal : layout;
339}
340
341static VkImageLayout NormalizeDepthImageLayout(VkImageLayout layout) {
342 return NormalizeImageLayout(layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
343 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL);
344}
345
346static VkImageLayout NormalizeStencilImageLayout(VkImageLayout layout) {
347 return NormalizeImageLayout(layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
348 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL);
349}
350
351static bool ImageLayoutMatches(const VkImageAspectFlags aspect_mask, VkImageLayout a, VkImageLayout b) {
352 bool matches = (a == b);
353 if (!matches) {
354 // Relaxed rules when referencing *only* the depth or stencil aspects
355 if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
356 matches = NormalizeDepthImageLayout(a) == NormalizeDepthImageLayout(b);
357 } else if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
358 matches = NormalizeStencilImageLayout(a) == NormalizeStencilImageLayout(b);
359 }
360 }
361 return matches;
362}
363
364// Utility type for ForRange callbacks
365struct LayoutUseCheckAndMessage {
366 const static VkImageAspectFlags kDepthOrStencil = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
367 const ImageSubresourceLayoutMap *layout_map;
368 const VkImageAspectFlags aspect_mask;
369 const char *message;
370 VkImageLayout layout;
371
372 LayoutUseCheckAndMessage() = delete;
373 LayoutUseCheckAndMessage(const ImageSubresourceLayoutMap *layout_map_, const VkImageAspectFlags aspect_mask_ = 0)
374 : layout_map(layout_map_), aspect_mask{aspect_mask_}, message(nullptr), layout(kInvalidLayout) {}
375 bool Check(const VkImageSubresource &subres, VkImageLayout check, VkImageLayout current_layout, VkImageLayout initial_layout) {
376 message = nullptr;
377 layout = kInvalidLayout; // Success status
378 if (current_layout != kInvalidLayout && !ImageLayoutMatches(aspect_mask, check, current_layout)) {
379 message = "previous known";
380 layout = current_layout;
381 } else if ((initial_layout != kInvalidLayout) && !ImageLayoutMatches(aspect_mask, check, initial_layout)) {
382 // To check the relaxed rule matching we need to see how the initial use was used
383 const auto initial_layout_state = layout_map->GetSubresourceInitialLayoutState(subres);
384 assert(initial_layout_state); // If we have an initial layout, we better have a state for it
385 if (!((initial_layout_state->aspect_mask & kDepthOrStencil) &&
386 ImageLayoutMatches(initial_layout_state->aspect_mask, check, initial_layout))) {
387 message = "previously used";
388 layout = initial_layout;
389 }
390 }
391 return layout == kInvalidLayout;
392 }
393};
394
locke-lunarg540b2252020-08-03 13:23:36 -0600395bool IMAGE_VIEW_STATE::OverlapSubresource(const IMAGE_VIEW_STATE &compare_view) const {
locke-lunarg540b2252020-08-03 13:23:36 -0600396 if (image_view == compare_view.image_view) {
397 return true;
398 }
locke-lunargdc287022020-08-21 12:03:57 -0600399 if (image_state->image != compare_view.image_state->image) {
400 return false;
401 }
locke-lunarg540b2252020-08-03 13:23:36 -0600402 if (normalized_subresource_range.aspectMask != compare_view.normalized_subresource_range.aspectMask) {
403 return false;
404 }
405
406 // compare if overlap mip level
locke-lunarg540b2252020-08-03 13:23:36 -0600407 if ((normalized_subresource_range.baseMipLevel < compare_view.normalized_subresource_range.baseMipLevel) &&
locke-lunargdc287022020-08-21 12:03:57 -0600408 ((normalized_subresource_range.baseMipLevel + normalized_subresource_range.levelCount) <=
locke-lunarg540b2252020-08-03 13:23:36 -0600409 compare_view.normalized_subresource_range.baseMipLevel)) {
locke-lunargdc287022020-08-21 12:03:57 -0600410 return false;
locke-lunarg540b2252020-08-03 13:23:36 -0600411 }
412
413 if ((normalized_subresource_range.baseMipLevel > compare_view.normalized_subresource_range.baseMipLevel) &&
locke-lunargdc287022020-08-21 12:03:57 -0600414 (normalized_subresource_range.baseMipLevel >=
locke-lunarg540b2252020-08-03 13:23:36 -0600415 (compare_view.normalized_subresource_range.baseMipLevel + compare_view.normalized_subresource_range.levelCount))) {
locke-lunargdc287022020-08-21 12:03:57 -0600416 return false;
locke-lunarg540b2252020-08-03 13:23:36 -0600417 }
418
419 // compare if overlap array layer
locke-lunarg540b2252020-08-03 13:23:36 -0600420 if ((normalized_subresource_range.baseArrayLayer < compare_view.normalized_subresource_range.baseArrayLayer) &&
locke-lunargdc287022020-08-21 12:03:57 -0600421 ((normalized_subresource_range.baseArrayLayer + normalized_subresource_range.layerCount) <=
locke-lunarg540b2252020-08-03 13:23:36 -0600422 compare_view.normalized_subresource_range.baseArrayLayer)) {
locke-lunargdc287022020-08-21 12:03:57 -0600423 return false;
locke-lunarg540b2252020-08-03 13:23:36 -0600424 }
425
426 if ((normalized_subresource_range.baseArrayLayer > compare_view.normalized_subresource_range.baseArrayLayer) &&
locke-lunargdc287022020-08-21 12:03:57 -0600427 (normalized_subresource_range.baseArrayLayer >=
locke-lunarg540b2252020-08-03 13:23:36 -0600428 (compare_view.normalized_subresource_range.baseArrayLayer + compare_view.normalized_subresource_range.layerCount))) {
locke-lunargdc287022020-08-21 12:03:57 -0600429 return false;
locke-lunarg540b2252020-08-03 13:23:36 -0600430 }
locke-lunargdc287022020-08-21 12:03:57 -0600431 return true;
locke-lunarg540b2252020-08-03 13:23:36 -0600432}
433
Dave Houltond9611312018-11-19 17:03:36 -0700434uint32_t FullMipChainLevels(uint32_t height, uint32_t width, uint32_t depth) {
435 // uint cast applies floor()
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700436 return 1u + static_cast<uint32_t>(log2(std::max({height, width, depth})));
Dave Houltond9611312018-11-19 17:03:36 -0700437}
438
439uint32_t FullMipChainLevels(VkExtent3D extent) { return FullMipChainLevels(extent.height, extent.width, extent.depth); }
440
441uint32_t FullMipChainLevels(VkExtent2D extent) { return FullMipChainLevels(extent.height, extent.width); }
442
Jeff Bolz46c0ea02019-10-09 13:06:29 -0500443bool CoreChecks::FindLayouts(VkImage image, std::vector<VkImageLayout> &layouts) const {
Mark Lobodzinski8ddc23f2019-03-06 11:48:49 -0700444 auto image_state = GetImageState(image);
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700445 if (!image_state) return false;
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -0700446
John Zulauf2076e812020-01-08 14:55:54 -0700447 const auto *layout_range_map = GetLayoutRangeMap(imageLayoutMap, image);
448 if (!layout_range_map) return false;
locke-lunargf155ccf2020-02-18 11:34:15 -0700449 // TODO: FindLayouts function should mutate into a ValidatePresentableLayout with the loop wrapping the LogError
450 // from the caller. You can then use decode to add the subresource of the range::begin to the error message.
451
John Zulauf2076e812020-01-08 14:55:54 -0700452 // TODO: what is this test and what is it supposed to do?! -- the logic doesn't match the comment below?!
453
454 // TODO: Make this robust for >1 aspect mask. Now it will just say ignore potential errors in this case.
455 if (layout_range_map->size() >= (image_state->createInfo.arrayLayers * image_state->createInfo.mipLevels + 1)) {
Tony Barbourdf013b92017-01-25 12:53:48 -0700456 return false;
457 }
locke-lunargcba7d5f2019-12-30 16:59:11 -0700458
John Zulauf2076e812020-01-08 14:55:54 -0700459 for (auto entry : *layout_range_map) {
460 layouts.push_back(entry.second);
Tony Barbourdf013b92017-01-25 12:53:48 -0700461 }
462 return true;
463}
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700464
Tobin Ehlise35b66a2017-03-15 12:18:31 -0600465// Set image layout for given VkImageSubresourceRange struct
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600466void CoreChecks::SetImageLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &image_state,
John Zulauff660ad62019-03-23 07:16:05 -0600467 const VkImageSubresourceRange &image_subresource_range, VkImageLayout layout,
468 VkImageLayout expected_layout) {
469 auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state);
470 assert(subresource_map); // the non-const getter must return a valid pointer
John Zulauf4ec24ec2019-05-02 17:22:59 -0600471 if (subresource_map->SetSubresourceRangeLayout(*cb_node, image_subresource_range, layout, expected_layout)) {
John Zulauff660ad62019-03-23 07:16:05 -0600472 cb_node->image_layout_change_count++; // Change the version of this data to force revalidation
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700473 }
Tony-LunarG330cf4c2020-03-04 16:29:03 -0700474 for (const auto &image : image_state.aliasing_images) {
475 auto alias_state = GetImageState(image);
476 // The map state of the aliases should all be in sync, so no need to check the return value
477 subresource_map = GetImageSubresourceLayoutMap(cb_node, *alias_state);
478 assert(subresource_map);
479 subresource_map->SetSubresourceRangeLayout(*cb_node, image_subresource_range, layout, expected_layout);
480 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700481}
John Zulauff660ad62019-03-23 07:16:05 -0600482
483// Set the initial image layout for all slices of an image view
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600484void CoreChecks::SetImageViewInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout) {
Mark Lobodzinski90eea5b2020-05-15 12:54:00 -0600485 if (disabled[image_layout_validation]) {
Jeff Bolz3e333222019-08-10 23:00:38 -0500486 return;
487 }
Jeff Bolzfaffeb32019-10-04 12:47:16 -0500488 IMAGE_STATE *image_state = view_state.image_state.get();
489 auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, *image_state);
John Zulaufb58415b2019-12-09 15:02:32 -0700490 subresource_map->SetSubresourceRangeInitialLayout(*cb_node, layout, view_state);
Tony-LunarG330cf4c2020-03-04 16:29:03 -0700491 for (const auto &image : image_state->aliasing_images) {
492 image_state = GetImageState(image);
493 subresource_map = GetImageSubresourceLayoutMap(cb_node, *image_state);
494 subresource_map->SetSubresourceRangeInitialLayout(*cb_node, layout, view_state);
495 }
John Zulauff660ad62019-03-23 07:16:05 -0600496}
497
498// Set the initial image layout for a passed non-normalized subresource range
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600499void CoreChecks::SetImageInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &image_state,
John Zulauff660ad62019-03-23 07:16:05 -0600500 const VkImageSubresourceRange &range, VkImageLayout layout) {
501 auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state);
502 assert(subresource_map);
John Zulauf4ec24ec2019-05-02 17:22:59 -0600503 subresource_map->SetSubresourceRangeInitialLayout(*cb_node, NormalizeSubresourceRange(image_state, range), layout);
Tony-LunarG330cf4c2020-03-04 16:29:03 -0700504 for (const auto &image : image_state.aliasing_images) {
505 auto alias_state = GetImageState(image);
506 subresource_map = GetImageSubresourceLayoutMap(cb_node, *alias_state);
507 assert(subresource_map);
508 subresource_map->SetSubresourceRangeInitialLayout(*cb_node, NormalizeSubresourceRange(*alias_state, range), layout);
509 }
John Zulauff660ad62019-03-23 07:16:05 -0600510}
511
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600512void CoreChecks::SetImageInitialLayout(CMD_BUFFER_STATE *cb_node, VkImage image, const VkImageSubresourceRange &range,
John Zulauff660ad62019-03-23 07:16:05 -0600513 VkImageLayout layout) {
514 const IMAGE_STATE *image_state = GetImageState(image);
515 if (!image_state) return;
516 SetImageInitialLayout(cb_node, *image_state, range, layout);
517};
518
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600519void CoreChecks::SetImageInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &image_state,
John Zulauff660ad62019-03-23 07:16:05 -0600520 const VkImageSubresourceLayers &layers, VkImageLayout layout) {
521 SetImageInitialLayout(cb_node, image_state, RangeFromLayers(layers), layout);
Tobin Ehlise35b66a2017-03-15 12:18:31 -0600522}
Dave Houltonddd65c52018-05-08 14:58:01 -0600523
Tobin Ehlise35b66a2017-03-15 12:18:31 -0600524// Set image layout for all slices of an image view
Piers Daniell4fde9b72019-11-27 16:19:46 -0700525void CoreChecks::SetImageViewLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout,
526 VkImageLayout layoutStencil) {
Jeff Bolzfaffeb32019-10-04 12:47:16 -0500527 IMAGE_STATE *image_state = view_state.image_state.get();
Tobin Ehlise35b66a2017-03-15 12:18:31 -0600528
John Zulauff660ad62019-03-23 07:16:05 -0600529 VkImageSubresourceRange sub_range = view_state.normalized_subresource_range;
Dave Houltonddd65c52018-05-08 14:58:01 -0600530 // When changing the layout of a 3D image subresource via a 2D or 2D_ARRRAY image view, all depth slices of
531 // the subresource mip level(s) are transitioned, ignoring any layers restriction in the subresource info.
John Zulauff660ad62019-03-23 07:16:05 -0600532 if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) && (view_state.create_info.viewType != VK_IMAGE_VIEW_TYPE_3D)) {
Dave Houltonddd65c52018-05-08 14:58:01 -0600533 sub_range.baseArrayLayer = 0;
534 sub_range.layerCount = image_state->createInfo.extent.depth;
535 }
536
Piers Daniell4fde9b72019-11-27 16:19:46 -0700537 if (sub_range.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) && layoutStencil != kInvalidLayout) {
538 sub_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
539 SetImageLayout(cb_node, *image_state, sub_range, layout);
540 sub_range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
541 SetImageLayout(cb_node, *image_state, sub_range, layoutStencil);
542 } else {
543 SetImageLayout(cb_node, *image_state, sub_range, layout);
544 }
John Zulauf4ccf5c02018-09-21 11:46:18 -0600545}
546
Mark Lobodzinskief4ab2e2019-03-07 13:23:36 -0700547bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version, VkImageLayout layout,
548 VkImage image, VkImageView image_view,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -0700549 VkFramebuffer framebuffer, VkRenderPass renderpass,
John Zulauf17a01bb2019-08-09 16:41:19 -0600550 uint32_t attachment_index, const char *variable_name) const {
Tobias Hectorbbb12282018-10-22 15:17:59 +0100551 bool skip = false;
Mark Lobodzinski8ddc23f2019-03-06 11:48:49 -0700552 auto image_state = GetImageState(image);
Tobias Hectorbbb12282018-10-22 15:17:59 +0100553 const char *vuid;
554 const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700555 const char *function_name = use_rp2 ? "vkCmdBeginRenderPass2()" : "vkCmdBeginRenderPass()";
Tobias Hectorbbb12282018-10-22 15:17:59 +0100556
557 if (!image_state) {
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600558 LogObjectList objlist(image);
559 objlist.add(renderpass);
560 objlist.add(framebuffer);
561 objlist.add(image_view);
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700562 skip |=
563 LogError(image, "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
564 "%s: RenderPass %s uses %s where pAttachments[%" PRIu32 "] = %s, which refers to an invalid image",
565 function_name, report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(framebuffer).c_str(),
566 attachment_index, report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100567 return skip;
568 }
569
570 auto image_usage = image_state->createInfo.usage;
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700571 const auto stencil_usage_info = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_state->createInfo.pNext);
Ricardo Garcia3f5984c2020-04-09 10:56:34 +0200572 if (stencil_usage_info) {
573 image_usage |= stencil_usage_info->stencilUsage;
574 }
Tobias Hectorbbb12282018-10-22 15:17:59 +0100575
576 // Check for layouts that mismatch image usages in the framebuffer
577 if (layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
Mike Schuchardt65847d92019-12-20 13:50:47 -0800578 vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03094" : "VUID-vkCmdBeginRenderPass-initialLayout-00895";
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600579 LogObjectList objlist(image);
580 objlist.add(renderpass);
581 objlist.add(framebuffer);
582 objlist.add(image_view);
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700583 skip |= LogError(objlist, vuid,
584 "%s: Layout/usage mismatch for attachment %u in %s"
585 " - the %s is %s but the image attached to %s via %s"
586 " was not created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT",
587 function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
588 string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
589 report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100590 }
591
592 if (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
593 !(image_usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
Mike Schuchardt65847d92019-12-20 13:50:47 -0800594 vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03097" : "VUID-vkCmdBeginRenderPass-initialLayout-00897";
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600595 LogObjectList objlist(image);
596 objlist.add(renderpass);
597 objlist.add(framebuffer);
598 objlist.add(image_view);
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700599 skip |= LogError(objlist, vuid,
600 "%s: Layout/usage mismatch for attachment %u in %s"
601 " - the %s is %s but the image attached to %s via %s"
602 " was not created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT or VK_IMAGE_USAGE_SAMPLED_BIT",
603 function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
604 string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
605 report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100606 }
607
608 if (layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
Mike Schuchardt65847d92019-12-20 13:50:47 -0800609 vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03098" : "VUID-vkCmdBeginRenderPass-initialLayout-00898";
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600610 LogObjectList objlist(image);
611 objlist.add(renderpass);
612 objlist.add(framebuffer);
613 objlist.add(image_view);
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700614 skip |= LogError(objlist, vuid,
615 "%s: Layout/usage mismatch for attachment %u in %s"
616 " - the %s is %s but the image attached to %s via %s"
617 " was not created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT",
618 function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
619 string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
620 report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100621 }
622
623 if (layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
Mike Schuchardt65847d92019-12-20 13:50:47 -0800624 vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03099" : "VUID-vkCmdBeginRenderPass-initialLayout-00899";
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600625 LogObjectList objlist(image);
626 objlist.add(renderpass);
627 objlist.add(framebuffer);
628 objlist.add(image_view);
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700629 skip |= LogError(objlist, vuid,
630 "%s: Layout/usage mismatch for attachment %u in %s"
631 " - the %s is %s but the image attached to %s via %s"
632 " was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT",
633 function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
634 string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
635 report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100636 }
637
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -0600638 if (device_extensions.vk_khr_maintenance2) {
Tobias Hectorbbb12282018-10-22 15:17:59 +0100639 if ((layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
640 layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
641 layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
642 layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
643 !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
Mike Schuchardt65847d92019-12-20 13:50:47 -0800644 vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03096" : "VUID-vkCmdBeginRenderPass-initialLayout-01758";
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600645 LogObjectList objlist(image);
646 objlist.add(renderpass);
647 objlist.add(framebuffer);
648 objlist.add(image_view);
649 skip |= LogError(objlist, vuid,
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700650 "%s: Layout/usage mismatch for attachment %u in %s"
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700651 " - the %s is %s but the image attached to %s via %s"
652 " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700653 function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700654 string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
655 report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100656 }
657 } else {
658 // The create render pass 2 extension requires maintenance 2 (the previous branch), so no vuid switch needed here.
659 if ((layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
660 layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
661 !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600662 LogObjectList objlist(image);
663 objlist.add(renderpass);
664 objlist.add(framebuffer);
665 objlist.add(image_view);
666 skip |= LogError(objlist, "VUID-vkCmdBeginRenderPass-initialLayout-00896",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700667 "%s: Layout/usage mismatch for attachment %u in %s"
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700668 " - the %s is %s but the image attached to %s via %s"
669 " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -0700670 function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700671 string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
672 report_data->FormatHandle(image_view).c_str());
Tobias Hectorbbb12282018-10-22 15:17:59 +0100673 }
674 }
675 return skip;
676}
677
John Zulauf17a01bb2019-08-09 16:41:19 -0600678bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version, const CMD_BUFFER_STATE *pCB,
Mark Lobodzinskief4ab2e2019-03-07 13:23:36 -0700679 const VkRenderPassBeginInfo *pRenderPassBegin,
John Zulauf17a01bb2019-08-09 16:41:19 -0600680 const FRAMEBUFFER_STATE *framebuffer_state) const {
Mark Lobodzinskibdc3b022017-04-24 09:11:35 -0600681 bool skip = false;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700682 auto const render_pass_info = GetRenderPassState(pRenderPassBegin->renderPass)->createInfo.ptr();
683 auto const &framebuffer_info = framebuffer_state->createInfo;
684 const VkImageView *attachments = framebuffer_info.pAttachments;
Tobias Hectorbbb12282018-10-22 15:17:59 +0100685
Mark Lobodzinski2e495882019-03-06 16:11:56 -0700686 auto render_pass = GetRenderPassState(pRenderPassBegin->renderPass)->renderPass;
Tobias Hectorbbb12282018-10-22 15:17:59 +0100687 auto framebuffer = framebuffer_state->framebuffer;
688
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700689 if (render_pass_info->attachmentCount != framebuffer_info.attachmentCount) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700690 skip |= LogError(pCB->commandBuffer, kVUID_Core_DrawState_InvalidRenderpass,
691 "You cannot start a render pass using a framebuffer with a different number of attachments.");
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700692 }
John Zulauf8e308292018-09-21 11:34:37 -0600693
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700694 const auto *attachment_info = LvlFindInChain<VkRenderPassAttachmentBeginInfo>(pRenderPassBegin->pNext);
Mike Schuchardt2df08912020-12-15 16:28:09 -0800695 if (((framebuffer_info.flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) != 0) && attachment_info != nullptr) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700696 attachments = attachment_info->pAttachments;
Tobias Hectorbbb12282018-10-22 15:17:59 +0100697 }
698
Tobias Hectorc9057422019-07-23 12:15:52 +0100699 if (attachments != nullptr) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700700 const auto *const_p_cb = static_cast<const CMD_BUFFER_STATE *>(pCB);
701 for (uint32_t i = 0; i < render_pass_info->attachmentCount; ++i) {
Tobias Hectorc9057422019-07-23 12:15:52 +0100702 auto image_view = attachments[i];
703 auto view_state = GetImageViewState(image_view);
Tobias Hectorbbb12282018-10-22 15:17:59 +0100704
Tobias Hectorc9057422019-07-23 12:15:52 +0100705 if (!view_state) {
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600706 LogObjectList objlist(pRenderPassBegin->renderPass);
707 objlist.add(framebuffer_state->framebuffer);
708 objlist.add(image_view);
709 skip |= LogError(objlist, "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700710 "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle",
711 report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i,
712 report_data->FormatHandle(image_view).c_str());
Tobias Hectorc9057422019-07-23 12:15:52 +0100713 continue;
Tobias Hectorbbb12282018-10-22 15:17:59 +0100714 }
Tobias Hectorc9057422019-07-23 12:15:52 +0100715
716 const VkImage image = view_state->create_info.image;
717 const IMAGE_STATE *image_state = GetImageState(image);
718
719 if (!image_state) {
Mark Lobodzinskiea561582020-03-16 18:13:56 -0600720 LogObjectList objlist(pRenderPassBegin->renderPass);
721 objlist.add(framebuffer_state->framebuffer);
722 objlist.add(image_view);
723 objlist.add(image);
724 skip |= LogError(objlist, "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700725 "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s references non-extant %s.",
726 report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i,
727 report_data->FormatHandle(image_view).c_str(), report_data->FormatHandle(image).c_str());
Tobias Hectorc9057422019-07-23 12:15:52 +0100728 continue;
729 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700730 auto attachment_initial_layout = render_pass_info->pAttachments[i].initialLayout;
731 auto final_layout = render_pass_info->pAttachments[i].finalLayout;
Tobias Hectorc9057422019-07-23 12:15:52 +0100732
Piers Daniell7f894f62020-01-09 16:33:48 -0700733 // Default to expecting stencil in the same layout.
734 auto attachment_stencil_initial_layout = attachment_initial_layout;
735
736 // If a separate layout is specified, look for that.
737 const auto *attachment_description_stencil_layout =
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700738 LvlFindInChain<VkAttachmentDescriptionStencilLayout>(render_pass_info->pAttachments[i].pNext);
Piers Daniell7f894f62020-01-09 16:33:48 -0700739 if (attachment_description_stencil_layout) {
740 attachment_stencil_initial_layout = attachment_description_stencil_layout->stencilInitialLayout;
741 }
742
Tobias Hectorc9057422019-07-23 12:15:52 +0100743 // Cast pCB to const because we don't want to create entries that don't exist here (in case the key changes to something
744 // in common with the non-const version.)
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700745 const ImageSubresourceLayoutMap *subresource_map = (attachment_initial_layout != VK_IMAGE_LAYOUT_UNDEFINED)
746 ? GetImageSubresourceLayoutMap(const_p_cb, image)
747 : nullptr;
Tobias Hectorc9057422019-07-23 12:15:52 +0100748
749 if (subresource_map) { // If no layout information for image yet, will be checked at QueueSubmit time
750 LayoutUseCheckAndMessage layout_check(subresource_map);
751 bool subres_skip = false;
John Zulauf5e617452019-11-19 14:44:16 -0700752 auto pos = subresource_map->Find(view_state->normalized_subresource_range);
Tony Barbour55688172020-09-23 15:19:50 -0700753 // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to
754 // the next "constant value" range
755 for (; !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
John Zulauf5e617452019-11-19 14:44:16 -0700756 const VkImageSubresource &subres = pos->subresource;
Piers Daniell7f894f62020-01-09 16:33:48 -0700757
John Zulauf5e617452019-11-19 14:44:16 -0700758 // Allow for differing depth and stencil layouts
759 VkImageLayout check_layout = attachment_initial_layout;
760 if (subres.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) check_layout = attachment_stencil_initial_layout;
761
762 if (!layout_check.Check(subres, check_layout, pos->current_layout, pos->initial_layout)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700763 subres_skip |= LogError(
764 device, kVUID_Core_DrawState_InvalidRenderpass,
Piers Daniell7f894f62020-01-09 16:33:48 -0700765 "You cannot start a render pass using attachment %u where the render pass initial layout is %s "
766 "and the %s layout of the attachment is %s. The layouts must match, or the render "
767 "pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED",
John Zulauf5e617452019-11-19 14:44:16 -0700768 i, string_VkImageLayout(check_layout), layout_check.message, string_VkImageLayout(layout_check.layout));
Tobias Hectorc9057422019-07-23 12:15:52 +0100769 }
Piers Daniell7f894f62020-01-09 16:33:48 -0700770 }
John Zulauf5e617452019-11-19 14:44:16 -0700771
Tobias Hectorc9057422019-07-23 12:15:52 +0100772 skip |= subres_skip;
773 }
774
775 ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_initial_layout, image, image_view,
776 framebuffer, render_pass, i, "initial layout");
777
778 ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, final_layout, image, image_view, framebuffer,
779 render_pass, i, "final layout");
Tobias Hectorbbb12282018-10-22 15:17:59 +0100780 }
781
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700782 for (uint32_t j = 0; j < render_pass_info->subpassCount; ++j) {
783 auto &subpass = render_pass_info->pSubpasses[j];
784 for (uint32_t k = 0; k < render_pass_info->pSubpasses[j].inputAttachmentCount; ++k) {
Tobias Hectorc9057422019-07-23 12:15:52 +0100785 auto &attachment_ref = subpass.pInputAttachments[k];
786 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
787 auto image_view = attachments[attachment_ref.attachment];
788 auto view_state = GetImageViewState(image_view);
Tobias Hectorbbb12282018-10-22 15:17:59 +0100789
Tobias Hectorc9057422019-07-23 12:15:52 +0100790 if (view_state) {
791 auto image = view_state->create_info.image;
Mark Lobodzinskief4ab2e2019-03-07 13:23:36 -0700792 ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view,
793 framebuffer, render_pass, attachment_ref.attachment,
Tobias Hectorc9057422019-07-23 12:15:52 +0100794 "input attachment layout");
Tobias Hectorbbb12282018-10-22 15:17:59 +0100795 }
796 }
797 }
Tobias Hectorbbb12282018-10-22 15:17:59 +0100798
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700799 for (uint32_t k = 0; k < render_pass_info->pSubpasses[j].colorAttachmentCount; ++k) {
Tobias Hectorc9057422019-07-23 12:15:52 +0100800 auto &attachment_ref = subpass.pColorAttachments[k];
801 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
802 auto image_view = attachments[attachment_ref.attachment];
803 auto view_state = GetImageViewState(image_view);
Tobias Hectorbbb12282018-10-22 15:17:59 +0100804
Tobias Hectorc9057422019-07-23 12:15:52 +0100805 if (view_state) {
806 auto image = view_state->create_info.image;
807 ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view,
808 framebuffer, render_pass, attachment_ref.attachment,
809 "color attachment layout");
810 if (subpass.pResolveAttachments) {
811 ValidateRenderPassLayoutAgainstFramebufferImageUsage(
812 rp_version, attachment_ref.layout, image, image_view, framebuffer, render_pass,
813 attachment_ref.attachment, "resolve attachment layout");
814 }
815 }
816 }
817 }
818
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700819 if (render_pass_info->pSubpasses[j].pDepthStencilAttachment) {
Tobias Hectorc9057422019-07-23 12:15:52 +0100820 auto &attachment_ref = *subpass.pDepthStencilAttachment;
821 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
822 auto image_view = attachments[attachment_ref.attachment];
823 auto view_state = GetImageViewState(image_view);
824
825 if (view_state) {
826 auto image = view_state->create_info.image;
827 ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view,
828 framebuffer, render_pass, attachment_ref.attachment,
829 "input attachment layout");
830 }
Tobias Hectorbbb12282018-10-22 15:17:59 +0100831 }
832 }
833 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700834 }
Mark Lobodzinskibdc3b022017-04-24 09:11:35 -0600835 return skip;
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700836}
837
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600838void CoreChecks::TransitionAttachmentRefLayout(CMD_BUFFER_STATE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
Mike Schuchardtf6f00492019-10-21 23:35:17 -0700839 const safe_VkAttachmentReference2 &ref) {
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700840 if (ref.attachment != VK_ATTACHMENT_UNUSED) {
Mark Lobodzinski8d46f802020-12-07 16:33:54 -0700841 IMAGE_VIEW_STATE *image_view = GetActiveAttachmentImageViewState(pCB, ref.attachment);
John Zulauf8e308292018-09-21 11:34:37 -0600842 if (image_view) {
Piers Daniell4fde9b72019-11-27 16:19:46 -0700843 VkImageLayout stencil_layout = kInvalidLayout;
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700844 const auto *attachment_reference_stencil_layout = LvlFindInChain<VkAttachmentReferenceStencilLayout>(ref.pNext);
Piers Daniell4fde9b72019-11-27 16:19:46 -0700845 if (attachment_reference_stencil_layout) {
846 stencil_layout = attachment_reference_stencil_layout->stencilLayout;
847 }
848
849 SetImageViewLayout(pCB, *image_view, ref.layout, stencil_layout);
John Zulauf8e308292018-09-21 11:34:37 -0600850 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700851 }
852}
853
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600854void CoreChecks::TransitionSubpassLayouts(CMD_BUFFER_STATE *pCB, const RENDER_PASS_STATE *render_pass_state,
855 const int subpass_index, FRAMEBUFFER_STATE *framebuffer_state) {
Tobin Ehlis0d4274b2017-02-17 15:17:04 -0700856 assert(render_pass_state);
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700857
858 if (framebuffer_state) {
Tobin Ehlis0d4274b2017-02-17 15:17:04 -0700859 auto const &subpass = render_pass_state->createInfo.pSubpasses[subpass_index];
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700860 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
Mark Lobodzinski8564e442019-03-07 12:49:41 -0700861 TransitionAttachmentRefLayout(pCB, framebuffer_state, subpass.pInputAttachments[j]);
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700862 }
863 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
Mark Lobodzinski8564e442019-03-07 12:49:41 -0700864 TransitionAttachmentRefLayout(pCB, framebuffer_state, subpass.pColorAttachments[j]);
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700865 }
866 if (subpass.pDepthStencilAttachment) {
Mark Lobodzinski8564e442019-03-07 12:49:41 -0700867 TransitionAttachmentRefLayout(pCB, framebuffer_state, *subpass.pDepthStencilAttachment);
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700868 }
869 }
870}
871
Tobin Ehlis0d4274b2017-02-17 15:17:04 -0700872// Transition the layout state for renderpass attachments based on the BeginRenderPass() call. This includes:
873// 1. Transition into initialLayout state
874// 2. Transition from initialLayout to layout used in subpass 0
Mark Lobodzinski33a34b82019-04-25 11:38:36 -0600875void CoreChecks::TransitionBeginRenderPassLayouts(CMD_BUFFER_STATE *cb_state, const RENDER_PASS_STATE *render_pass_state,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -0700876 FRAMEBUFFER_STATE *framebuffer_state) {
John Zulauf81dd1f12021-01-26 16:49:16 -0700877 // First record expected initialLayout as a potential initial layout usage.
Tobin Ehlis0d4274b2017-02-17 15:17:04 -0700878 auto const rpci = render_pass_state->createInfo.ptr();
879 for (uint32_t i = 0; i < rpci->attachmentCount; ++i) {
locke-lunargfc78e932020-11-19 17:06:24 -0700880 auto *view_state = GetActiveAttachmentImageViewState(cb_state, i);
John Zulauf8e308292018-09-21 11:34:37 -0600881 if (view_state) {
John Zulauf81dd1f12021-01-26 16:49:16 -0700882 IMAGE_STATE *image_state = view_state->image_state.get();
883 const auto initial_layout = rpci->pAttachments[i].initialLayout;
Piers Daniell4fde9b72019-11-27 16:19:46 -0700884 const auto *attachment_description_stencil_layout =
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700885 LvlFindInChain<VkAttachmentDescriptionStencilLayout>(rpci->pAttachments[i].pNext);
Piers Daniell4fde9b72019-11-27 16:19:46 -0700886 if (attachment_description_stencil_layout) {
John Zulauf81dd1f12021-01-26 16:49:16 -0700887 const auto stencil_initial_layout = attachment_description_stencil_layout->stencilInitialLayout;
888 VkImageSubresourceRange sub_range = view_state->normalized_subresource_range;
889 sub_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
890 SetImageInitialLayout(cb_state, *image_state, sub_range, initial_layout);
891 sub_range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
892 SetImageInitialLayout(cb_state, *image_state, sub_range, stencil_initial_layout);
893 } else {
894 SetImageInitialLayout(cb_state, *image_state, view_state->normalized_subresource_range, initial_layout);
Piers Daniell4fde9b72019-11-27 16:19:46 -0700895 }
John Zulauf8e308292018-09-21 11:34:37 -0600896 }
Tobin Ehlis0d4274b2017-02-17 15:17:04 -0700897 }
898 // Now transition for first subpass (index 0)
Mark Lobodzinski8564e442019-03-07 12:49:41 -0700899 TransitionSubpassLayouts(cb_state, render_pass_state, 0, framebuffer_state);
Tobin Ehlis0d4274b2017-02-17 15:17:04 -0700900}
901
Dave Houlton10b39482017-03-16 13:18:15 -0600902bool VerifyAspectsPresent(VkImageAspectFlags aspect_mask, VkFormat format) {
Dave Houlton4eaaf3a2017-03-14 11:31:20 -0600903 if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
Dave Houltone2fca552018-04-05 16:20:33 -0600904 if (!(FormatIsColor(format) || FormatIsMultiplane(format))) return false;
Dave Houlton4eaaf3a2017-03-14 11:31:20 -0600905 }
906 if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
Dave Houlton1d2022c2017-03-29 11:43:58 -0600907 if (!FormatHasDepth(format)) return false;
Dave Houlton4eaaf3a2017-03-14 11:31:20 -0600908 }
909 if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
Dave Houlton1d2022c2017-03-29 11:43:58 -0600910 if (!FormatHasStencil(format)) return false;
Dave Houlton4eaaf3a2017-03-14 11:31:20 -0600911 }
Mike Schuchardt2df08912020-12-15 16:28:09 -0800912 if (0 != (aspect_mask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT))) {
Dave Houltonb3f4b282018-02-22 16:25:16 -0700913 if (FormatPlaneCount(format) == 1) return false;
914 }
Dave Houlton4eaaf3a2017-03-14 11:31:20 -0600915 return true;
916}
917
Mike Weiblen62d08a32017-03-07 22:18:27 -0700918// Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags.
Petr Krausad0096a2019-08-09 18:35:04 +0200919bool CoreChecks::ValidateBarrierLayoutToImageUsage(const VkImageMemoryBarrier &img_barrier, bool new_not_old,
920 VkImageUsageFlags usage_flags, const char *func_name,
John Zulaufa4472282019-08-22 14:44:34 -0600921 const char *barrier_pname) const {
Mike Weiblen62d08a32017-03-07 22:18:27 -0700922 bool skip = false;
Petr Krausad0096a2019-08-09 18:35:04 +0200923 const VkImageLayout layout = (new_not_old) ? img_barrier.newLayout : img_barrier.oldLayout;
Jeff Bolz6d3beaa2019-02-09 21:00:05 -0600924 const char *msg_code = kVUIDUndefined; // sentinel value meaning "no error"
Mike Weiblen62d08a32017-03-07 22:18:27 -0700925
926 switch (layout) {
927 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
928 if ((usage_flags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0) {
Dave Houltond8ed0212018-05-16 17:18:24 -0600929 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01208";
Mike Weiblen62d08a32017-03-07 22:18:27 -0700930 }
931 break;
932 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
933 if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
Dave Houltond8ed0212018-05-16 17:18:24 -0600934 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01209";
Mike Weiblen62d08a32017-03-07 22:18:27 -0700935 }
936 break;
937 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
938 if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
Dave Houltond8ed0212018-05-16 17:18:24 -0600939 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01210";
Mike Weiblen62d08a32017-03-07 22:18:27 -0700940 }
941 break;
942 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
943 if ((usage_flags & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0) {
Dave Houltond8ed0212018-05-16 17:18:24 -0600944 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01211";
Mike Weiblen62d08a32017-03-07 22:18:27 -0700945 }
946 break;
947 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
948 if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0) {
Dave Houltond8ed0212018-05-16 17:18:24 -0600949 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01212";
Mike Weiblen62d08a32017-03-07 22:18:27 -0700950 }
951 break;
952 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
953 if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
Dave Houltond8ed0212018-05-16 17:18:24 -0600954 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01213";
Mike Weiblen62d08a32017-03-07 22:18:27 -0700955 }
956 break;
Dave Houlton142c4cb2018-10-17 15:04:41 -0600957 case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV:
Jeff Bolz9af91c52018-09-01 21:53:57 -0500958 if ((usage_flags & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) == 0) {
959 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-02088";
960 }
961 break;
sfricke-samsung9f9ca962020-04-25 02:04:55 -0700962 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
963 if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
964 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01658";
965 }
966 break;
967 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
968 if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
969 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01659";
970 }
971 break;
Mike Weiblen62d08a32017-03-07 22:18:27 -0700972 default:
973 // Other VkImageLayout values do not have VUs defined in this context.
974 break;
975 }
976
Dave Houlton8e9f6542018-05-18 12:18:22 -0600977 if (msg_code != kVUIDUndefined) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -0700978 skip |= LogError(img_barrier.image, msg_code,
979 "%s: Image barrier %s %s Layout=%s is not compatible with %s usage flags 0x%" PRIx32 ".", func_name,
980 barrier_pname, ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout),
981 report_data->FormatHandle(img_barrier.image).c_str(), usage_flags);
Mike Weiblen62d08a32017-03-07 22:18:27 -0700982 }
983 return skip;
984}
985
986// Verify image barriers are compatible with the images they reference.
John Zulaufa4472282019-08-22 14:44:34 -0600987bool CoreChecks::ValidateBarriersToImages(const CMD_BUFFER_STATE *cb_state, uint32_t imageMemoryBarrierCount,
988 const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) const {
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700989 bool skip = false;
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -0700990
Petr Krausad0096a2019-08-09 18:35:04 +0200991 // Scoreboard for checking for duplicate and inconsistent barriers to images
992 struct ImageBarrierScoreboardEntry {
993 uint32_t index;
994 // This is designed for temporary storage within the scope of the API call. If retained storage of the barriers is
995 // required, copies should be made and smart or unique pointers used in some other stucture (or this one refactored)
996 const VkImageMemoryBarrier *barrier;
997 };
998 using ImageBarrierScoreboardSubresMap = std::unordered_map<VkImageSubresourceRange, ImageBarrierScoreboardEntry>;
999 using ImageBarrierScoreboardImageMap = std::unordered_map<VkImage, ImageBarrierScoreboardSubresMap>;
1000
John Zulauf463c51e2018-05-31 13:29:20 -06001001 // Scoreboard for duplicate layout transition barriers within the list
1002 // Pointers retained in the scoreboard only have the lifetime of *this* call (i.e. within the scope of the API call)
1003 ImageBarrierScoreboardImageMap layout_transitions;
1004
Mike Weiblen62d08a32017-03-07 22:18:27 -07001005 for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
Petr Krausad0096a2019-08-09 18:35:04 +02001006 const auto &img_barrier = pImageMemoryBarriers[i];
1007 const std::string barrier_pname = "pImageMemoryBarrier[" + std::to_string(i) + "]";
Mike Weiblen62d08a32017-03-07 22:18:27 -07001008
John Zulauf463c51e2018-05-31 13:29:20 -06001009 // Update the scoreboard of layout transitions and check for barriers affecting the same image and subresource
1010 // TODO: a higher precision could be gained by adapting the command_buffer image_layout_map logic looking for conflicts
1011 // at a per sub-resource level
Petr Krausad0096a2019-08-09 18:35:04 +02001012 if (img_barrier.oldLayout != img_barrier.newLayout) {
1013 const ImageBarrierScoreboardEntry new_entry{i, &img_barrier};
1014 const auto image_it = layout_transitions.find(img_barrier.image);
John Zulauf463c51e2018-05-31 13:29:20 -06001015 if (image_it != layout_transitions.end()) {
1016 auto &subres_map = image_it->second;
Petr Krausad0096a2019-08-09 18:35:04 +02001017 auto subres_it = subres_map.find(img_barrier.subresourceRange);
John Zulauf463c51e2018-05-31 13:29:20 -06001018 if (subres_it != subres_map.end()) {
1019 auto &entry = subres_it->second;
Petr Krausad0096a2019-08-09 18:35:04 +02001020 if ((entry.barrier->newLayout != img_barrier.oldLayout) &&
1021 (img_barrier.oldLayout != VK_IMAGE_LAYOUT_UNDEFINED)) {
1022 const VkImageSubresourceRange &range = img_barrier.subresourceRange;
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001023 skip = LogError(
1024 cb_state->commandBuffer, "VUID-VkImageMemoryBarrier-oldLayout-01197",
Petr Krausad0096a2019-08-09 18:35:04 +02001025 "%s: %s conflicts with earlier entry pImageMemoryBarrier[%u]. %s"
John Zulauf463c51e2018-05-31 13:29:20 -06001026 " subresourceRange: aspectMask=%u baseMipLevel=%u levelCount=%u, baseArrayLayer=%u, layerCount=%u; "
1027 "conflicting barrier transitions image layout from %s when earlier barrier transitioned to layout %s.",
Petr Krausad0096a2019-08-09 18:35:04 +02001028 func_name, barrier_pname.c_str(), entry.index, report_data->FormatHandle(img_barrier.image).c_str(),
1029 range.aspectMask, range.baseMipLevel, range.levelCount, range.baseArrayLayer, range.layerCount,
1030 string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(entry.barrier->newLayout));
John Zulauf463c51e2018-05-31 13:29:20 -06001031 }
1032 entry = new_entry;
1033 } else {
Petr Krausad0096a2019-08-09 18:35:04 +02001034 subres_map[img_barrier.subresourceRange] = new_entry;
John Zulauf463c51e2018-05-31 13:29:20 -06001035 }
1036 } else {
Petr Krausad0096a2019-08-09 18:35:04 +02001037 layout_transitions[img_barrier.image][img_barrier.subresourceRange] = new_entry;
John Zulauf463c51e2018-05-31 13:29:20 -06001038 }
1039 }
1040
Petr Krausad0096a2019-08-09 18:35:04 +02001041 auto image_state = GetImageState(img_barrier.image);
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06001042 if (image_state) {
1043 VkImageUsageFlags usage_flags = image_state->createInfo.usage;
Petr Krausad0096a2019-08-09 18:35:04 +02001044 skip |= ValidateBarrierLayoutToImageUsage(img_barrier, false, usage_flags, func_name, barrier_pname.c_str());
1045 skip |= ValidateBarrierLayoutToImageUsage(img_barrier, true, usage_flags, func_name, barrier_pname.c_str());
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06001046
1047 // Make sure layout is able to be transitioned, currently only presented shared presentable images are locked
1048 if (image_state->layout_locked) {
1049 // TODO: Add unique id for error when available
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001050 skip |= LogError(
1051 img_barrier.image, 0,
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07001052 "%s: Attempting to transition shared presentable %s"
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06001053 " from layout %s to layout %s, but image has already been presented and cannot have its layout transitioned.",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07001054 func_name, report_data->FormatHandle(img_barrier.image).c_str(), string_VkImageLayout(img_barrier.oldLayout),
Petr Krausad0096a2019-08-09 18:35:04 +02001055 string_VkImageLayout(img_barrier.newLayout));
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06001056 }
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06001057
John Zulaufa4472282019-08-22 14:44:34 -06001058 const VkImageCreateInfo &image_create_info = image_state->createInfo;
sfricke-samsung79b00482020-04-01 21:15:50 -07001059 const VkFormat image_format = image_create_info.format;
1060 const VkImageAspectFlags aspect_mask = img_barrier.subresourceRange.aspectMask;
John Zulauff660ad62019-03-23 07:16:05 -06001061 // For a Depth/Stencil image both aspects MUST be set
sfricke-samsung79b00482020-04-01 21:15:50 -07001062 if (FormatIsDepthAndStencil(image_format)) {
Piers Daniell41b8c5d2020-01-10 15:42:00 -07001063 if (enabled_features.core12.separateDepthStencilLayouts) {
Piers Daniell9af77cd2019-10-16 13:54:12 -06001064 if (!(aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
1065 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001066 LogError(img_barrier.image, "VUID-VkImageMemoryBarrier-image-03319",
1067 "%s: Image barrier %s references %s of format %s that must have either the depth or stencil "
1068 "aspects set, but its aspectMask is 0x%" PRIx32 ".",
1069 func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
sfricke-samsung79b00482020-04-01 21:15:50 -07001070 string_VkFormat(image_format), aspect_mask);
Piers Daniell9af77cd2019-10-16 13:54:12 -06001071 }
1072 } else {
1073 auto const ds_mask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1074 if ((aspect_mask & ds_mask) != (ds_mask)) {
sfricke-samsung38d280b2020-05-16 08:02:56 -07001075 const char *vuid = device_extensions.vk_khr_separate_depth_stencil_layouts
1076 ? "VUID-VkImageMemoryBarrier-image-03320"
1077 : "VUID-VkImageMemoryBarrier-image-01207";
1078 skip |= LogError(img_barrier.image, vuid,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001079 "%s: Image barrier %s references %s of format %s that must have the depth and stencil "
1080 "aspects set, but its aspectMask is 0x%" PRIx32 ".",
1081 func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
sfricke-samsung79b00482020-04-01 21:15:50 -07001082 string_VkFormat(image_format), aspect_mask);
Piers Daniell9af77cd2019-10-16 13:54:12 -06001083 }
Dave Houltonb3f4b282018-02-22 16:25:16 -07001084 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001085 }
John Zulauff660ad62019-03-23 07:16:05 -06001086
Petr Krausad0096a2019-08-09 18:35:04 +02001087 const auto *subresource_map = GetImageSubresourceLayoutMap(cb_state, img_barrier.image);
1088 if (img_barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
John Zulauff660ad62019-03-23 07:16:05 -06001089 // TODO: Set memory invalid which is in mem_tracker currently
1090 // Not sure if this needs to be in the ForRange traversal, pulling it out as it is currently invariant with
1091 // subresource.
John Zulaufcea64cb2020-06-10 17:17:27 -06001092 } else if (subresource_map && !QueueFamilyIsExternal(img_barrier.srcQueueFamilyIndex)) {
John Zulauff660ad62019-03-23 07:16:05 -06001093 bool subres_skip = false;
John Zulauf02a204c2019-04-23 18:52:11 -06001094 LayoutUseCheckAndMessage layout_check(subresource_map);
Petr Krausad0096a2019-08-09 18:35:04 +02001095 VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, img_barrier.subresourceRange);
Tony Barbour55688172020-09-23 15:19:50 -07001096 // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to
1097 // the next "constant value" range
1098 for (auto pos = subresource_map->Find(normalized_isr); !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
John Zulauf5e617452019-11-19 14:44:16 -07001099 const auto &value = *pos;
1100 if (!layout_check.Check(value.subresource, img_barrier.oldLayout, value.current_layout, value.initial_layout)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001101 subres_skip = LogError(
1102 cb_state->commandBuffer, "VUID-VkImageMemoryBarrier-oldLayout-01197",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07001103 "%s: For %s you cannot transition the layout of aspect=%d level=%d layer=%d from %s when the "
John Zulauf5e617452019-11-19 14:44:16 -07001104 "%s layout is %s.",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07001105 func_name, report_data->FormatHandle(img_barrier.image).c_str(), value.subresource.aspectMask,
John Zulauf5e617452019-11-19 14:44:16 -07001106 value.subresource.mipLevel, value.subresource.arrayLayer, string_VkImageLayout(img_barrier.oldLayout),
1107 layout_check.message, string_VkImageLayout(layout_check.layout));
John Zulauff660ad62019-03-23 07:16:05 -06001108 }
John Zulauf5e617452019-11-19 14:44:16 -07001109 }
John Zulauff660ad62019-03-23 07:16:05 -06001110 skip |= subres_skip;
1111 }
sfricke-samsung79b00482020-04-01 21:15:50 -07001112
1113 // checks color format and (single-plane or non-disjoint)
1114 // if ycbcr extension is not supported then single-plane and non-disjoint are always both true
1115 if ((FormatIsColor(image_format) == true) &&
sfricke-samsung71bc6572020-04-29 15:49:43 -07001116 ((FormatIsMultiplane(image_format) == false) || (image_state->disjoint == false))) {
sfricke-samsung79b00482020-04-01 21:15:50 -07001117 if (aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT) {
1118 const char *vuid = (device_extensions.vk_khr_sampler_ycbcr_conversion)
1119 ? "VUID-VkImageMemoryBarrier-image-01671"
1120 : "VUID-VkImageMemoryBarrier-image-02902";
1121 skip |= LogError(img_barrier.image, vuid,
1122 "%s: Image barrier %s references %s of format %s that must be only VK_IMAGE_ASPECT_COLOR_BIT, "
1123 "but its aspectMask is 0x%" PRIx32 ".",
1124 func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
1125 string_VkFormat(image_format), aspect_mask);
1126 }
1127 }
1128
1129 VkImageAspectFlags valid_disjoint_mask =
1130 VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT | VK_IMAGE_ASPECT_COLOR_BIT;
sfricke-samsung71bc6572020-04-29 15:49:43 -07001131 if ((FormatIsMultiplane(image_format) == true) && (image_state->disjoint == true) &&
sfricke-samsung79b00482020-04-01 21:15:50 -07001132 ((aspect_mask & valid_disjoint_mask) == 0)) {
1133 skip |= LogError(img_barrier.image, "VUID-VkImageMemoryBarrier-image-01672",
1134 "%s: Image barrier %s references %s of format %s has aspectMask (0x%" PRIx32
1135 ") but needs to include either an VK_IMAGE_ASPECT_PLANE_*_BIT or VK_IMAGE_ASPECT_COLOR_BIT.",
1136 func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
1137 string_VkFormat(image_format), aspect_mask);
1138 }
1139
1140 if ((FormatPlaneCount(image_format) == 2) && ((aspect_mask & VK_IMAGE_ASPECT_PLANE_2_BIT) != 0)) {
1141 skip |= LogError(img_barrier.image, "VUID-VkImageMemoryBarrier-image-01673",
1142 "%s: Image barrier %s references %s of format %s has only two planes but included "
1143 "VK_IMAGE_ASPECT_PLANE_2_BIT in its aspectMask (0x%" PRIx32 ").",
1144 func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
1145 string_VkFormat(image_format), aspect_mask);
1146 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001147 }
1148 }
1149 return skip;
1150}
1151
John Zulauf6b4aae82018-05-09 13:03:36 -06001152template <typename Barrier>
John Zulaufa4472282019-08-22 14:44:34 -06001153bool CoreChecks::ValidateQFOTransferBarrierUniqueness(const char *func_name, const CMD_BUFFER_STATE *cb_state,
1154 uint32_t barrier_count, const Barrier *barriers) const {
John Zulauf6b4aae82018-05-09 13:03:36 -06001155 using BarrierRecord = QFOTransferBarrier<Barrier>;
1156 bool skip = false;
Jeff Bolz6835fda2019-10-06 00:15:34 -05001157 auto pool = cb_state->command_pool.get();
John Zulauf6b4aae82018-05-09 13:03:36 -06001158 auto &barrier_sets = GetQFOBarrierSets(cb_state, typename BarrierRecord::Tag());
1159 const char *barrier_name = BarrierRecord::BarrierName();
1160 const char *handle_name = BarrierRecord::HandleName();
1161 const char *transfer_type = nullptr;
1162 for (uint32_t b = 0; b < barrier_count; b++) {
1163 if (!IsTransferOp(&barriers[b])) continue;
1164 const BarrierRecord *barrier_record = nullptr;
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07001165 if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer */>(pool, &barriers[b]) &&
John Zulaufcea64cb2020-06-10 17:17:27 -06001166 !QueueFamilyIsExternal(barriers[b].dstQueueFamilyIndex)) {
John Zulauf6b4aae82018-05-09 13:03:36 -06001167 const auto found = barrier_sets.release.find(barriers[b]);
1168 if (found != barrier_sets.release.cend()) {
1169 barrier_record = &(*found);
1170 transfer_type = "releasing";
1171 }
Shannon McPhersoned2f0092018-08-30 17:18:04 -06001172 } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barriers[b]) &&
John Zulaufcea64cb2020-06-10 17:17:27 -06001173 !QueueFamilyIsExternal(barriers[b].srcQueueFamilyIndex)) {
John Zulauf6b4aae82018-05-09 13:03:36 -06001174 const auto found = barrier_sets.acquire.find(barriers[b]);
1175 if (found != barrier_sets.acquire.cend()) {
1176 barrier_record = &(*found);
1177 transfer_type = "acquiring";
1178 }
1179 }
1180 if (barrier_record != nullptr) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001181 skip |= LogWarning(cb_state->commandBuffer, BarrierRecord::ErrMsgDuplicateQFOInCB(),
1182 "%s: %s at index %" PRIu32 " %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1183 " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier recorded in this command buffer.",
1184 func_name, barrier_name, b, transfer_type, handle_name,
1185 report_data->FormatHandle(barrier_record->handle).c_str(), barrier_record->srcQueueFamilyIndex,
1186 barrier_record->dstQueueFamilyIndex);
John Zulauf6b4aae82018-05-09 13:03:36 -06001187 }
1188 }
1189 return skip;
1190}
1191
John Zulaufa4472282019-08-22 14:44:34 -06001192VulkanTypedHandle BarrierTypedHandle(const VkImageMemoryBarrier &barrier) {
1193 return VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage);
1194}
1195
1196const IMAGE_STATE *BarrierHandleState(const ValidationStateTracker &device_state, const VkImageMemoryBarrier &barrier) {
1197 return device_state.GetImageState(barrier.image);
1198}
1199
1200VulkanTypedHandle BarrierTypedHandle(const VkBufferMemoryBarrier &barrier) {
1201 return VulkanTypedHandle(barrier.buffer, kVulkanObjectTypeBuffer);
1202}
1203
1204const BUFFER_STATE *BarrierHandleState(const ValidationStateTracker &device_state, const VkBufferMemoryBarrier &barrier) {
1205 return device_state.GetBufferState(barrier.buffer);
1206}
1207
1208VkBuffer BarrierHandle(const VkBufferMemoryBarrier &barrier) { return barrier.buffer; }
1209
John Zulauf6b4aae82018-05-09 13:03:36 -06001210template <typename Barrier>
John Zulaufa4472282019-08-22 14:44:34 -06001211void CoreChecks::RecordBarrierArrayValidationInfo(const char *func_name, CMD_BUFFER_STATE *cb_state, uint32_t barrier_count,
1212 const Barrier *barriers) {
Jeff Bolz6835fda2019-10-06 00:15:34 -05001213 auto pool = cb_state->command_pool.get();
John Zulauf6b4aae82018-05-09 13:03:36 -06001214 auto &barrier_sets = GetQFOBarrierSets(cb_state, typename QFOTransferBarrier<Barrier>::Tag());
1215 for (uint32_t b = 0; b < barrier_count; b++) {
John Zulaufa4472282019-08-22 14:44:34 -06001216 auto &barrier = barriers[b];
1217 if (IsTransferOp(&barrier)) {
1218 if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer*/>(pool, &barrier) &&
John Zulaufcea64cb2020-06-10 17:17:27 -06001219 !QueueFamilyIsExternal(barrier.dstQueueFamilyIndex)) {
John Zulaufa4472282019-08-22 14:44:34 -06001220 barrier_sets.release.emplace(barrier);
1221 } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barrier) &&
John Zulaufcea64cb2020-06-10 17:17:27 -06001222 !QueueFamilyIsExternal(barrier.srcQueueFamilyIndex)) {
John Zulaufa4472282019-08-22 14:44:34 -06001223 barrier_sets.acquire.emplace(barrier);
1224 }
1225 }
1226
1227 const uint32_t src_queue_family = barrier.srcQueueFamilyIndex;
1228 const uint32_t dst_queue_family = barrier.dstQueueFamilyIndex;
1229 if (!QueueFamilyIsIgnored(src_queue_family) && !QueueFamilyIsIgnored(dst_queue_family)) {
1230 // Only enqueue submit time check if it is needed. If more submit time checks are added, change the criteria
1231 // TODO create a better named list, or rename the submit time lists to something that matches the broader usage...
1232 auto handle_state = BarrierHandleState(*this, barrier);
1233 bool mode_concurrent = handle_state ? handle_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT : false;
1234 if (!mode_concurrent) {
1235 const auto typed_handle = BarrierTypedHandle(barrier);
Jeff Bolz310775c2019-10-09 00:46:33 -05001236 cb_state->queue_submit_functions.emplace_back(
1237 [func_name, cb_state, typed_handle, src_queue_family, dst_queue_family](
1238 const ValidationStateTracker *device_data, const QUEUE_STATE *queue_state) {
1239 return ValidateConcurrentBarrierAtSubmit(device_data, queue_state, func_name, cb_state, typed_handle,
1240 src_queue_family, dst_queue_family);
John Zulaufa4472282019-08-22 14:44:34 -06001241 });
1242 }
John Zulauf6b4aae82018-05-09 13:03:36 -06001243 }
1244 }
1245}
1246
John Zulaufa4472282019-08-22 14:44:34 -06001247bool CoreChecks::ValidateBarriersQFOTransferUniqueness(const char *func_name, const CMD_BUFFER_STATE *cb_state,
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06001248 uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07001249 uint32_t imageMemBarrierCount,
John Zulaufa4472282019-08-22 14:44:34 -06001250 const VkImageMemoryBarrier *pImageMemBarriers) const {
John Zulauf6b4aae82018-05-09 13:03:36 -06001251 bool skip = false;
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07001252 skip |= ValidateQFOTransferBarrierUniqueness(func_name, cb_state, bufferBarrierCount, pBufferMemBarriers);
1253 skip |= ValidateQFOTransferBarrierUniqueness(func_name, cb_state, imageMemBarrierCount, pImageMemBarriers);
John Zulauf6b4aae82018-05-09 13:03:36 -06001254 return skip;
1255}
1256
John Zulaufa4472282019-08-22 14:44:34 -06001257void CoreChecks::RecordBarrierValidationInfo(const char *func_name, CMD_BUFFER_STATE *cb_state, uint32_t bufferBarrierCount,
1258 const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
1259 const VkImageMemoryBarrier *pImageMemBarriers) {
1260 RecordBarrierArrayValidationInfo(func_name, cb_state, bufferBarrierCount, pBufferMemBarriers);
1261 RecordBarrierArrayValidationInfo(func_name, cb_state, imageMemBarrierCount, pImageMemBarriers);
John Zulauf6b4aae82018-05-09 13:03:36 -06001262}
1263
Jeremy Gebben50e0b412021-02-18 10:39:41 -07001264// Verify image barrier image state and that the image is consistent with FB image
1265bool CoreChecks::ValidateImageBarrierAttachment(const char *funcName, CMD_BUFFER_STATE const *cb_state,
1266 const FRAMEBUFFER_STATE *framebuffer, uint32_t active_subpass,
1267 const safe_VkSubpassDescription2 &sub_desc, const VkRenderPass rp_handle,
1268 uint32_t img_index, const VkImageMemoryBarrier &img_barrier,
1269 const CMD_BUFFER_STATE *primary_cb_state) const {
1270 bool skip = false;
1271 const auto *fb_state = framebuffer;
1272 assert(fb_state);
1273 const auto img_bar_image = img_barrier.image;
1274 bool image_match = false;
1275 bool sub_image_found = false; // Do we find a corresponding subpass description
1276 VkImageLayout sub_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
1277 uint32_t attach_index = 0;
1278 // Verify that a framebuffer image matches barrier image
1279 const auto attachment_count = fb_state->createInfo.attachmentCount;
1280 for (uint32_t attachment = 0; attachment < attachment_count; ++attachment) {
1281 auto view_state = GetActiveAttachmentImageViewState(cb_state, attachment, primary_cb_state);
1282 if (view_state && (img_bar_image == view_state->create_info.image)) {
1283 image_match = true;
1284 attach_index = attachment;
1285 break;
1286 }
1287 }
1288 if (image_match) { // Make sure subpass is referring to matching attachment
1289 if (sub_desc.pDepthStencilAttachment && sub_desc.pDepthStencilAttachment->attachment == attach_index) {
1290 sub_image_layout = sub_desc.pDepthStencilAttachment->layout;
1291 sub_image_found = true;
1292 }
1293 if (!sub_image_found && device_extensions.vk_khr_depth_stencil_resolve) {
1294 const auto *resolve = LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(sub_desc.pNext);
1295 if (resolve && resolve->pDepthStencilResolveAttachment &&
1296 resolve->pDepthStencilResolveAttachment->attachment == attach_index) {
1297 sub_image_layout = resolve->pDepthStencilResolveAttachment->layout;
1298 sub_image_found = true;
1299 }
1300 }
1301 if (!sub_image_found) {
1302 for (uint32_t j = 0; j < sub_desc.colorAttachmentCount; ++j) {
1303 if (sub_desc.pColorAttachments && sub_desc.pColorAttachments[j].attachment == attach_index) {
1304 sub_image_layout = sub_desc.pColorAttachments[j].layout;
1305 sub_image_found = true;
1306 break;
1307 }
1308 if (!sub_image_found && sub_desc.pResolveAttachments &&
1309 sub_desc.pResolveAttachments[j].attachment == attach_index) {
1310 sub_image_layout = sub_desc.pResolveAttachments[j].layout;
1311 sub_image_found = true;
1312 break;
1313 }
1314 }
1315 }
1316 if (!sub_image_found) {
1317 skip |= LogError(rp_handle, "VUID-vkCmdPipelineBarrier-image-04073",
1318 "%s: Barrier pImageMemoryBarriers[%d].%s is not referenced by the VkSubpassDescription for "
1319 "active subpass (%d) of current %s.",
1320 funcName, img_index, report_data->FormatHandle(img_bar_image).c_str(), active_subpass,
1321 report_data->FormatHandle(rp_handle).c_str());
1322 }
1323 } else { // !image_match
1324 skip |=
1325 LogError(fb_state->framebuffer, "VUID-vkCmdPipelineBarrier-image-04073",
1326 "%s: Barrier pImageMemoryBarriers[%d].%s does not match an image from the current %s.", funcName, img_index,
1327 report_data->FormatHandle(img_bar_image).c_str(), report_data->FormatHandle(fb_state->framebuffer).c_str());
1328 }
1329 if (img_barrier.oldLayout != img_barrier.newLayout) {
1330 skip |= LogError(cb_state->commandBuffer, "VUID-vkCmdPipelineBarrier-oldLayout-01181",
1331 "%s: As the Image Barrier for %s is being executed within a render pass instance, oldLayout must "
1332 "equal newLayout yet they are %s and %s.",
1333 funcName, report_data->FormatHandle(img_barrier.image).c_str(),
1334 string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(img_barrier.newLayout));
1335 } else {
1336 if (sub_image_found && sub_image_layout != img_barrier.oldLayout) {
1337 LogObjectList objlist(rp_handle);
1338 objlist.add(img_bar_image);
1339 skip |= LogError(objlist, "VUID-vkCmdPipelineBarrier-oldLayout-01181",
1340 "%s: Barrier pImageMemoryBarriers[%d].%s is referenced by the VkSubpassDescription for active "
1341 "subpass (%d) of current %s as having layout %s, but image barrier has layout %s.",
1342 funcName, img_index, report_data->FormatHandle(img_bar_image).c_str(), active_subpass,
1343 report_data->FormatHandle(rp_handle).c_str(), string_VkImageLayout(sub_image_layout),
1344 string_VkImageLayout(img_barrier.oldLayout));
1345 }
1346 }
1347 return skip;
1348}
1349
1350void CoreChecks::EnqueueSubmitTimeValidateImageBarrierAttachment(const char *func_name, CMD_BUFFER_STATE *cb_state,
1351 uint32_t imageMemBarrierCount,
1352 const VkImageMemoryBarrier *pImageMemBarriers) {
1353 // Secondary CBs can have null framebuffer so queue up validation in that case 'til FB is known
1354 if ((cb_state->activeRenderPass) && (VK_NULL_HANDLE == cb_state->activeFramebuffer) &&
1355 (VK_COMMAND_BUFFER_LEVEL_SECONDARY == cb_state->createInfo.level)) {
1356 const auto active_subpass = cb_state->activeSubpass;
1357 const auto rp_state = cb_state->activeRenderPass;
1358 const auto &sub_desc = rp_state->createInfo.pSubpasses[active_subpass];
1359 for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
1360 const auto &img_barrier = pImageMemBarriers[i];
1361 // Secondary CB case w/o FB specified delay validation
1362 auto *this_ptr = this; // Required for older compilers with c++20 compatibility
1363 cb_state->cmd_execute_commands_functions.emplace_back(
1364 [=](const CMD_BUFFER_STATE *primary_cb, const FRAMEBUFFER_STATE *fb) {
1365 return this_ptr->ValidateImageBarrierAttachment(func_name, cb_state, fb, active_subpass, sub_desc,
1366 rp_state->renderPass, i, img_barrier, primary_cb);
1367 });
1368 }
1369 }
1370}
1371
John Zulauf6b4aae82018-05-09 13:03:36 -06001372template <typename BarrierRecord, typename Scoreboard>
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06001373bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const CMD_BUFFER_STATE *cb_state,
John Zulauf3b04ebd2019-07-18 14:08:11 -06001374 const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) const {
John Zulauf6b4aae82018-05-09 13:03:36 -06001375 // Record to the scoreboard or report that we have a duplication
1376 bool skip = false;
1377 auto inserted = scoreboard->insert(std::make_pair(barrier, cb_state));
1378 if (!inserted.second && inserted.first->second != cb_state) {
1379 // This is a duplication (but don't report duplicates from the same CB, as we do that at record time
Mark Lobodzinskiea561582020-03-16 18:13:56 -06001380 LogObjectList objlist(cb_state->commandBuffer);
1381 objlist.add(barrier.handle);
1382 objlist.add(inserted.first->second->commandBuffer);
1383 skip = LogWarning(objlist, BarrierRecord::ErrMsgDuplicateQFOInSubmit(),
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001384 "%s: %s %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1385 " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier submitted in this batch from %s.",
1386 "vkQueueSubmit()", BarrierRecord::BarrierName(), operation, BarrierRecord::HandleName(),
1387 report_data->FormatHandle(barrier.handle).c_str(), barrier.srcQueueFamilyIndex,
1388 barrier.dstQueueFamilyIndex, report_data->FormatHandle(inserted.first->second->commandBuffer).c_str());
John Zulauf6b4aae82018-05-09 13:03:36 -06001389 }
1390 return skip;
1391}
1392
1393template <typename Barrier>
John Zulauf3b04ebd2019-07-18 14:08:11 -06001394bool CoreChecks::ValidateQueuedQFOTransferBarriers(const CMD_BUFFER_STATE *cb_state,
1395 QFOTransferCBScoreboards<Barrier> *scoreboards) const {
John Zulauf6b4aae82018-05-09 13:03:36 -06001396 using BarrierRecord = QFOTransferBarrier<Barrier>;
1397 using TypeTag = typename BarrierRecord::Tag;
1398 bool skip = false;
John Zulauf6b4aae82018-05-09 13:03:36 -06001399 const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
Mark Lobodzinski8deebf12019-03-07 11:38:38 -07001400 const GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
John Zulauf6b4aae82018-05-09 13:03:36 -06001401 const char *barrier_name = BarrierRecord::BarrierName();
1402 const char *handle_name = BarrierRecord::HandleName();
1403 // No release should have an extant duplicate (WARNING)
1404 for (const auto &release : cb_barriers.release) {
1405 // Check the global pending release barriers
1406 const auto set_it = global_release_barriers.find(release.handle);
1407 if (set_it != global_release_barriers.cend()) {
1408 const QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
1409 const auto found = set_for_handle.find(release);
1410 if (found != set_for_handle.cend()) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001411 skip |= LogWarning(cb_state->commandBuffer, BarrierRecord::ErrMsgDuplicateQFOSubmitted(),
1412 "%s: %s releasing queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1413 " to dstQueueFamilyIndex %" PRIu32
1414 " duplicates existing barrier queued for execution, without intervening acquire operation.",
1415 "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(found->handle).c_str(),
1416 found->srcQueueFamilyIndex, found->dstQueueFamilyIndex);
John Zulauf6b4aae82018-05-09 13:03:36 -06001417 }
1418 }
1419 skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "releasing", release, &scoreboards->release);
1420 }
1421 // Each acquire must have a matching release (ERROR)
1422 for (const auto &acquire : cb_barriers.acquire) {
1423 const auto set_it = global_release_barriers.find(acquire.handle);
1424 bool matching_release_found = false;
1425 if (set_it != global_release_barriers.cend()) {
1426 const QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
1427 matching_release_found = set_for_handle.find(acquire) != set_for_handle.cend();
1428 }
1429 if (!matching_release_found) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001430 skip |= LogError(cb_state->commandBuffer, BarrierRecord::ErrMsgMissingQFOReleaseInSubmit(),
1431 "%s: in submitted command buffer %s acquiring ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1432 " to dstQueueFamilyIndex %" PRIu32 " has no matching release barrier queued for execution.",
1433 "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(acquire.handle).c_str(),
1434 acquire.srcQueueFamilyIndex, acquire.dstQueueFamilyIndex);
John Zulauf6b4aae82018-05-09 13:03:36 -06001435 }
1436 skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "acquiring", acquire, &scoreboards->acquire);
1437 }
1438 return skip;
1439}
1440
John Zulauf3b04ebd2019-07-18 14:08:11 -06001441bool CoreChecks::ValidateQueuedQFOTransfers(const CMD_BUFFER_STATE *cb_state,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07001442 QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
John Zulauf3b04ebd2019-07-18 14:08:11 -06001443 QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) const {
John Zulauf6b4aae82018-05-09 13:03:36 -06001444 bool skip = false;
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07001445 skip |= ValidateQueuedQFOTransferBarriers<VkImageMemoryBarrier>(cb_state, qfo_image_scoreboards);
1446 skip |= ValidateQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(cb_state, qfo_buffer_scoreboards);
John Zulauf6b4aae82018-05-09 13:03:36 -06001447 return skip;
1448}
1449
1450template <typename Barrier>
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06001451void CoreChecks::RecordQueuedQFOTransferBarriers(CMD_BUFFER_STATE *cb_state) {
John Zulauf6b4aae82018-05-09 13:03:36 -06001452 using BarrierRecord = QFOTransferBarrier<Barrier>;
1453 using TypeTag = typename BarrierRecord::Tag;
1454 const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
Mark Lobodzinski8deebf12019-03-07 11:38:38 -07001455 GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
John Zulauf6b4aae82018-05-09 13:03:36 -06001456
1457 // Add release barriers from this submit to the global map
1458 for (const auto &release : cb_barriers.release) {
1459 // the global barrier list is mapped by resource handle to allow cleanup on resource destruction
1460 // NOTE: We're using [] because creation of a Set is a needed side effect for new handles
1461 global_release_barriers[release.handle].insert(release);
1462 }
1463
1464 // Erase acquired barriers from this submit from the global map -- essentially marking releases as consumed
1465 for (const auto &acquire : cb_barriers.acquire) {
1466 // NOTE: We're not using [] because we don't want to create entries for missing releases
1467 auto set_it = global_release_barriers.find(acquire.handle);
1468 if (set_it != global_release_barriers.end()) {
1469 QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
1470 set_for_handle.erase(acquire);
1471 if (set_for_handle.size() == 0) { // Clean up empty sets
1472 global_release_barriers.erase(set_it);
1473 }
1474 }
1475 }
1476}
1477
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06001478void CoreChecks::RecordQueuedQFOTransfers(CMD_BUFFER_STATE *cb_state) {
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07001479 RecordQueuedQFOTransferBarriers<VkImageMemoryBarrier>(cb_state);
1480 RecordQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(cb_state);
John Zulauf6b4aae82018-05-09 13:03:36 -06001481}
1482
John Zulauf6b4aae82018-05-09 13:03:36 -06001483// Avoid making the template globally visible by exporting the one instance of it we need.
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07001484void CoreChecks::EraseQFOImageRelaseBarriers(const VkImage &image) { EraseQFOReleaseBarriers<VkImageMemoryBarrier>(image); }
John Zulauf6b4aae82018-05-09 13:03:36 -06001485
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06001486void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t memBarrierCount,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07001487 const VkImageMemoryBarrier *pImgMemBarriers) {
Mark Lobodzinski6b6c50a2017-02-27 12:56:14 -07001488 for (uint32_t i = 0; i < memBarrierCount; ++i) {
Petr Krausad0096a2019-08-09 18:35:04 +02001489 const auto &mem_barrier = pImgMemBarriers[i];
Mark Lobodzinski6b6c50a2017-02-27 12:56:14 -07001490
Chris Forbes4de4b132017-08-21 11:27:08 -07001491 // For ownership transfers, the barrier is specified twice; as a release
1492 // operation on the yielding queue family, and as an acquire operation
1493 // on the acquiring queue family. This barrier may also include a layout
1494 // transition, which occurs 'between' the two operations. For validation
1495 // purposes it doesn't seem important which side performs the layout
1496 // transition, but it must not be performed twice. We'll arbitrarily
1497 // choose to perform it as part of the acquire operation.
John Zulauf2be3fe02019-12-30 09:48:02 -07001498 //
1499 // However, we still need to record initial layout for the "initial layout" validation
1500 const bool is_release_op = IsReleaseOp(cb_state, mem_barrier);
Chris Forbes4de4b132017-08-21 11:27:08 -07001501
Petr Krausad0096a2019-08-09 18:35:04 +02001502 auto *image_state = GetImageState(mem_barrier.image);
John Zulauff660ad62019-03-23 07:16:05 -06001503 if (!image_state) continue;
John Zulauf2be3fe02019-12-30 09:48:02 -07001504 RecordTransitionImageLayout(cb_state, image_state, mem_barrier, is_release_op);
Mark Lobodzinski6b6c50a2017-02-27 12:56:14 -07001505 }
1506}
1507
unknown86bcb3a2019-07-11 13:05:36 -06001508void CoreChecks::RecordTransitionImageLayout(CMD_BUFFER_STATE *cb_state, const IMAGE_STATE *image_state,
John Zulauf2be3fe02019-12-30 09:48:02 -07001509 const VkImageMemoryBarrier &mem_barrier, bool is_release_op) {
unknown86bcb3a2019-07-11 13:05:36 -06001510 VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, mem_barrier.subresourceRange);
1511 const auto &image_create_info = image_state->createInfo;
1512
Mike Schuchardt2df08912020-12-15 16:28:09 -08001513 // Special case for 3D images with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT flag bit, where <extent.depth> and
unknown86bcb3a2019-07-11 13:05:36 -06001514 // <arrayLayers> can potentially alias. When recording layout for the entire image, pre-emptively record layouts
1515 // for all (potential) layer sub_resources.
Mike Schuchardt2df08912020-12-15 16:28:09 -08001516 if (0 != (image_create_info.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)) {
unknown86bcb3a2019-07-11 13:05:36 -06001517 normalized_isr.baseArrayLayer = 0;
1518 normalized_isr.layerCount = image_create_info.extent.depth; // Treat each depth slice as a layer subresource
1519 }
1520
Michael Spang8af7c102020-05-03 20:50:09 -04001521 VkImageLayout initial_layout = mem_barrier.oldLayout;
1522
1523 // Layout transitions in external instance are not tracked, so don't validate initial layout.
John Zulaufcea64cb2020-06-10 17:17:27 -06001524 if (QueueFamilyIsExternal(mem_barrier.srcQueueFamilyIndex)) {
Michael Spang8af7c102020-05-03 20:50:09 -04001525 initial_layout = VK_IMAGE_LAYOUT_UNDEFINED;
1526 }
1527
John Zulauf2be3fe02019-12-30 09:48:02 -07001528 if (is_release_op) {
1529 SetImageInitialLayout(cb_state, *image_state, normalized_isr, mem_barrier.oldLayout);
1530 } else {
Michael Spang8af7c102020-05-03 20:50:09 -04001531 SetImageLayout(cb_state, *image_state, normalized_isr, mem_barrier.newLayout, initial_layout);
John Zulauf2be3fe02019-12-30 09:48:02 -07001532 }
unknown86bcb3a2019-07-11 13:05:36 -06001533}
1534
John Zulaufe2b7bcb2019-07-05 16:08:39 -06001535bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
1536 const VkImageSubresourceRange &range, VkImageAspectFlags aspect_mask,
1537 VkImageLayout explicit_layout, VkImageLayout optimal_layout, const char *caller,
1538 const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code, bool *error) const {
Mark Lobodzinski90eea5b2020-05-15 12:54:00 -06001539 if (disabled[image_layout_validation]) return false;
John Zulauff660ad62019-03-23 07:16:05 -06001540 assert(cb_node);
1541 assert(image_state);
Tobin Ehlis2d85ec62017-03-14 15:38:48 -06001542 const auto image = image_state->image;
Mark Lobodzinskibdc3b022017-04-24 09:11:35 -06001543 bool skip = false;
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001544
John Zulauff660ad62019-03-23 07:16:05 -06001545 const auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image);
1546 if (subresource_map) {
1547 bool subres_skip = false;
John Zulauf02a204c2019-04-23 18:52:11 -06001548 LayoutUseCheckAndMessage layout_check(subresource_map, aspect_mask);
Tony Barbour55688172020-09-23 15:19:50 -07001549 // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to
1550 // the next "constant value" range
1551 for (auto pos = subresource_map->Find(range); !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
John Zulauf5e617452019-11-19 14:44:16 -07001552 if (!layout_check.Check(pos->subresource, explicit_layout, pos->current_layout, pos->initial_layout)) {
Tobin Ehlisc8266452017-04-07 12:20:30 -06001553 *error = true;
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001554 subres_skip |= LogError(cb_node->commandBuffer, layout_mismatch_msg_code,
1555 "%s: Cannot use %s (layer=%u mip=%u) with specific layout %s that doesn't match the "
1556 "%s layout %s.",
1557 caller, report_data->FormatHandle(image).c_str(), pos->subresource.arrayLayer,
1558 pos->subresource.mipLevel, string_VkImageLayout(explicit_layout), layout_check.message,
1559 string_VkImageLayout(layout_check.layout));
Tobin Ehlise35b66a2017-03-15 12:18:31 -06001560 }
John Zulauf5e617452019-11-19 14:44:16 -07001561 }
John Zulauff660ad62019-03-23 07:16:05 -06001562 skip |= subres_skip;
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001563 }
John Zulauff660ad62019-03-23 07:16:05 -06001564
Tobin Ehlis2d85ec62017-03-14 15:38:48 -06001565 // If optimal_layout is not UNDEFINED, check that layout matches optimal for this case
1566 if ((VK_IMAGE_LAYOUT_UNDEFINED != optimal_layout) && (explicit_layout != optimal_layout)) {
1567 if (VK_IMAGE_LAYOUT_GENERAL == explicit_layout) {
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001568 if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
1569 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001570 skip |= LogPerformanceWarning(cb_node->commandBuffer, kVUID_Core_DrawState_InvalidImageLayout,
1571 "%s: For optimal performance %s layout should be %s instead of GENERAL.", caller,
1572 report_data->FormatHandle(image).c_str(), string_VkImageLayout(optimal_layout));
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001573 }
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06001574 } else if (device_extensions.vk_khr_shared_presentable_image) {
Mark Lobodzinski087380c2017-05-16 14:42:25 -06001575 if (image_state->shared_presentable) {
1576 if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != explicit_layout) {
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07001577 skip |=
1578 LogError(device, layout_invalid_msg_code,
1579 "%s: Layout for shared presentable image is %s but must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.",
1580 caller, string_VkImageLayout(optimal_layout));
Mark Lobodzinski087380c2017-05-16 14:42:25 -06001581 }
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06001582 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001583 } else {
Tobin Ehlisc8266452017-04-07 12:20:30 -06001584 *error = true;
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001585 skip |= LogError(cb_node->commandBuffer, layout_invalid_msg_code,
1586 "%s: Layout for %s is %s but can only be %s or VK_IMAGE_LAYOUT_GENERAL.", caller,
1587 report_data->FormatHandle(image).c_str(), string_VkImageLayout(explicit_layout),
1588 string_VkImageLayout(optimal_layout));
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001589 }
1590 }
Mark Lobodzinskibdc3b022017-04-24 09:11:35 -06001591 return skip;
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001592}
John Zulaufe2b7bcb2019-07-05 16:08:39 -06001593bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
John Zulauff660ad62019-03-23 07:16:05 -06001594 const VkImageSubresourceLayers &subLayers, VkImageLayout explicit_layout,
1595 VkImageLayout optimal_layout, const char *caller, const char *layout_invalid_msg_code,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06001596 const char *layout_mismatch_msg_code, bool *error) const {
John Zulauff660ad62019-03-23 07:16:05 -06001597 return VerifyImageLayout(cb_node, image_state, RangeFromLayers(subLayers), explicit_layout, optimal_layout, caller,
1598 layout_invalid_msg_code, layout_mismatch_msg_code, error);
1599}
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001600
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06001601void CoreChecks::TransitionFinalSubpassLayouts(CMD_BUFFER_STATE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07001602 FRAMEBUFFER_STATE *framebuffer_state) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001603 auto render_pass = GetRenderPassState(pRenderPassBegin->renderPass);
1604 if (!render_pass) return;
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001605
Mike Schuchardt2df08912020-12-15 16:28:09 -08001606 const VkRenderPassCreateInfo2 *render_pass_info = render_pass->createInfo.ptr();
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001607 if (framebuffer_state) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001608 for (uint32_t i = 0; i < render_pass_info->attachmentCount; ++i) {
locke-lunargfc78e932020-11-19 17:06:24 -07001609 auto *view_state = GetActiveAttachmentImageViewState(pCB, i);
John Zulauf8e308292018-09-21 11:34:37 -06001610 if (view_state) {
Piers Daniell4fde9b72019-11-27 16:19:46 -07001611 VkImageLayout stencil_layout = kInvalidLayout;
1612 const auto *attachment_description_stencil_layout =
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001613 LvlFindInChain<VkAttachmentDescriptionStencilLayout>(render_pass_info->pAttachments[i].pNext);
Piers Daniell4fde9b72019-11-27 16:19:46 -07001614 if (attachment_description_stencil_layout) {
1615 stencil_layout = attachment_description_stencil_layout->stencilFinalLayout;
1616 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001617 SetImageViewLayout(pCB, *view_state, render_pass_info->pAttachments[i].finalLayout, stencil_layout);
John Zulauf8e308292018-09-21 11:34:37 -06001618 }
Mark Lobodzinski3c0f6362017-02-01 13:35:48 -07001619 }
1620 }
1621}
Dave Houltone19e20d2018-02-02 16:32:41 -07001622
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001623#ifdef VK_USE_PLATFORM_ANDROID_KHR
1624// Android-specific validation that uses types defined only with VK_USE_PLATFORM_ANDROID_KHR
1625// This could also move into a seperate core_validation_android.cpp file... ?
1626
1627//
1628// AHB-specific validation within non-AHB APIs
1629//
Jeff Bolz46c0ea02019-10-09 13:06:29 -05001630bool CoreChecks::ValidateCreateImageANDROID(const debug_report_data *report_data, const VkImageCreateInfo *create_info) const {
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001631 bool skip = false;
1632
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001633 const VkExternalFormatANDROID *ext_fmt_android = LvlFindInChain<VkExternalFormatANDROID>(create_info->pNext);
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001634 if (ext_fmt_android) {
Dave Houltond9611312018-11-19 17:03:36 -07001635 if (0 != ext_fmt_android->externalFormat) {
1636 if (VK_FORMAT_UNDEFINED != create_info->format) {
1637 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001638 LogError(device, "VUID-VkImageCreateInfo-pNext-01974",
1639 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with non-zero "
1640 "externalFormat, but the VkImageCreateInfo's format is not VK_FORMAT_UNDEFINED.");
Dave Houltond9611312018-11-19 17:03:36 -07001641 }
1642
1643 if (0 != (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT & create_info->flags)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001644 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02396",
1645 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1646 "non-zero externalFormat, but flags include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
Dave Houltond9611312018-11-19 17:03:36 -07001647 }
1648
1649 if (0 != (~VK_IMAGE_USAGE_SAMPLED_BIT & create_info->usage)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001650 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02397",
1651 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
Spencer Frickef48ad4a2020-04-09 00:07:39 -07001652 "non-zero externalFormat, but usage includes bits (0x%" PRIx64
1653 ") other than VK_IMAGE_USAGE_SAMPLED_BIT.",
1654 create_info->usage);
Dave Houltond9611312018-11-19 17:03:36 -07001655 }
1656
1657 if (VK_IMAGE_TILING_OPTIMAL != create_info->tiling) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001658 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02398",
1659 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1660 "non-zero externalFormat, but layout is not VK_IMAGE_TILING_OPTIMAL.");
Dave Houltond9611312018-11-19 17:03:36 -07001661 }
1662 }
1663
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001664 if ((0 != ext_fmt_android->externalFormat) &&
1665 (ahb_ext_formats_map.find(ext_fmt_android->externalFormat) == ahb_ext_formats_map.end())) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001666 skip |= LogError(device, "VUID-VkExternalFormatANDROID-externalFormat-01894",
Spencer Frickef48ad4a2020-04-09 00:07:39 -07001667 "vkCreateImage(): Chained VkExternalFormatANDROID struct contains a non-zero externalFormat (%" PRIu64
1668 ") which has "
1669 "not been previously retrieved by vkGetAndroidHardwareBufferPropertiesANDROID().",
1670 ext_fmt_android->externalFormat);
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001671 }
1672 }
1673
Dave Houltond9611312018-11-19 17:03:36 -07001674 if ((nullptr == ext_fmt_android) || (0 == ext_fmt_android->externalFormat)) {
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001675 if (VK_FORMAT_UNDEFINED == create_info->format) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001676 skip |=
1677 LogError(device, "VUID-VkImageCreateInfo-pNext-01975",
1678 "vkCreateImage(): VkImageCreateInfo struct's format is VK_FORMAT_UNDEFINED, but either does not have a "
1679 "chained VkExternalFormatANDROID struct or the struct exists but has an externalFormat of 0.");
Dave Houltond9611312018-11-19 17:03:36 -07001680 }
1681 }
1682
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001683 const VkExternalMemoryImageCreateInfo *emici = LvlFindInChain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
Dave Houltond9611312018-11-19 17:03:36 -07001684 if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
1685 if (create_info->imageType != VK_IMAGE_TYPE_2D) {
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00001686 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001687 LogError(device, "VUID-VkImageCreateInfo-pNext-02393",
1688 "vkCreateImage(): VkImageCreateInfo struct with imageType %s has chained VkExternalMemoryImageCreateInfo "
1689 "struct with handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
1690 string_VkImageType(create_info->imageType));
Dave Houltond9611312018-11-19 17:03:36 -07001691 }
1692
1693 if ((create_info->mipLevels != 1) && (create_info->mipLevels != FullMipChainLevels(create_info->extent))) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001694 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02394",
1695 "vkCreateImage(): VkImageCreateInfo struct with chained VkExternalMemoryImageCreateInfo struct of "
1696 "handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID "
1697 "specifies mipLevels = %" PRId32 " (full chain mipLevels are %" PRId32 ").",
1698 create_info->mipLevels, FullMipChainLevels(create_info->extent));
Dave Houltond9611312018-11-19 17:03:36 -07001699 }
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001700 }
1701
1702 return skip;
1703}
1704
Jeff Bolz46c0ea02019-10-09 13:06:29 -05001705bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) const {
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001706 bool skip = false;
Jeff Bolz46c0ea02019-10-09 13:06:29 -05001707 const IMAGE_STATE *image_state = GetImageState(create_info->image);
Dave Houltond3e046d2018-11-28 13:08:09 -07001708
1709 if (image_state->has_ahb_format) {
Dave Houltond9611312018-11-19 17:03:36 -07001710 if (VK_FORMAT_UNDEFINED != create_info->format) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001711 skip |= LogError(create_info->image, "VUID-VkImageViewCreateInfo-image-02399",
1712 "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
Spencer Frickef48ad4a2020-04-09 00:07:39 -07001713 "format member is %s and must be VK_FORMAT_UNDEFINED.",
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001714 string_VkFormat(create_info->format));
Dave Houltond9611312018-11-19 17:03:36 -07001715 }
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001716
Dave Houltond9611312018-11-19 17:03:36 -07001717 // Chain must include a compatible ycbcr conversion
1718 bool conv_found = false;
1719 uint64_t external_format = 0;
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001720 const VkSamplerYcbcrConversionInfo *ycbcr_conv_info = LvlFindInChain<VkSamplerYcbcrConversionInfo>(create_info->pNext);
Dave Houltond9611312018-11-19 17:03:36 -07001721 if (ycbcr_conv_info != nullptr) {
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001722 VkSamplerYcbcrConversion conv_handle = ycbcr_conv_info->conversion;
Mark Lobodzinskib32db312019-04-19 14:01:08 -06001723 if (ycbcr_conversion_ahb_fmt_map.find(conv_handle) != ycbcr_conversion_ahb_fmt_map.end()) {
Dave Houltond9611312018-11-19 17:03:36 -07001724 conv_found = true;
Mark Lobodzinskib32db312019-04-19 14:01:08 -06001725 external_format = ycbcr_conversion_ahb_fmt_map.at(conv_handle);
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001726 }
Dave Houltond9611312018-11-19 17:03:36 -07001727 }
Dave Houltond3e046d2018-11-28 13:08:09 -07001728 if ((!conv_found) || (external_format != image_state->ahb_format)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001729 skip |= LogError(create_info->image, "VUID-VkImageViewCreateInfo-image-02400",
Spencer Frickef48ad4a2020-04-09 00:07:39 -07001730 "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1731 "an externalFormat (%" PRIu64
1732 ") but needs a chained VkSamplerYcbcrConversionInfo struct with a VkSamplerYcbcrConversion created "
1733 "with the same external format.",
1734 image_state->ahb_format);
Dave Houltond9611312018-11-19 17:03:36 -07001735 }
1736
1737 // Errors in create_info swizzles
sfricke-samsungbd0e8052020-06-06 01:36:39 -07001738 if (IsIdentitySwizzle(create_info->components) == false) {
1739 skip |= LogError(
1740 create_info->image, "VUID-VkImageViewCreateInfo-image-02401",
1741 "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
1742 "includes one or more non-identity component swizzles, r swizzle = %s, g swizzle = %s, b swizzle = %s, a swizzle "
1743 "= %s.",
1744 string_VkComponentSwizzle(create_info->components.r), string_VkComponentSwizzle(create_info->components.g),
1745 string_VkComponentSwizzle(create_info->components.b), string_VkComponentSwizzle(create_info->components.a));
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001746 }
1747 }
Dave Houltond9611312018-11-19 17:03:36 -07001748
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001749 return skip;
1750}
1751
John Zulaufa26d3c82019-08-14 16:09:08 -06001752bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const {
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001753 bool skip = false;
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001754
John Zulaufa26d3c82019-08-14 16:09:08 -06001755 const IMAGE_STATE *image_state = GetImageState(image);
sfricke-samsung013f1ef2020-05-14 22:56:20 -07001756 if (image_state != nullptr) {
1757 if (image_state->external_ahb && (0 == image_state->GetBoundMemory().size())) {
1758 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-image-01895",
1759 "vkGetImageSubresourceLayout(): Attempt to query layout from an image created with "
1760 "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType which has not yet been "
1761 "bound to memory.");
1762 }
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001763 }
1764 return skip;
1765}
1766
1767#else
1768
Jeff Bolz46c0ea02019-10-09 13:06:29 -05001769bool CoreChecks::ValidateCreateImageANDROID(const debug_report_data *report_data, const VkImageCreateInfo *create_info) const {
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001770 return false;
1771}
1772
Jeff Bolz46c0ea02019-10-09 13:06:29 -05001773bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) const { return false; }
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001774
John Zulaufa26d3c82019-08-14 16:09:08 -06001775bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const { return false; }
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001776
1777#endif // VK_USE_PLATFORM_ANDROID_KHR
1778
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001779bool CoreChecks::ValidateImageFormatFeatures(const VkImageCreateInfo *pCreateInfo) const {
1780 bool skip = false;
1781
1782 // validates based on imageCreateFormatFeatures from vkspec.html#resources-image-creation-limits
1783 VkFormatFeatureFlags tiling_features = VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM;
1784 const VkImageTiling image_tiling = pCreateInfo->tiling;
1785 const VkFormat image_format = pCreateInfo->format;
1786
1787 if (image_format == VK_FORMAT_UNDEFINED) {
1788 // VU 01975 states format can't be undefined unless an android externalFormat
1789#ifdef VK_USE_PLATFORM_ANDROID_KHR
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001790 const VkExternalFormatANDROID *ext_fmt_android = LvlFindInChain<VkExternalFormatANDROID>(pCreateInfo->pNext);
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001791 if ((image_tiling == VK_IMAGE_TILING_OPTIMAL) && (ext_fmt_android != nullptr) && (0 != ext_fmt_android->externalFormat)) {
1792 auto it = ahb_ext_formats_map.find(ext_fmt_android->externalFormat);
1793 if (it != ahb_ext_formats_map.end()) {
1794 tiling_features = it->second;
1795 }
1796 }
1797#endif
1798 } else if (image_tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
1799 uint64_t drm_format_modifier = 0;
1800 const VkImageDrmFormatModifierExplicitCreateInfoEXT *drm_explicit =
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001801 LvlFindInChain<VkImageDrmFormatModifierExplicitCreateInfoEXT>(pCreateInfo->pNext);
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001802 const VkImageDrmFormatModifierListCreateInfoEXT *drm_implicit =
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001803 LvlFindInChain<VkImageDrmFormatModifierListCreateInfoEXT>(pCreateInfo->pNext);
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001804
1805 if (drm_explicit != nullptr) {
1806 drm_format_modifier = drm_explicit->drmFormatModifier;
1807 } else {
1808 // VUID 02261 makes sure its only explict or implict in parameter checking
1809 assert(drm_implicit != nullptr);
1810 for (uint32_t i = 0; i < drm_implicit->drmFormatModifierCount; i++) {
1811 drm_format_modifier |= drm_implicit->pDrmFormatModifiers[i];
1812 }
1813 }
1814
1815 VkFormatProperties2 format_properties_2 = {VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, nullptr};
1816 VkDrmFormatModifierPropertiesListEXT drm_properties_list = {VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
1817 nullptr};
1818 format_properties_2.pNext = (void *)&drm_properties_list;
1819 DispatchGetPhysicalDeviceFormatProperties2(physical_device, image_format, &format_properties_2);
Lionel Landwerlin09351a72020-06-22 18:15:59 +03001820 std::vector<VkDrmFormatModifierPropertiesEXT> drm_properties;
1821 drm_properties.resize(drm_properties_list.drmFormatModifierCount);
1822 drm_properties_list.pDrmFormatModifierProperties = &drm_properties[0];
1823 DispatchGetPhysicalDeviceFormatProperties2(physical_device, image_format, &format_properties_2);
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001824
1825 for (uint32_t i = 0; i < drm_properties_list.drmFormatModifierCount; i++) {
1826 if ((drm_properties_list.pDrmFormatModifierProperties[i].drmFormatModifier & drm_format_modifier) != 0) {
1827 tiling_features |= drm_properties_list.pDrmFormatModifierProperties[i].drmFormatModifierTilingFeatures;
1828 }
1829 }
1830 } else {
1831 VkFormatProperties format_properties = GetPDFormatProperties(image_format);
1832 tiling_features = (image_tiling == VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
1833 : format_properties.optimalTilingFeatures;
1834 }
1835
Spencer Fricke3c2a8232020-04-19 18:47:25 -07001836 // Lack of disjoint format feature support while using the flag
1837 if (FormatIsMultiplane(image_format) && ((pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0) &&
1838 ((tiling_features & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0)) {
1839 skip |= LogError(device, "VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260",
1840 "vkCreateImage(): can't use VK_IMAGE_CREATE_DISJOINT_BIT because %s doesn't support "
1841 "VK_FORMAT_FEATURE_DISJOINT_BIT based on imageCreateFormatFeatures.",
1842 string_VkFormat(pCreateInfo->format));
1843 }
Spencer Fricke6bba8c72020-04-06 07:41:21 -07001844
1845 return skip;
1846}
1847
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07001848bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
Jeff Bolz5c801d12019-10-09 10:38:45 -05001849 const VkAllocationCallbacks *pAllocator, VkImage *pImage) const {
Mark Lobodzinskibdc3b022017-04-24 09:11:35 -06001850 bool skip = false;
Mark Lobodzinski90224de2017-01-26 15:23:11 -07001851
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06001852 if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
Mark Lobodzinskie9b99792019-03-07 16:34:29 -07001853 skip |= ValidateCreateImageANDROID(report_data, pCreateInfo);
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001854 } else { // These checks are omitted or replaced when Android HW Buffer extension is active
1855 if (pCreateInfo->format == VK_FORMAT_UNDEFINED) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001856 return LogError(device, "VUID-VkImageCreateInfo-format-00943",
1857 "vkCreateImage(): VkFormat for image must not be VK_FORMAT_UNDEFINED.");
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06001858 }
Jeremy Hayes96dcd812017-03-14 14:04:19 -06001859 }
1860
Mark Lobodzinskidef4c092019-06-18 13:08:01 -06001861 if (pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
1862 if (VK_IMAGE_TYPE_2D != pCreateInfo->imageType) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001863 skip |= LogError(device, "VUID-VkImageCreateInfo-flags-00949",
1864 "vkCreateImage(): Image type must be VK_IMAGE_TYPE_2D when VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT "
1865 "flag bit is set");
Mark Lobodzinskidef4c092019-06-18 13:08:01 -06001866 }
1867
1868 if ((pCreateInfo->extent.width != pCreateInfo->extent.height) || (pCreateInfo->arrayLayers < 6)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001869 skip |= LogError(device, "VUID-VkImageCreateInfo-imageType-00954",
1870 "vkCreateImage(): If VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT flag bit is set, width (%d) must equal "
1871 "height (%d) and arrayLayers (%d) must be >= 6.",
1872 pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->arrayLayers);
Mark Lobodzinskidef4c092019-06-18 13:08:01 -06001873 }
Dave Houlton130c0212018-01-29 13:39:56 -07001874 }
Mark Lobodzinski90224de2017-01-26 15:23:11 -07001875
Mark Lobodzinski79b5d5b2019-04-19 12:27:10 -06001876 const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
Dave Houlton130c0212018-01-29 13:39:56 -07001877 VkImageUsageFlags attach_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
1878 VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1879 if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.width > device_limits->maxFramebufferWidth)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001880 skip |= LogError(device, "VUID-VkImageCreateInfo-usage-00964",
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08001881 "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image width (%u) exceeds "
1882 "device maxFramebufferWidth (%u).",
1883 pCreateInfo->extent.width, device_limits->maxFramebufferWidth);
Dave Houlton130c0212018-01-29 13:39:56 -07001884 }
1885
1886 if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.height > device_limits->maxFramebufferHeight)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001887 skip |= LogError(device, "VUID-VkImageCreateInfo-usage-00965",
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08001888 "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image height (%u) exceeds "
1889 "device maxFramebufferHeight (%u).",
1890 pCreateInfo->extent.height, device_limits->maxFramebufferHeight);
Dave Houlton130c0212018-01-29 13:39:56 -07001891 }
1892
janharaldfredriksen-arm36e17572020-07-07 13:59:28 +02001893 if (device_extensions.vk_ext_fragment_density_map || device_extensions.vk_ext_fragment_density_map_2) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001894 uint32_t ceiling_width = static_cast<uint32_t>(ceil(
1895 static_cast<float>(device_limits->maxFramebufferWidth) /
1896 std::max(static_cast<float>(phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width), 1.0f)));
ByumjinConffx991b6062019-08-14 15:17:53 -07001897 if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.width > ceiling_width)) {
1898 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001899 LogError(device, "VUID-VkImageCreateInfo-usage-02559",
1900 "vkCreateImage(): Image usage flags include a fragment density map bit and image width (%u) exceeds the "
1901 "ceiling of device "
1902 "maxFramebufferWidth (%u) / minFragmentDensityTexelSize.width (%u). The ceiling value: %u",
1903 pCreateInfo->extent.width, device_limits->maxFramebufferWidth,
1904 phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width, ceiling_width);
ByumjinConffx991b6062019-08-14 15:17:53 -07001905 }
1906
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001907 uint32_t ceiling_height = static_cast<uint32_t>(ceil(
1908 static_cast<float>(device_limits->maxFramebufferHeight) /
1909 std::max(static_cast<float>(phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height), 1.0f)));
ByumjinConffx991b6062019-08-14 15:17:53 -07001910 if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.height > ceiling_height)) {
1911 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001912 LogError(device, "VUID-VkImageCreateInfo-usage-02560",
1913 "vkCreateImage(): Image usage flags include a fragment density map bit and image height (%u) exceeds the "
1914 "ceiling of device "
1915 "maxFramebufferHeight (%u) / minFragmentDensityTexelSize.height (%u). The ceiling value: %u",
1916 pCreateInfo->extent.height, device_limits->maxFramebufferHeight,
1917 phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height, ceiling_height);
ByumjinConffx991b6062019-08-14 15:17:53 -07001918 }
1919 }
1920
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00001921 VkImageFormatProperties format_limits = {};
Mark Lobodzinskib8d149f2019-10-02 16:42:32 -06001922 VkResult result = VK_SUCCESS;
1923 if (pCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
1924 result = DispatchGetPhysicalDeviceImageFormatProperties(physical_device, pCreateInfo->format, pCreateInfo->imageType,
1925 pCreateInfo->tiling, pCreateInfo->usage, pCreateInfo->flags,
1926 &format_limits);
1927 } else {
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001928 auto modifier_list = LvlFindInChain<VkImageDrmFormatModifierListCreateInfoEXT>(pCreateInfo->pNext);
1929 auto explicit_modifier = LvlFindInChain<VkImageDrmFormatModifierExplicitCreateInfoEXT>(pCreateInfo->pNext);
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001930 if (modifier_list) {
1931 for (uint32_t i = 0; i < modifier_list->drmFormatModifierCount; i++) {
Mark Lobodzinski6fe9e702020-12-30 15:36:39 -07001932 auto drm_format_modifier = LvlInitStruct<VkPhysicalDeviceImageDrmFormatModifierInfoEXT>();
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001933 drm_format_modifier.drmFormatModifier = modifier_list->pDrmFormatModifiers[i];
Mark Lobodzinski6fe9e702020-12-30 15:36:39 -07001934 auto image_format_info = LvlInitStruct<VkPhysicalDeviceImageFormatInfo2>(&drm_format_modifier);
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001935 image_format_info.type = pCreateInfo->imageType;
1936 image_format_info.format = pCreateInfo->format;
1937 image_format_info.tiling = pCreateInfo->tiling;
1938 image_format_info.usage = pCreateInfo->usage;
1939 image_format_info.flags = pCreateInfo->flags;
Mark Lobodzinski6fe9e702020-12-30 15:36:39 -07001940 auto image_format_properties = LvlInitStruct<VkImageFormatProperties2>();
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001941
1942 result =
1943 DispatchGetPhysicalDeviceImageFormatProperties2(physical_device, &image_format_info, &image_format_properties);
1944 format_limits = image_format_properties.imageFormatProperties;
1945
1946 /* The application gives a list of modifier and the driver
1947 * selects one. If one is wrong, stop there.
1948 */
1949 if (result != VK_SUCCESS) break;
1950 }
1951 } else if (explicit_modifier) {
Mark Lobodzinski6fe9e702020-12-30 15:36:39 -07001952 auto drm_format_modifier = LvlInitStruct<VkPhysicalDeviceImageDrmFormatModifierInfoEXT>();
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001953 drm_format_modifier.drmFormatModifier = explicit_modifier->drmFormatModifier;
Mark Lobodzinski6fe9e702020-12-30 15:36:39 -07001954 auto image_format_info = LvlInitStruct<VkPhysicalDeviceImageFormatInfo2>(&drm_format_modifier);
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001955 image_format_info.type = pCreateInfo->imageType;
1956 image_format_info.format = pCreateInfo->format;
1957 image_format_info.tiling = pCreateInfo->tiling;
1958 image_format_info.usage = pCreateInfo->usage;
1959 image_format_info.flags = pCreateInfo->flags;
Mark Lobodzinski6fe9e702020-12-30 15:36:39 -07001960 auto image_format_properties = LvlInitStruct<VkImageFormatProperties2>();
Lionel Landwerlind8b1aa12020-06-22 21:22:05 +03001961
1962 result = DispatchGetPhysicalDeviceImageFormatProperties2(physical_device, &image_format_info, &image_format_properties);
1963 format_limits = image_format_properties.imageFormatProperties;
1964 }
Mark Lobodzinskib8d149f2019-10-02 16:42:32 -06001965 }
Mark Lobodzinski41dc7a82019-10-02 16:02:13 -06001966
sfricke-samsunga6d30f62020-06-20 20:22:00 -07001967 // 1. vkGetPhysicalDeviceImageFormatProperties[2] only success code is VK_SUCCESS
1968 // 2. If call returns an error, then "imageCreateImageFormatPropertiesList" is defined to be the empty list
1969 // 3. All values in 02251 are undefined if "imageCreateImageFormatPropertiesList" is empty.
1970 if (result != VK_SUCCESS) {
1971 // External memory will always have a "imageCreateImageFormatPropertiesList" so skip
Lockee87f87c2019-04-23 17:53:10 -06001972#ifdef VK_USE_PLATFORM_ANDROID_KHR
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07001973 if (!LvlFindInChain<VkExternalFormatANDROID>(pCreateInfo->pNext)) {
Lockee87f87c2019-04-23 17:53:10 -06001974#endif // VK_USE_PLATFORM_ANDROID_KHR
sfricke-samsunga6d30f62020-06-20 20:22:00 -07001975 skip |= LogError(device, "VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251",
Spencer Frickec46fc6d2020-04-16 06:23:05 -07001976 "vkCreateImage(): Format %s is not supported for this combination of parameters and "
sfricke-samsunga6d30f62020-06-20 20:22:00 -07001977 "VkGetPhysicalDeviceImageFormatProperties returned back %s.",
1978 string_VkFormat(pCreateInfo->format), string_VkResult(result));
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001979#ifdef VK_USE_PLATFORM_ANDROID_KHR
1980 }
1981#endif // VK_USE_PLATFORM_ANDROID_KHR
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00001982 } else {
1983 if (pCreateInfo->mipLevels > format_limits.maxMipLevels) {
1984 const char *format_string = string_VkFormat(pCreateInfo->format);
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07001985 skip |= LogError(device, "VUID-VkImageCreateInfo-mipLevels-02255",
1986 "vkCreateImage(): Image mip levels=%d exceed image format maxMipLevels=%d for format %s.",
1987 pCreateInfo->mipLevels, format_limits.maxMipLevels, format_string);
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00001988 }
Dave Houlton130c0212018-01-29 13:39:56 -07001989
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001990 uint64_t texel_count = static_cast<uint64_t>(pCreateInfo->extent.width) *
1991 static_cast<uint64_t>(pCreateInfo->extent.height) *
1992 static_cast<uint64_t>(pCreateInfo->extent.depth) * static_cast<uint64_t>(pCreateInfo->arrayLayers) *
1993 static_cast<uint64_t>(pCreateInfo->samples);
1994 uint64_t total_size =
1995 static_cast<uint64_t>(std::ceil(FormatTexelSize(pCreateInfo->format) * static_cast<double>(texel_count)));
Dave Houlton130c0212018-01-29 13:39:56 -07001996
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00001997 // Round up to imageGranularity boundary
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001998 VkDeviceSize image_granularity = phys_dev_props.limits.bufferImageGranularity;
1999 uint64_t ig_mask = image_granularity - 1;
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00002000 total_size = (total_size + ig_mask) & ~ig_mask;
Mark Lobodzinski90224de2017-01-26 15:23:11 -07002001
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00002002 if (total_size > format_limits.maxResourceSize) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002003 skip |= LogWarning(device, kVUID_Core_Image_InvalidFormatLimitsViolation,
2004 "vkCreateImage(): resource size exceeds allowable maximum Image resource size = 0x%" PRIxLEAST64
2005 ", maximum resource size = 0x%" PRIxLEAST64 " ",
2006 total_size, format_limits.maxResourceSize);
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00002007 }
Mark Lobodzinski90224de2017-01-26 15:23:11 -07002008
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00002009 if (pCreateInfo->arrayLayers > format_limits.maxArrayLayers) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002010 skip |= LogError(device, "VUID-VkImageCreateInfo-arrayLayers-02256",
2011 "vkCreateImage(): arrayLayers=%d exceeds allowable maximum supported by format of %d.",
2012 pCreateInfo->arrayLayers, format_limits.maxArrayLayers);
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00002013 }
2014
2015 if ((pCreateInfo->samples & format_limits.sampleCounts) == 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002016 skip |= LogError(device, "VUID-VkImageCreateInfo-samples-02258",
2017 "vkCreateImage(): samples %s is not supported by format 0x%.8X.",
2018 string_VkSampleCountFlagBits(pCreateInfo->samples), format_limits.sampleCounts);
Graeme Leese2cd2a1f2018-11-19 15:11:45 +00002019 }
sfricke-samsung612f3622020-06-20 20:42:46 -07002020
2021 if (pCreateInfo->extent.width > format_limits.maxExtent.width) {
2022 skip |= LogError(device, "VUID-VkImageCreateInfo-extent-02252",
2023 "vkCreateImage(): extent.width %u exceeds allowable maximum image extent width %u.",
2024 pCreateInfo->extent.width, format_limits.maxExtent.width);
2025 }
2026
2027 if (pCreateInfo->extent.height > format_limits.maxExtent.height) {
2028 skip |= LogError(device, "VUID-VkImageCreateInfo-extent-02253",
2029 "vkCreateImage(): extent.height %u exceeds allowable maximum image extent height %u.",
2030 pCreateInfo->extent.height, format_limits.maxExtent.height);
2031 }
2032
2033 if (pCreateInfo->extent.depth > format_limits.maxExtent.depth) {
2034 skip |= LogError(device, "VUID-VkImageCreateInfo-extent-02254",
2035 "vkCreateImage(): extent.depth %u exceeds allowable maximum image extent depth %u.",
2036 pCreateInfo->extent.depth, format_limits.maxExtent.depth);
2037 }
Mark Lobodzinski90224de2017-01-26 15:23:11 -07002038 }
2039
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002040 // Tests for "Formats requiring sampler YCBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views"
sfricke-samsungcead0802020-01-30 22:20:10 -08002041 if (FormatRequiresYcbcrConversion(pCreateInfo->format)) {
2042 if (!enabled_features.ycbcr_image_array_features.ycbcrImageArrays && pCreateInfo->arrayLayers != 1) {
2043 const char *error_vuid = (device_extensions.vk_ext_ycbcr_image_arrays) ? "VUID-VkImageCreateInfo-format-02653"
2044 : "VUID-VkImageCreateInfo-format-02564";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002045 skip |= LogError(device, error_vuid,
2046 "vkCreateImage(): arrayLayers = %d, but when the ycbcrImagesArrays feature is not enabled and using a "
2047 "YCbCr Conversion format, arrayLayers must be 1",
2048 pCreateInfo->arrayLayers);
sfricke-samsungcead0802020-01-30 22:20:10 -08002049 }
2050
2051 if (pCreateInfo->mipLevels != 1) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002052 skip |= LogError(device, "VUID-VkImageCreateInfo-format-02561",
2053 "vkCreateImage(): mipLevels = %d, but when using a YCbCr Conversion format, mipLevels must be 1",
2054 pCreateInfo->arrayLayers);
sfricke-samsungcead0802020-01-30 22:20:10 -08002055 }
2056
2057 if (pCreateInfo->samples != VK_SAMPLE_COUNT_1_BIT) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002058 skip |= LogError(
2059 device, "VUID-VkImageCreateInfo-format-02562",
sfricke-samsungcead0802020-01-30 22:20:10 -08002060 "vkCreateImage(): samples = %s, but when using a YCbCr Conversion format, samples must be VK_SAMPLE_COUNT_1_BIT",
2061 string_VkSampleCountFlagBits(pCreateInfo->samples));
2062 }
2063
2064 if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002065 skip |= LogError(
2066 device, "VUID-VkImageCreateInfo-format-02563",
sfricke-samsungcead0802020-01-30 22:20:10 -08002067 "vkCreateImage(): imageType = %s, but when using a YCbCr Conversion format, imageType must be VK_IMAGE_TYPE_2D ",
2068 string_VkImageType(pCreateInfo->imageType));
2069 }
2070 }
2071
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06002072 if (device_extensions.vk_khr_maintenance2) {
Spencer Fricke48db59b2020-03-23 10:31:46 -07002073 if (pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) {
sfricke-samsungb764f092020-05-25 15:05:36 -07002074 if (!(FormatIsCompressed_BC(pCreateInfo->format) || FormatIsCompressed_ASTC(pCreateInfo->format) ||
Lenny Komowb79f04a2017-09-18 17:07:00 -06002075 FormatIsCompressed_ETC2_EAC(pCreateInfo->format))) {
Spencer Fricke48db59b2020-03-23 10:31:46 -07002076 skip |= LogError(device, "VUID-VkImageCreateInfo-flags-01572",
2077 "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, "
2078 "format must be block, ETC or ASTC compressed, but is %s",
2079 string_VkFormat(pCreateInfo->format));
Lenny Komowb79f04a2017-09-18 17:07:00 -06002080 }
2081 if (!(pCreateInfo->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) {
Spencer Fricke48db59b2020-03-23 10:31:46 -07002082 skip |= LogError(device, "VUID-VkImageCreateInfo-flags-01573",
2083 "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, "
2084 "flags must also contain VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
Lenny Komowb79f04a2017-09-18 17:07:00 -06002085 }
2086 }
2087 }
2088
Mark Lobodzinski08ee03c2019-02-04 10:57:47 -07002089 if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
Mark Lobodzinski314b9162020-07-16 15:33:08 -06002090 skip |= ValidatePhysicalDeviceQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
2091 "vkCreateImage", "pCreateInfo->pQueueFamilyIndices",
2092 "VUID-VkImageCreateInfo-sharingMode-01420");
Mark Lobodzinski08ee03c2019-02-04 10:57:47 -07002093 }
2094
unknown2c877272019-07-11 12:56:50 -06002095 if (!FormatIsMultiplane(pCreateInfo->format) && !(pCreateInfo->flags & VK_IMAGE_CREATE_ALIAS_BIT) &&
2096 (pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT)) {
2097 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002098 LogError(device, "VUID-VkImageCreateInfo-format-01577",
2099 "vkCreateImage(): format is %s and flags are %s. The flags should not include VK_IMAGE_CREATE_DISJOINT_BIT.",
2100 string_VkFormat(pCreateInfo->format), string_VkImageCreateFlags(pCreateInfo->flags).c_str());
unknown2c877272019-07-11 12:56:50 -06002101 }
Spencer Fricke6bba8c72020-04-06 07:41:21 -07002102
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07002103 const auto swapchain_create_info = LvlFindInChain<VkImageSwapchainCreateInfoKHR>(pCreateInfo->pNext);
sfricke-samsungddaf72b2020-06-23 21:39:28 -07002104 if (swapchain_create_info != nullptr) {
2105 if (swapchain_create_info->swapchain != VK_NULL_HANDLE) {
2106 const SWAPCHAIN_NODE *swapchain_state = GetSwapchainState(swapchain_create_info->swapchain);
2107 const VkSwapchainCreateFlagsKHR swapchain_flags = swapchain_state->createInfo.flags;
2108
2109 // Validate rest of Swapchain Image create check that require swapchain state
2110 const char *vuid = "VUID-VkImageSwapchainCreateInfoKHR-swapchain-00995";
2111 if (((swapchain_flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR) != 0) &&
2112 ((pCreateInfo->flags & VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT) == 0)) {
2113 skip |= LogError(
2114 device, vuid,
2115 "vkCreateImage(): Swapchain was created with VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR flag so "
2116 "all swapchain images must have the VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT flag set.");
2117 }
2118 if (((swapchain_flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) != 0) &&
2119 ((pCreateInfo->flags & VK_IMAGE_CREATE_PROTECTED_BIT) == 0)) {
2120 skip |= LogError(device, vuid,
2121 "vkCreateImage(): Swapchain was created with VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR flag so all "
2122 "swapchain images must have the VK_IMAGE_CREATE_PROTECTED_BIT flag set.");
2123 }
Mike Schuchardt2df08912020-12-15 16:28:09 -08002124 const VkImageCreateFlags mutable_flags = (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT);
sfricke-samsungddaf72b2020-06-23 21:39:28 -07002125 if (((swapchain_flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) != 0) &&
2126 ((pCreateInfo->flags & mutable_flags) != mutable_flags)) {
2127 skip |= LogError(device, vuid,
2128 "vkCreateImage(): Swapchain was created with VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR flag so "
2129 "all swapchain images must have the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT and "
Mike Schuchardt2df08912020-12-15 16:28:09 -08002130 "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT flags both set.");
sfricke-samsungddaf72b2020-06-23 21:39:28 -07002131 }
2132 }
2133 }
2134
sfricke-samsungedce77a2020-07-03 22:35:13 -07002135 if ((pCreateInfo->flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0) {
2136 if (enabled_features.core11.protectedMemory == VK_FALSE) {
2137 skip |= LogError(device, "VUID-VkImageCreateInfo-flags-01890",
2138 "vkCreateImage(): the protectedMemory device feature is disabled: Images cannot be created with the "
2139 "VK_IMAGE_CREATE_PROTECTED_BIT set.");
2140 }
2141 const VkImageCreateFlags invalid_flags =
2142 VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT;
2143 if ((pCreateInfo->flags & invalid_flags) != 0) {
2144 skip |= LogError(device, "VUID-VkImageCreateInfo-None-01891",
2145 "vkCreateImage(): VK_IMAGE_CREATE_PROTECTED_BIT is set so no sparse create flags can be used at same "
2146 "time (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | "
2147 "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT).");
2148 }
2149 }
2150
Spencer Fricke6bba8c72020-04-06 07:41:21 -07002151 skip |= ValidateImageFormatFeatures(pCreateInfo);
2152
Nathaniel Cesarioc02c2512020-11-13 12:04:24 -07002153 // Check compatibility with VK_KHR_portability_subset
2154 if (ExtEnabled::kNotEnabled != device_extensions.vk_khr_portability_subset) {
2155 if (VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT & pCreateInfo->flags &&
2156 VK_FALSE == enabled_features.portability_subset_features.imageView2DOn3DImage) {
2157 skip |= LogError(device, "VUID-VkImageCreateInfo-imageView2DOn3DImage-04459",
2158 "vkCreateImage (portability error): VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT is not supported.");
2159 }
2160 if ((VK_SAMPLE_COUNT_1_BIT != pCreateInfo->samples) && (1 != pCreateInfo->arrayLayers) &&
2161 (VK_FALSE == enabled_features.portability_subset_features.multisampleArrayImage)) {
2162 skip |=
2163 LogError(device, "VUID-VkImageCreateInfo-multisampleArrayImage-04460",
2164 "vkCreateImage (portability error): Cannot create an image with samples/texel > 1 && arrayLayers != 1");
2165 }
2166 }
2167
Mark Lobodzinskibdc3b022017-04-24 09:11:35 -06002168 return skip;
Mark Lobodzinski90224de2017-01-26 15:23:11 -07002169}
2170
John Zulauf7eeb6f72019-06-17 11:56:36 -06002171void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
2172 const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) {
2173 if (VK_SUCCESS != result) return;
2174
2175 StateTracker::PostCallRecordCreateImage(device, pCreateInfo, pAllocator, pImage, result);
locke-lunarg20699892020-01-02 19:17:29 -07002176 auto image_state = Get<IMAGE_STATE>(*pImage);
2177 AddInitialLayoutintoImageLayoutMap(*image_state, imageLayoutMap);
Mark Lobodzinski42fe5f72017-01-11 11:36:16 -07002178}
Mark Lobodzinski9ef5d562017-01-27 12:28:30 -07002179
Jeff Bolz5c801d12019-10-09 10:38:45 -05002180bool CoreChecks::PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) const {
Jeff Bolz46c0ea02019-10-09 13:06:29 -05002181 const IMAGE_STATE *image_state = GetImageState(image);
John Zulauf4fea6622019-04-01 11:38:18 -06002182 const VulkanTypedHandle obj_struct(image, kVulkanObjectTypeImage);
Mark Lobodzinski9ef5d562017-01-27 12:28:30 -07002183 bool skip = false;
Mark Lobodzinski6b35c8a2019-01-10 10:57:27 -07002184 if (image_state) {
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07002185 skip |= ValidateObjectNotInUse(image_state, obj_struct, "vkDestroyImage", "VUID-vkDestroyImage-image-01000");
Mark Lobodzinski9ef5d562017-01-27 12:28:30 -07002186 }
2187 return skip;
2188}
2189
John Zulauf7eeb6f72019-06-17 11:56:36 -06002190void CoreChecks::PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
2191 // Clean up validation specific data
2192 EraseQFOReleaseBarriers<VkImageMemoryBarrier>(image);
Mark Lobodzinski9ef5d562017-01-27 12:28:30 -07002193
locke-lunargcba7d5f2019-12-30 16:59:11 -07002194 imageLayoutMap.erase(image);
John Zulauf7eeb6f72019-06-17 11:56:36 -06002195
2196 // Clean up generic image state
2197 StateTracker::PreCallRecordDestroyImage(device, image, pAllocator);
Mark Lobodzinski9ef5d562017-01-27 12:28:30 -07002198}
Mark Lobodzinskic409a582017-01-27 15:16:01 -07002199
sfricke-samsungcd924d92020-05-20 23:51:17 -07002200bool CoreChecks::ValidateImageAttributes(const IMAGE_STATE *image_state, const VkImageSubresourceRange &range,
2201 const char *param_name) const {
Mark Lobodzinskic409a582017-01-27 15:16:01 -07002202 bool skip = false;
sfricke-samsungcd924d92020-05-20 23:51:17 -07002203 const VkImage image = image_state->image;
2204 const VkFormat format = image_state->createInfo.format;
Mark Lobodzinskic409a582017-01-27 15:16:01 -07002205
2206 if (range.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
sfricke-samsungcd924d92020-05-20 23:51:17 -07002207 skip |= LogError(image, "VUID-vkCmdClearColorImage-aspectMask-02498",
2208 "vkCmdClearColorImage(): %s.aspectMasks must only be set to VK_IMAGE_ASPECT_COLOR_BIT.", param_name);
Mark Lobodzinskic409a582017-01-27 15:16:01 -07002209 }
2210
sfricke-samsungcd924d92020-05-20 23:51:17 -07002211 if (FormatIsDepthOrStencil(format)) {
2212 skip |= LogError(image, "VUID-vkCmdClearColorImage-image-00007",
2213 "vkCmdClearColorImage(): %s called with image %s which has a depth/stencil format (%s).", param_name,
2214 report_data->FormatHandle(image).c_str(), string_VkFormat(format));
2215 } else if (FormatIsCompressed(format)) {
2216 skip |= LogError(image, "VUID-vkCmdClearColorImage-image-00007",
2217 "vkCmdClearColorImage(): %s called with image %s which has a compressed format (%s).", param_name,
2218 report_data->FormatHandle(image).c_str(), string_VkFormat(format));
Mark Lobodzinskic409a582017-01-27 15:16:01 -07002219 }
2220
2221 if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
sfricke-samsungcd924d92020-05-20 23:51:17 -07002222 skip |=
2223 LogError(image, "VUID-vkCmdClearColorImage-image-00002",
2224 "vkCmdClearColorImage() %s called with image %s which was created without VK_IMAGE_USAGE_TRANSFER_DST_BIT.",
2225 param_name, report_data->FormatHandle(image).c_str());
Mark Lobodzinskic409a582017-01-27 15:16:01 -07002226 }
2227 return skip;
2228}
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002229
John Zulauf07288512019-07-05 11:09:50 -06002230bool CoreChecks::VerifyClearImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
2231 const VkImageSubresourceRange &range, VkImageLayout dest_image_layout,
2232 const char *func_name) const {
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002233 bool skip = false;
Mark Lobodzinskia4651ba2019-12-18 12:57:46 -07002234 if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
2235 if ((dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) && (dest_image_layout != VK_IMAGE_LAYOUT_GENERAL)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002236 skip |= LogError(image_state->image, "VUID-vkCmdClearDepthStencilImage-imageLayout-00012",
2237 "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL.", func_name,
2238 string_VkImageLayout(dest_image_layout));
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002239 }
Mark Lobodzinskia4651ba2019-12-18 12:57:46 -07002240
2241 } else {
2242 assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
2243 if (!device_extensions.vk_khr_shared_presentable_image) {
2244 if ((dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) && (dest_image_layout != VK_IMAGE_LAYOUT_GENERAL)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002245 skip |= LogError(image_state->image, "VUID-vkCmdClearColorImage-imageLayout-00005",
2246 "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL.", func_name,
2247 string_VkImageLayout(dest_image_layout));
Mark Lobodzinskia4651ba2019-12-18 12:57:46 -07002248 }
2249 } else {
2250 if ((dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) && (dest_image_layout != VK_IMAGE_LAYOUT_GENERAL) &&
2251 (dest_image_layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002252 skip |= LogError(
2253 image_state->image, "VUID-vkCmdClearColorImage-imageLayout-01394",
Mark Lobodzinskia4651ba2019-12-18 12:57:46 -07002254 "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL, SHARED_PRESENT_KHR, or GENERAL.",
2255 func_name, string_VkImageLayout(dest_image_layout));
2256 }
2257 }
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002258 }
2259
John Zulauff660ad62019-03-23 07:16:05 -06002260 // Cast to const to prevent creation at validate time.
John Zulauf07288512019-07-05 11:09:50 -06002261 const auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state->image);
John Zulauff660ad62019-03-23 07:16:05 -06002262 if (subresource_map) {
2263 bool subres_skip = false;
John Zulauf02a204c2019-04-23 18:52:11 -06002264 LayoutUseCheckAndMessage layout_check(subresource_map);
John Zulauff660ad62019-03-23 07:16:05 -06002265 VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, range);
Tony Barbour55688172020-09-23 15:19:50 -07002266 // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to
2267 // the next "constant value" range
2268 for (auto pos = subresource_map->Find(normalized_isr); !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
John Zulauf5e617452019-11-19 14:44:16 -07002269 if (!layout_check.Check(pos->subresource, dest_image_layout, pos->current_layout, pos->initial_layout)) {
John Zulauff660ad62019-03-23 07:16:05 -06002270 const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
2271 if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
2272 error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
2273 } else {
2274 assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002275 }
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002276 subres_skip |= LogError(cb_node->commandBuffer, error_code,
2277 "%s: Cannot clear an image whose layout is %s and doesn't match the %s layout %s.",
2278 func_name, string_VkImageLayout(dest_image_layout), layout_check.message,
2279 string_VkImageLayout(layout_check.layout));
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002280 }
John Zulauf5e617452019-11-19 14:44:16 -07002281 }
John Zulauff660ad62019-03-23 07:16:05 -06002282 skip |= subres_skip;
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002283 }
2284
2285 return skip;
2286}
2287
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07002288bool CoreChecks::PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2289 const VkClearColorValue *pColor, uint32_t rangeCount,
Jeff Bolz5c801d12019-10-09 10:38:45 -05002290 const VkImageSubresourceRange *pRanges) const {
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002291 bool skip = false;
2292 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
John Zulauf07288512019-07-05 11:09:50 -06002293 const auto *cb_node = GetCBState(commandBuffer);
2294 const auto *image_state = GetImageState(image);
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002295 if (cb_node && image_state) {
Mark Lobodzinski0ebe9712019-03-07 13:39:07 -07002296 skip |= ValidateMemoryIsBoundToImage(image_state, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-image-00003");
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07002297 skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearColorImage()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
Dave Houltond8ed0212018-05-16 17:18:24 -06002298 "VUID-vkCmdClearColorImage-commandBuffer-cmdpool");
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07002299 skip |= ValidateCmd(cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
Mark Lobodzinski8c193c02020-02-20 09:20:33 -07002300 if (device_extensions.vk_khr_maintenance1) {
Spencer Fricke6bba8c72020-04-06 07:41:21 -07002301 skip |= ValidateImageFormatFeatureFlags(image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdClearColorImage",
2302 "VUID-vkCmdClearColorImage-image-01993");
Cort Stratton186b1a22018-05-01 20:18:06 -04002303 }
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07002304 skip |= InsideRenderPass(cb_node, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-renderpass");
sfricke-samsung022fa252020-07-24 03:26:16 -07002305 skip |=
2306 ValidateProtectedImage(cb_node, image_state, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-commandBuffer-01805");
2307 skip |= ValidateUnprotectedImage(cb_node, image_state, "vkCmdClearColorImage()",
2308 "VUID-vkCmdClearColorImage-commandBuffer-01806");
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002309 for (uint32_t i = 0; i < rangeCount; ++i) {
Petr Kraus4d718682017-05-18 03:38:41 +02002310 std::string param_name = "pRanges[" + std::to_string(i) + "]";
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07002311 skip |= ValidateCmdClearColorSubresourceRange(image_state, pRanges[i], param_name.c_str());
sfricke-samsungcd924d92020-05-20 23:51:17 -07002312 skip |= ValidateImageAttributes(image_state, pRanges[i], param_name.c_str());
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002313 skip |= VerifyClearImageLayout(cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearColorImage()");
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002314 }
sfricke-samsunge775d492020-02-28 09:02:25 -08002315 // Tests for "Formats requiring sampler Y’CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views"
2316 if (FormatRequiresYcbcrConversion(image_state->createInfo.format)) {
2317 skip |= LogError(device, "VUID-vkCmdClearColorImage-image-01545",
2318 "vkCmdClearColorImage(): format (%s) must not be one of the formats requiring sampler YCBCR "
2319 "conversion for VK_IMAGE_ASPECT_COLOR_BIT image views",
2320 string_VkFormat(image_state->createInfo.format));
2321 }
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002322 }
2323 return skip;
2324}
2325
John Zulaufeabb4462019-07-05 14:13:03 -06002326void CoreChecks::PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2327 const VkClearColorValue *pColor, uint32_t rangeCount,
2328 const VkImageSubresourceRange *pRanges) {
2329 StateTracker::PreCallRecordCmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
2330
2331 auto cb_node = GetCBState(commandBuffer);
2332 auto image_state = GetImageState(image);
2333 if (cb_node && image_state) {
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002334 for (uint32_t i = 0; i < rangeCount; ++i) {
John Zulauff660ad62019-03-23 07:16:05 -06002335 SetImageInitialLayout(cb_node, image, pRanges[i], imageLayout);
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002336 }
2337 }
2338}
2339
sfricke-samsung03f11ef2021-01-23 02:02:15 -08002340bool CoreChecks::ValidateClearDepthStencilValue(VkCommandBuffer commandBuffer, VkClearDepthStencilValue clearValue,
2341 const char *apiName) const {
2342 bool skip = false;
2343
2344 // The extension was not created with a feature bit whichs prevents displaying the 2 variations of the VUIDs
2345 if (!device_extensions.vk_ext_depth_range_unrestricted) {
2346 if (!(clearValue.depth >= 0.0) || !(clearValue.depth <= 1.0)) {
2347 // Also VUID-VkClearDepthStencilValue-depth-00022
2348 skip |= LogError(commandBuffer, "VUID-VkClearDepthStencilValue-depth-02506",
2349 "%s: VK_EXT_depth_range_unrestricted extension is not enabled and VkClearDepthStencilValue::depth "
2350 "(=%f) is not within the [0.0, 1.0] range.",
2351 apiName, clearValue.depth);
2352 }
2353 }
2354
2355 return skip;
2356}
2357
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07002358bool CoreChecks::PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2359 const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
Jeff Bolz5c801d12019-10-09 10:38:45 -05002360 const VkImageSubresourceRange *pRanges) const {
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002361 bool skip = false;
Mark Lobodzinski1241a312017-02-01 10:57:21 -07002362
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002363 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
John Zulaufeabb4462019-07-05 14:13:03 -06002364 const auto *cb_node = GetCBState(commandBuffer);
2365 const auto *image_state = GetImageState(image);
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002366 if (cb_node && image_state) {
sfricke-samsung30e325a2020-07-25 12:56:13 -07002367 const VkFormat image_format = image_state->createInfo.format;
Mark Lobodzinski0ebe9712019-03-07 13:39:07 -07002368 skip |= ValidateMemoryIsBoundToImage(image_state, "vkCmdClearDepthStencilImage()",
Dave Houltond8ed0212018-05-16 17:18:24 -06002369 "VUID-vkCmdClearDepthStencilImage-image-00010");
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07002370 skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearDepthStencilImage()", VK_QUEUE_GRAPHICS_BIT,
Dave Houltond8ed0212018-05-16 17:18:24 -06002371 "VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool");
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07002372 skip |= ValidateCmd(cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
Mark Lobodzinski8c193c02020-02-20 09:20:33 -07002373 if (device_extensions.vk_khr_maintenance1) {
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002374 skip |= ValidateImageFormatFeatureFlags(image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdClearDepthStencilImage",
Shannon McPherson40c0cba2018-08-07 13:39:13 -06002375 "VUID-vkCmdClearDepthStencilImage-image-01994");
Cort Stratton186b1a22018-05-01 20:18:06 -04002376 }
sfricke-samsung03f11ef2021-01-23 02:02:15 -08002377 skip |= ValidateClearDepthStencilValue(commandBuffer, *pDepthStencil, "vkCmdClearDepthStencilImage()");
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07002378 skip |= InsideRenderPass(cb_node, "vkCmdClearDepthStencilImage()", "VUID-vkCmdClearDepthStencilImage-renderpass");
sfricke-samsung022fa252020-07-24 03:26:16 -07002379 skip |= ValidateProtectedImage(cb_node, image_state, "vkCmdClearDepthStencilImage()",
2380 "VUID-vkCmdClearDepthStencilImage-commandBuffer-01807");
2381 skip |= ValidateUnprotectedImage(cb_node, image_state, "vkCmdClearDepthStencilImage()",
2382 "VUID-vkCmdClearDepthStencilImage-commandBuffer-01808");
Andrew Fobel3abeb992020-01-20 16:33:22 -05002383
2384 bool any_include_aspect_depth_bit = false;
2385 bool any_include_aspect_stencil_bit = false;
2386
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002387 for (uint32_t i = 0; i < rangeCount; ++i) {
Petr Kraus4d718682017-05-18 03:38:41 +02002388 std::string param_name = "pRanges[" + std::to_string(i) + "]";
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07002389 skip |= ValidateCmdClearDepthSubresourceRange(image_state, pRanges[i], param_name.c_str());
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002390 skip |= VerifyClearImageLayout(cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
Mark Lobodzinski1241a312017-02-01 10:57:21 -07002391 // Image aspect must be depth or stencil or both
Dave Houlton12befb92018-06-26 17:16:46 -06002392 VkImageAspectFlags valid_aspects = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
2393 if (((pRanges[i].aspectMask & valid_aspects) == 0) || ((pRanges[i].aspectMask & ~valid_aspects) != 0)) {
sfricke-samsungcd924d92020-05-20 23:51:17 -07002394 skip |= LogError(commandBuffer, "VUID-vkCmdClearDepthStencilImage-aspectMask-02824",
2395 "vkCmdClearDepthStencilImage(): pRanges[%u].aspectMask can only be VK_IMAGE_ASPECT_DEPTH_BIT "
2396 "and/or VK_IMAGE_ASPECT_STENCIL_BIT.",
2397 i);
Mark Lobodzinski1241a312017-02-01 10:57:21 -07002398 }
Andrew Fobel3abeb992020-01-20 16:33:22 -05002399 if ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
2400 any_include_aspect_depth_bit = true;
sfricke-samsung30e325a2020-07-25 12:56:13 -07002401 if (FormatHasDepth(image_format) == false) {
2402 skip |= LogError(commandBuffer, "VUID-vkCmdClearDepthStencilImage-image-02826",
2403 "vkCmdClearDepthStencilImage(): pRanges[%u].aspectMask has a VK_IMAGE_ASPECT_DEPTH_BIT but %s "
2404 "doesn't have a depth component.",
2405 i, string_VkFormat(image_format));
2406 }
Andrew Fobel3abeb992020-01-20 16:33:22 -05002407 }
2408 if ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
2409 any_include_aspect_stencil_bit = true;
sfricke-samsung30e325a2020-07-25 12:56:13 -07002410 if (FormatHasStencil(image_format) == false) {
2411 skip |= LogError(commandBuffer, "VUID-vkCmdClearDepthStencilImage-image-02825",
2412 "vkCmdClearDepthStencilImage(): pRanges[%u].aspectMask has a VK_IMAGE_ASPECT_STENCIL_BIT but "
2413 "%s doesn't have a stencil component.",
2414 i, string_VkFormat(image_format));
2415 }
Andrew Fobel3abeb992020-01-20 16:33:22 -05002416 }
2417 }
2418 if (any_include_aspect_stencil_bit) {
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07002419 const auto image_stencil_struct = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_state->createInfo.pNext);
Andrew Fobel3abeb992020-01-20 16:33:22 -05002420 if (image_stencil_struct != nullptr) {
2421 if ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
2422 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002423 LogError(device, "VUID-vkCmdClearDepthStencilImage-pRanges-02658",
2424 "vkCmdClearDepthStencilImage(): an element of pRanges.aspect includes VK_IMAGE_ASPECT_STENCIL_BIT "
2425 "and image was created with separate stencil usage, VK_IMAGE_USAGE_TRANSFER_DST_BIT must be "
2426 "included in VkImageStencilUsageCreateInfo::stencilUsage used to create image");
Andrew Fobel3abeb992020-01-20 16:33:22 -05002427 }
2428 } else {
2429 if ((image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002430 skip |= LogError(
2431 device, "VUID-vkCmdClearDepthStencilImage-pRanges-02659",
Andrew Fobel3abeb992020-01-20 16:33:22 -05002432 "vkCmdClearDepthStencilImage(): an element of pRanges.aspect includes VK_IMAGE_ASPECT_STENCIL_BIT and "
2433 "image was not created with separate stencil usage, VK_IMAGE_USAGE_TRANSFER_DST_BIT must be included "
2434 "in VkImageCreateInfo::usage used to create image");
2435 }
2436 }
2437 }
2438 if (any_include_aspect_depth_bit && (image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002439 skip |= LogError(device, "VUID-vkCmdClearDepthStencilImage-pRanges-02660",
2440 "vkCmdClearDepthStencilImage(): an element of pRanges.aspect includes VK_IMAGE_ASPECT_DEPTH_BIT, "
2441 "VK_IMAGE_USAGE_TRANSFER_DST_BIT must be included in VkImageCreateInfo::usage used to create image");
Mark Lobodzinski1241a312017-02-01 10:57:21 -07002442 }
sfricke-samsung30e325a2020-07-25 12:56:13 -07002443 if (image_state && !FormatIsDepthOrStencil(image_format)) {
sfricke-samsungcd924d92020-05-20 23:51:17 -07002444 skip |= LogError(image, "VUID-vkCmdClearDepthStencilImage-image-00014",
2445 "vkCmdClearDepthStencilImage(): called with image %s which doesn't have a depth/stencil format (%s).",
sfricke-samsung30e325a2020-07-25 12:56:13 -07002446 report_data->FormatHandle(image).c_str(), string_VkFormat(image_format));
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002447 }
Tobin Ehlis4af8c242017-11-30 13:47:11 -07002448 if (VK_IMAGE_USAGE_TRANSFER_DST_BIT != (VK_IMAGE_USAGE_TRANSFER_DST_BIT & image_state->createInfo.usage)) {
sfricke-samsungcd924d92020-05-20 23:51:17 -07002449 skip |= LogError(image, "VUID-vkCmdClearDepthStencilImage-image-00009",
2450 "vkCmdClearDepthStencilImage(): called with image %s which was not created with the "
2451 "VK_IMAGE_USAGE_TRANSFER_DST_BIT set.",
2452 report_data->FormatHandle(image).c_str());
Tobin Ehlis4af8c242017-11-30 13:47:11 -07002453 }
Mark Lobodzinskid81d1012017-02-01 09:03:06 -07002454 }
2455 return skip;
2456}
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002457
John Zulaufeabb4462019-07-05 14:13:03 -06002458void CoreChecks::PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2459 const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
2460 const VkImageSubresourceRange *pRanges) {
2461 StateTracker::PreCallRecordCmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
2462 auto cb_node = GetCBState(commandBuffer);
2463 auto image_state = GetImageState(image);
2464 if (cb_node && image_state) {
Mark Lobodzinski9a075c22019-01-10 14:30:39 -07002465 for (uint32_t i = 0; i < rangeCount; ++i) {
John Zulauff660ad62019-03-23 07:16:05 -06002466 SetImageInitialLayout(cb_node, image, pRanges[i], imageLayout);
Mark Lobodzinski9a075c22019-01-10 14:30:39 -07002467 }
2468 }
2469}
2470
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002471// Returns true if [x, xoffset] and [y, yoffset] overlap
2472static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) {
2473 bool result = false;
2474 uint32_t intersection_min = std::max(static_cast<uint32_t>(start), static_cast<uint32_t>(end));
2475 uint32_t intersection_max = std::min(static_cast<uint32_t>(start) + start_offset, static_cast<uint32_t>(end) + end_offset);
2476
2477 if (intersection_max > intersection_min) {
2478 result = true;
2479 }
2480 return result;
2481}
2482
Jeff Leger178b1e52020-10-05 12:22:23 -04002483// Returns true if source area of first vkImageCopy/vkImageCopy2KHR region intersects dest area of second region
Dave Houltonc991cc92018-03-06 11:08:51 -07002484// It is assumed that these are copy regions within a single image (otherwise no possibility of collision)
Jeff Leger178b1e52020-10-05 12:22:23 -04002485template <typename RegionType>
2486static bool RegionIntersects(const RegionType *rgn0, const RegionType *rgn1, VkImageType type, bool is_multiplane) {
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002487 bool result = false;
Dave Houltonf5217612018-02-02 16:18:52 -07002488
Dave Houltonc991cc92018-03-06 11:08:51 -07002489 // Separate planes within a multiplane image cannot intersect
2490 if (is_multiplane && (rgn0->srcSubresource.aspectMask != rgn1->dstSubresource.aspectMask)) {
Dave Houltonf5217612018-02-02 16:18:52 -07002491 return result;
2492 }
2493
Dave Houltonc991cc92018-03-06 11:08:51 -07002494 if ((rgn0->srcSubresource.mipLevel == rgn1->dstSubresource.mipLevel) &&
2495 (RangesIntersect(rgn0->srcSubresource.baseArrayLayer, rgn0->srcSubresource.layerCount, rgn1->dstSubresource.baseArrayLayer,
2496 rgn1->dstSubresource.layerCount))) {
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002497 result = true;
2498 switch (type) {
2499 case VK_IMAGE_TYPE_3D:
Dave Houltonc991cc92018-03-06 11:08:51 -07002500 result &= RangesIntersect(rgn0->srcOffset.z, rgn0->extent.depth, rgn1->dstOffset.z, rgn1->extent.depth);
Tobin Ehlis648b1cf2018-04-13 15:24:13 -06002501 // fall through
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002502 case VK_IMAGE_TYPE_2D:
Dave Houltonc991cc92018-03-06 11:08:51 -07002503 result &= RangesIntersect(rgn0->srcOffset.y, rgn0->extent.height, rgn1->dstOffset.y, rgn1->extent.height);
Tobin Ehlis648b1cf2018-04-13 15:24:13 -06002504 // fall through
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002505 case VK_IMAGE_TYPE_1D:
Dave Houltonc991cc92018-03-06 11:08:51 -07002506 result &= RangesIntersect(rgn0->srcOffset.x, rgn0->extent.width, rgn1->dstOffset.x, rgn1->extent.width);
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002507 break;
2508 default:
2509 // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
2510 assert(false);
2511 }
2512 }
2513 return result;
2514}
2515
Dave Houltonfc1a4052017-04-27 14:32:45 -06002516// Returns non-zero if offset and extent exceed image extents
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07002517static const uint32_t kXBit = 1;
2518static const uint32_t kYBit = 2;
2519static const uint32_t kZBit = 4;
Dave Houlton1150cf52017-04-27 14:38:11 -06002520static uint32_t ExceedsBounds(const VkOffset3D *offset, const VkExtent3D *extent, const VkExtent3D *image_extent) {
Dave Houltonfc1a4052017-04-27 14:32:45 -06002521 uint32_t result = 0;
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002522 // Extents/depths cannot be negative but checks left in for clarity
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002523 if ((offset->z + extent->depth > image_extent->depth) || (offset->z < 0) ||
2524 ((offset->z + static_cast<int32_t>(extent->depth)) < 0)) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07002525 result |= kZBit;
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002526 }
2527 if ((offset->y + extent->height > image_extent->height) || (offset->y < 0) ||
2528 ((offset->y + static_cast<int32_t>(extent->height)) < 0)) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07002529 result |= kYBit;
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002530 }
2531 if ((offset->x + extent->width > image_extent->width) || (offset->x < 0) ||
2532 ((offset->x + static_cast<int32_t>(extent->width)) < 0)) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07002533 result |= kXBit;
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002534 }
2535 return result;
2536}
2537
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002538// Test if two VkExtent3D structs are equivalent
2539static inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
2540 bool result = true;
2541 if ((extent->width != other_extent->width) || (extent->height != other_extent->height) ||
2542 (extent->depth != other_extent->depth)) {
2543 result = false;
2544 }
2545 return result;
2546}
2547
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002548// Test if the extent argument has all dimensions set to 0.
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002549static inline bool IsExtentAllZeroes(const VkExtent3D *extent) {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002550 return ((extent->width == 0) && (extent->height == 0) && (extent->depth == 0));
2551}
2552
2553// Returns the image transfer granularity for a specific image scaled by compressed block size if necessary.
John Zulaufe2b7bcb2019-07-05 16:08:39 -06002554VkExtent3D CoreChecks::GetScaledItg(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img) const {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002555 // Default to (0, 0, 0) granularity in case we can't find the real granularity for the physical device.
2556 VkExtent3D granularity = {0, 0, 0};
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07002557 auto pool = cb_node->command_pool.get();
2558 if (pool) {
2559 granularity = GetPhysicalDeviceState()->queue_family_properties[pool->queueFamilyIndex].minImageTransferGranularity;
unknown948b6ba2019-09-19 17:32:54 -06002560 if (FormatIsCompressed(img->createInfo.format) || FormatIsSinglePlane_422(img->createInfo.format)) {
Dave Houltona585d132019-01-18 13:05:42 -07002561 auto block_size = FormatTexelBlockExtent(img->createInfo.format);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002562 granularity.width *= block_size.width;
2563 granularity.height *= block_size.height;
2564 }
2565 }
2566 return granularity;
2567}
2568
2569// Test elements of a VkExtent3D structure against alignment constraints contained in another VkExtent3D structure
2570static inline bool IsExtentAligned(const VkExtent3D *extent, const VkExtent3D *granularity) {
2571 bool valid = true;
Dave Houlton1d2022c2017-03-29 11:43:58 -06002572 if ((SafeModulo(extent->depth, granularity->depth) != 0) || (SafeModulo(extent->width, granularity->width) != 0) ||
2573 (SafeModulo(extent->height, granularity->height) != 0)) {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002574 valid = false;
2575 }
2576 return valid;
2577}
2578
2579// Check elements of a VkOffset3D structure against a queue family's Image Transfer Granularity values
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06002580bool CoreChecks::CheckItgOffset(const CMD_BUFFER_STATE *cb_node, const VkOffset3D *offset, const VkExtent3D *granularity,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06002581 const uint32_t i, const char *function, const char *member, const char *vuid) const {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002582 bool skip = false;
2583 VkExtent3D offset_extent = {};
2584 offset_extent.width = static_cast<uint32_t>(abs(offset->x));
2585 offset_extent.height = static_cast<uint32_t>(abs(offset->y));
2586 offset_extent.depth = static_cast<uint32_t>(abs(offset->z));
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002587 if (IsExtentAllZeroes(granularity)) {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002588 // If the queue family image transfer granularity is (0, 0, 0), then the offset must always be (0, 0, 0)
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002589 if (IsExtentAllZeroes(&offset_extent) == false) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002590 skip |= LogError(cb_node->commandBuffer, vuid,
2591 "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) must be (x=0, y=0, z=0) when the command buffer's queue family "
2592 "image transfer granularity is (w=0, h=0, d=0).",
2593 function, i, member, offset->x, offset->y, offset->z);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002594 }
2595 } else {
2596 // If the queue family image transfer granularity is not (0, 0, 0), then the offset dimensions must always be even
2597 // integer multiples of the image transfer granularity.
2598 if (IsExtentAligned(&offset_extent, granularity) == false) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002599 skip |= LogError(cb_node->commandBuffer, vuid,
2600 "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) dimensions must be even integer multiples of this command "
2601 "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d).",
2602 function, i, member, offset->x, offset->y, offset->z, granularity->width, granularity->height,
2603 granularity->depth);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002604 }
2605 }
2606 return skip;
2607}
2608
2609// Check elements of a VkExtent3D structure against a queue family's Image Transfer Granularity values
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06002610bool CoreChecks::CheckItgExtent(const CMD_BUFFER_STATE *cb_node, const VkExtent3D *extent, const VkOffset3D *offset,
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002611 const VkExtent3D *granularity, const VkExtent3D *subresource_extent, const VkImageType image_type,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06002612 const uint32_t i, const char *function, const char *member, const char *vuid) const {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002613 bool skip = false;
Dave Houlton9dae7ec2017-03-01 16:23:25 -07002614 if (IsExtentAllZeroes(granularity)) {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002615 // If the queue family image transfer granularity is (0, 0, 0), then the extent must always match the image
2616 // subresource extent.
2617 if (IsExtentEqual(extent, subresource_extent) == false) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002618 skip |= LogError(cb_node->commandBuffer, vuid,
2619 "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d) "
2620 "when the command buffer's queue family image transfer granularity is (w=0, h=0, d=0).",
2621 function, i, member, extent->width, extent->height, extent->depth, subresource_extent->width,
2622 subresource_extent->height, subresource_extent->depth);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002623 }
2624 } else {
2625 // If the queue family image transfer granularity is not (0, 0, 0), then the extent dimensions must always be even
2626 // integer multiples of the image transfer granularity or the offset + extent dimensions must always match the image
2627 // subresource extent dimensions.
2628 VkExtent3D offset_extent_sum = {};
2629 offset_extent_sum.width = static_cast<uint32_t>(abs(offset->x)) + extent->width;
2630 offset_extent_sum.height = static_cast<uint32_t>(abs(offset->y)) + extent->height;
2631 offset_extent_sum.depth = static_cast<uint32_t>(abs(offset->z)) + extent->depth;
Mark Lobodzinski283ade62017-10-09 16:36:49 -06002632 bool x_ok = true;
2633 bool y_ok = true;
2634 bool z_ok = true;
2635 switch (image_type) {
2636 case VK_IMAGE_TYPE_3D:
2637 z_ok = ((0 == SafeModulo(extent->depth, granularity->depth)) ||
2638 (subresource_extent->depth == offset_extent_sum.depth));
Tobin Ehlis648b1cf2018-04-13 15:24:13 -06002639 // fall through
Mark Lobodzinski283ade62017-10-09 16:36:49 -06002640 case VK_IMAGE_TYPE_2D:
2641 y_ok = ((0 == SafeModulo(extent->height, granularity->height)) ||
2642 (subresource_extent->height == offset_extent_sum.height));
Tobin Ehlis648b1cf2018-04-13 15:24:13 -06002643 // fall through
Mark Lobodzinski283ade62017-10-09 16:36:49 -06002644 case VK_IMAGE_TYPE_1D:
2645 x_ok = ((0 == SafeModulo(extent->width, granularity->width)) ||
2646 (subresource_extent->width == offset_extent_sum.width));
2647 break;
2648 default:
2649 // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
2650 assert(false);
2651 }
Dave Houlton6f9059e2017-05-02 17:15:13 -06002652 if (!(x_ok && y_ok && z_ok)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002653 skip |=
2654 LogError(cb_node->commandBuffer, vuid,
2655 "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) dimensions must be even integer multiples of this command "
2656 "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d) or offset (x=%d, y=%d, z=%d) + "
2657 "extent (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d).",
2658 function, i, member, extent->width, extent->height, extent->depth, granularity->width, granularity->height,
2659 granularity->depth, offset->x, offset->y, offset->z, extent->width, extent->height, extent->depth,
2660 subresource_extent->width, subresource_extent->height, subresource_extent->depth);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002661 }
2662 }
2663 return skip;
2664}
2665
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06002666bool CoreChecks::ValidateImageMipLevel(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, uint32_t mip_level,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06002667 const uint32_t i, const char *function, const char *member, const char *vuid) const {
Cort Strattonff1542a2018-05-27 10:49:28 -07002668 bool skip = false;
2669 if (mip_level >= img->createInfo.mipLevels) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002670 skip |= LogError(cb_node->commandBuffer, vuid, "In %s, pRegions[%u].%s.mipLevel is %u, but provided %s has %u mip levels.",
2671 function, i, member, mip_level, report_data->FormatHandle(img->image).c_str(), img->createInfo.mipLevels);
Cort Strattonff1542a2018-05-27 10:49:28 -07002672 }
2673 return skip;
2674}
2675
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06002676bool CoreChecks::ValidateImageArrayLayerRange(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, const uint32_t base_layer,
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002677 const uint32_t layer_count, const uint32_t i, const char *function,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06002678 const char *member, const char *vuid) const {
Cort Strattonff1542a2018-05-27 10:49:28 -07002679 bool skip = false;
2680 if (base_layer >= img->createInfo.arrayLayers || layer_count > img->createInfo.arrayLayers ||
2681 (base_layer + layer_count) > img->createInfo.arrayLayers) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002682 skip |= LogError(cb_node->commandBuffer, vuid,
2683 "In %s, pRegions[%u].%s.baseArrayLayer is %u and .layerCount is "
2684 "%u, but provided %s has %u array layers.",
2685 function, i, member, base_layer, layer_count, report_data->FormatHandle(img->image).c_str(),
2686 img->createInfo.arrayLayers);
Cort Strattonff1542a2018-05-27 10:49:28 -07002687 }
2688 return skip;
2689}
2690
Jeff Leger178b1e52020-10-05 12:22:23 -04002691// Check valid usage Image Transfer Granularity requirements for elements of a VkBufferImageCopy/VkBufferImageCopy2KHR structure
2692template <typename BufferImageCopyRegionType>
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06002693bool CoreChecks::ValidateCopyBufferImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img,
Jeff Leger178b1e52020-10-05 12:22:23 -04002694 const BufferImageCopyRegionType *region, const uint32_t i,
John Zulaufe3d1c8a2019-08-12 14:34:58 -06002695 const char *function, const char *vuid) const {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002696 bool skip = false;
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002697 VkExtent3D granularity = GetScaledItg(cb_node, img);
2698 skip |= CheckItgOffset(cb_node, &region->imageOffset, &granularity, i, function, "imageOffset", vuid);
Cort Stratton420ebd42018-05-04 01:12:23 -04002699 VkExtent3D subresource_extent = GetImageSubresourceExtent(img, &region->imageSubresource);
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002700 skip |= CheckItgExtent(cb_node, &region->imageExtent, &region->imageOffset, &granularity, &subresource_extent,
Cort Stratton420ebd42018-05-04 01:12:23 -04002701 img->createInfo.imageType, i, function, "imageExtent", vuid);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002702 return skip;
2703}
2704
Jeff Leger178b1e52020-10-05 12:22:23 -04002705// Check valid usage Image Transfer Granularity requirements for elements of a VkImageCopy/VkImageCopy2KHR structure
2706template <typename RegionType>
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06002707bool CoreChecks::ValidateCopyImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *src_img,
Jeff Leger178b1e52020-10-05 12:22:23 -04002708 const IMAGE_STATE *dst_img, const RegionType *region,
2709 const uint32_t i, const char *function,
2710 CopyCommandVersion version) const {
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002711 bool skip = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04002712 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
2713 const char *vuid;
2714
Mark Lobodzinskid0788802017-10-19 15:38:59 -06002715 // Source image checks
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002716 VkExtent3D granularity = GetScaledItg(cb_node, src_img);
Jeff Leger178b1e52020-10-05 12:22:23 -04002717 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-01783" : "VUID-vkCmdCopyImage-srcOffset-01783";
2718 skip |= CheckItgOffset(cb_node, &region->srcOffset, &granularity, i, function, "srcOffset", vuid);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002719 VkExtent3D subresource_extent = GetImageSubresourceExtent(src_img, &region->srcSubresource);
Dave Houlton94a00372017-12-14 15:08:47 -07002720 const VkExtent3D extent = region->extent;
Jeff Leger178b1e52020-10-05 12:22:23 -04002721 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-01783" : "VUID-vkCmdCopyImage-srcOffset-01783";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002722 skip |= CheckItgExtent(cb_node, &extent, &region->srcOffset, &granularity, &subresource_extent, src_img->createInfo.imageType,
Jeff Leger178b1e52020-10-05 12:22:23 -04002723 i, function, "extent", vuid);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002724
Mark Lobodzinskid0788802017-10-19 15:38:59 -06002725 // Destination image checks
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002726 granularity = GetScaledItg(cb_node, dst_img);
Jeff Leger178b1e52020-10-05 12:22:23 -04002727 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-01784" : "VUID-vkCmdCopyImage-dstOffset-01784";
2728 skip |= CheckItgOffset(cb_node, &region->dstOffset, &granularity, i, function, "dstOffset", vuid);
Dave Houltonee281a52017-12-08 13:51:02 -07002729 // Adjust dest extent, if necessary
Dave Houlton94a00372017-12-14 15:08:47 -07002730 const VkExtent3D dest_effective_extent =
2731 GetAdjustedDestImageExtent(src_img->createInfo.format, dst_img->createInfo.format, extent);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002732 subresource_extent = GetImageSubresourceExtent(dst_img, &region->dstSubresource);
Jeff Leger178b1e52020-10-05 12:22:23 -04002733 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-01784" : "VUID-vkCmdCopyImage-dstOffset-01784";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07002734 skip |= CheckItgExtent(cb_node, &dest_effective_extent, &region->dstOffset, &granularity, &subresource_extent,
Jeff Leger178b1e52020-10-05 12:22:23 -04002735 dst_img->createInfo.imageType, i, function, "extent", vuid);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07002736 return skip;
2737}
2738
Jeff Leger178b1e52020-10-05 12:22:23 -04002739// Validate contents of a VkImageCopy or VkImageCopy2KHR struct
2740template <typename ImageCopyRegionType>
2741bool CoreChecks::ValidateImageCopyData(const uint32_t regionCount, const ImageCopyRegionType *ic_regions,
2742 const IMAGE_STATE *src_state, const IMAGE_STATE *dst_state,
2743 CopyCommandVersion version) const {
Dave Houlton6f9059e2017-05-02 17:15:13 -06002744 bool skip = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04002745 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
2746 const char *func_name = is_2khr ? "vkCmdCopyImage2KHR()" : "vkCmdCopyImage()";
2747 const char *vuid;
Dave Houlton6f9059e2017-05-02 17:15:13 -06002748
2749 for (uint32_t i = 0; i < regionCount; i++) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002750 const ImageCopyRegionType region = ic_regions[i];
Dave Houltonee281a52017-12-08 13:51:02 -07002751
2752 // For comp<->uncomp copies, the copy extent for the dest image must be adjusted
Dave Houlton94a00372017-12-14 15:08:47 -07002753 const VkExtent3D src_copy_extent = region.extent;
2754 const VkExtent3D dst_copy_extent =
Dave Houltonee281a52017-12-08 13:51:02 -07002755 GetAdjustedDestImageExtent(src_state->createInfo.format, dst_state->createInfo.format, region.extent);
2756
Dave Houlton6f9059e2017-05-02 17:15:13 -06002757 bool slice_override = false;
2758 uint32_t depth_slices = 0;
2759
2760 // Special case for copying between a 1D/2D array and a 3D image
2761 // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
2762 if ((VK_IMAGE_TYPE_3D == src_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != dst_state->createInfo.imageType)) {
Dave Houltonee281a52017-12-08 13:51:02 -07002763 depth_slices = region.dstSubresource.layerCount; // Slice count from 2D subresource
Dave Houlton6f9059e2017-05-02 17:15:13 -06002764 slice_override = (depth_slices != 1);
2765 } else if ((VK_IMAGE_TYPE_3D == dst_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != src_state->createInfo.imageType)) {
Dave Houltonee281a52017-12-08 13:51:02 -07002766 depth_slices = region.srcSubresource.layerCount; // Slice count from 2D subresource
Dave Houlton6f9059e2017-05-02 17:15:13 -06002767 slice_override = (depth_slices != 1);
2768 }
2769
2770 // Do all checks on source image
Dave Houlton6f9059e2017-05-02 17:15:13 -06002771 if (src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
Dave Houltonee281a52017-12-08 13:51:02 -07002772 if ((0 != region.srcOffset.y) || (1 != src_copy_extent.height)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002773 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00146" : "VUID-vkCmdCopyImage-srcImage-00146";
2774 skip |= LogError(src_state->image, vuid,
2775 "%s: pRegion[%d] srcOffset.y is %d and extent.height is %d. For 1D images these must "
2776 "be 0 and 1, respectively.",
2777 func_name, i, region.srcOffset.y, src_copy_extent.height);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002778 }
2779 }
2780
Dave Houlton533be9f2018-03-26 17:08:30 -06002781 if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.srcOffset.z) || (1 != src_copy_extent.depth))) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002782 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01785" : "VUID-vkCmdCopyImage-srcImage-01785";
2783 skip |= LogError(src_state->image, vuid,
2784 "%s: pRegion[%d] srcOffset.z is %d and extent.depth is %d. For 1D images "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002785 "these must be 0 and 1, respectively.",
Jeff Leger178b1e52020-10-05 12:22:23 -04002786 func_name, i, region.srcOffset.z, src_copy_extent.depth);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002787 }
2788
Dave Houlton533be9f2018-03-26 17:08:30 -06002789 if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.srcOffset.z)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002790 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01787" : "VUID-vkCmdCopyImage-srcImage-01787";
2791 skip |= LogError(src_state->image, vuid, "%s: pRegion[%d] srcOffset.z is %d. For 2D images the z-offset must be 0.",
2792 func_name, i, region.srcOffset.z);
Dave Houlton533be9f2018-03-26 17:08:30 -06002793 }
2794
Dave Houltonc991cc92018-03-06 11:08:51 -07002795 // Source checks that apply only to compressed images (or to _422 images if ycbcr enabled)
Tony-LunarG2ec96bb2019-11-26 13:43:02 -07002796 bool ext_ycbcr = IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion);
Dave Houltonc991cc92018-03-06 11:08:51 -07002797 if (FormatIsCompressed(src_state->createInfo.format) ||
2798 (ext_ycbcr && FormatIsSinglePlane_422(src_state->createInfo.format))) {
Dave Houltona585d132019-01-18 13:05:42 -07002799 const VkExtent3D block_size = FormatTexelBlockExtent(src_state->createInfo.format);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002800 // image offsets must be multiples of block dimensions
Dave Houltonee281a52017-12-08 13:51:02 -07002801 if ((SafeModulo(region.srcOffset.x, block_size.width) != 0) ||
2802 (SafeModulo(region.srcOffset.y, block_size.height) != 0) ||
2803 (SafeModulo(region.srcOffset.z, block_size.depth) != 0)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002804 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01727" : "VUID-vkCmdCopyImage-srcImage-01727";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002805 skip |= LogError(src_state->image, vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04002806 "%s: pRegion[%d] srcOffset (%d, %d) must be multiples of the compressed image's "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002807 "texel width & height (%d, %d).",
Jeff Leger178b1e52020-10-05 12:22:23 -04002808 func_name, i, region.srcOffset.x, region.srcOffset.y, block_size.width, block_size.height);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002809 }
2810
Dave Houlton94a00372017-12-14 15:08:47 -07002811 const VkExtent3D mip_extent = GetImageSubresourceExtent(src_state, &(region.srcSubresource));
Dave Houltonee281a52017-12-08 13:51:02 -07002812 if ((SafeModulo(src_copy_extent.width, block_size.width) != 0) &&
2813 (src_copy_extent.width + region.srcOffset.x != mip_extent.width)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002814 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01728" : "VUID-vkCmdCopyImage-srcImage-01728";
2815 skip |= LogError(src_state->image, vuid,
2816 "%s: pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
2817 "width (%d), or when added to srcOffset.x (%d) must equal the image subresource width (%d).",
2818 func_name, i, src_copy_extent.width, block_size.width, region.srcOffset.x, mip_extent.width);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002819 }
2820
Mark Lobodzinskid0788802017-10-19 15:38:59 -06002821 // Extent height must be a multiple of block height, or extent+offset height must equal subresource height
Dave Houltonee281a52017-12-08 13:51:02 -07002822 if ((SafeModulo(src_copy_extent.height, block_size.height) != 0) &&
2823 (src_copy_extent.height + region.srcOffset.y != mip_extent.height)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002824 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01729" : "VUID-vkCmdCopyImage-srcImage-01729";
2825 skip |= LogError(src_state->image, vuid,
2826 "%s: pRegion[%d] extent height (%d) must be a multiple of the compressed texture block "
2827 "height (%d), or when added to srcOffset.y (%d) must equal the image subresource height (%d).",
2828 func_name, i, src_copy_extent.height, block_size.height, region.srcOffset.y, mip_extent.height);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002829 }
2830
Mark Lobodzinskid0788802017-10-19 15:38:59 -06002831 // Extent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
Dave Houltonee281a52017-12-08 13:51:02 -07002832 uint32_t copy_depth = (slice_override ? depth_slices : src_copy_extent.depth);
2833 if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.srcOffset.z != mip_extent.depth)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002834 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01730" : "VUID-vkCmdCopyImage-srcImage-01730";
2835 skip |= LogError(src_state->image, vuid,
2836 "%s: pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
2837 "depth (%d), or when added to srcOffset.z (%d) must equal the image subresource depth (%d).",
2838 func_name, i, src_copy_extent.depth, block_size.depth, region.srcOffset.z, mip_extent.depth);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002839 }
2840 } // Compressed
2841
2842 // Do all checks on dest image
Dave Houlton6f9059e2017-05-02 17:15:13 -06002843 if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
Dave Houltonee281a52017-12-08 13:51:02 -07002844 if ((0 != region.dstOffset.y) || (1 != dst_copy_extent.height)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002845 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-00152" : "VUID-vkCmdCopyImage-dstImage-00152";
2846 skip |= LogError(dst_state->image, vuid,
2847 "%s: pRegion[%d] dstOffset.y is %d and dst_copy_extent.height is %d. For 1D images "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002848 "these must be 0 and 1, respectively.",
Jeff Leger178b1e52020-10-05 12:22:23 -04002849 func_name, i, region.dstOffset.y, dst_copy_extent.height);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002850 }
2851 }
2852
Dave Houlton533be9f2018-03-26 17:08:30 -06002853 if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.dstOffset.z) || (1 != dst_copy_extent.depth))) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002854 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01786" : "VUID-vkCmdCopyImage-dstImage-01786";
2855 skip |= LogError(dst_state->image, vuid,
2856 "%s: pRegion[%d] dstOffset.z is %d and extent.depth is %d. For 1D images these must be 0 "
2857 "and 1, respectively.",
2858 func_name, i, region.dstOffset.z, dst_copy_extent.depth);
Dave Houlton533be9f2018-03-26 17:08:30 -06002859 }
2860
Dave Houlton533be9f2018-03-26 17:08:30 -06002861 if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.dstOffset.z)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002862 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01788" : "VUID-vkCmdCopyImage-dstImage-01788";
2863 skip |= LogError(dst_state->image, vuid, "%s: pRegion[%d] dstOffset.z is %d. For 2D images the z-offset must be 0.",
2864 func_name, i, region.dstOffset.z);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002865 }
2866
sfricke-samsung30b094c2020-05-30 11:42:11 -07002867 // Handle difference between Maintenance 1
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06002868 if (device_extensions.vk_khr_maintenance1) {
sfricke-samsung30b094c2020-05-30 11:42:11 -07002869 if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2870 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002871 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-04443" : "VUID-vkCmdCopyImage-srcImage-04443";
2872 skip |= LogError(src_state->image, vuid,
2873 "%s: pRegion[%d] srcSubresource.baseArrayLayer is %d and srcSubresource.layerCount "
2874 "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2875 func_name, i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
sfricke-samsung30b094c2020-05-30 11:42:11 -07002876 }
2877 }
Dave Houlton6f9059e2017-05-02 17:15:13 -06002878 if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
Dave Houltonee281a52017-12-08 13:51:02 -07002879 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002880 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-04444" : "VUID-vkCmdCopyImage-dstImage-04444";
2881 skip |= LogError(dst_state->image, vuid,
2882 "%s: pRegion[%d] dstSubresource.baseArrayLayer is %d and dstSubresource.layerCount "
2883 "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2884 func_name, i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002885 }
2886 }
2887 } else { // Pre maint 1
2888 if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D || dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
sfricke-samsung30b094c2020-05-30 11:42:11 -07002889 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002890 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00139" : "VUID-vkCmdCopyImage-srcImage-00139";
2891 skip |= LogError(src_state->image, vuid,
2892 "%s: pRegion[%d] srcSubresource.baseArrayLayer is %d and "
sfricke-samsung30b094c2020-05-30 11:42:11 -07002893 "srcSubresource.layerCount is %d. For copies with either source or dest of type "
2894 "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
Jeff Leger178b1e52020-10-05 12:22:23 -04002895 func_name, i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
sfricke-samsung30b094c2020-05-30 11:42:11 -07002896 }
Dave Houltonee281a52017-12-08 13:51:02 -07002897 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002898 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00139" : "VUID-vkCmdCopyImage-srcImage-00139";
2899 skip |= LogError(dst_state->image, vuid,
2900 "%s: pRegion[%d] dstSubresource.baseArrayLayer is %d and "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002901 "dstSubresource.layerCount is %d. For copies with either source or dest of type "
2902 "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
Jeff Leger178b1e52020-10-05 12:22:23 -04002903 func_name, i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002904 }
2905 }
2906 }
2907
Dave Houltonc991cc92018-03-06 11:08:51 -07002908 // Dest checks that apply only to compressed images (or to _422 images if ycbcr enabled)
2909 if (FormatIsCompressed(dst_state->createInfo.format) ||
2910 (ext_ycbcr && FormatIsSinglePlane_422(dst_state->createInfo.format))) {
Dave Houltona585d132019-01-18 13:05:42 -07002911 const VkExtent3D block_size = FormatTexelBlockExtent(dst_state->createInfo.format);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002912
2913 // image offsets must be multiples of block dimensions
Dave Houltonee281a52017-12-08 13:51:02 -07002914 if ((SafeModulo(region.dstOffset.x, block_size.width) != 0) ||
2915 (SafeModulo(region.dstOffset.y, block_size.height) != 0) ||
2916 (SafeModulo(region.dstOffset.z, block_size.depth) != 0)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002917 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01731" : "VUID-vkCmdCopyImage-dstImage-01731";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002918 skip |= LogError(dst_state->image, vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04002919 "%s: pRegion[%d] dstOffset (%d, %d) must be multiples of the compressed image's "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002920 "texel width & height (%d, %d).",
Jeff Leger178b1e52020-10-05 12:22:23 -04002921 func_name, i, region.dstOffset.x, region.dstOffset.y, block_size.width, block_size.height);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002922 }
2923
Dave Houlton94a00372017-12-14 15:08:47 -07002924 const VkExtent3D mip_extent = GetImageSubresourceExtent(dst_state, &(region.dstSubresource));
Dave Houltonee281a52017-12-08 13:51:02 -07002925 if ((SafeModulo(dst_copy_extent.width, block_size.width) != 0) &&
2926 (dst_copy_extent.width + region.dstOffset.x != mip_extent.width)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002927 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01732" : "VUID-vkCmdCopyImage-dstImage-01732";
2928 skip |= LogError(dst_state->image, vuid,
2929 "%s: pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
2930 "block width (%d), or when added to dstOffset.x (%d) must equal the image subresource width (%d).",
2931 func_name, i, dst_copy_extent.width, block_size.width, region.dstOffset.x, mip_extent.width);
Mark Lobodzinskid0788802017-10-19 15:38:59 -06002932 }
2933
Dave Houltonee281a52017-12-08 13:51:02 -07002934 // Extent height must be a multiple of block height, or dst_copy_extent+offset height must equal subresource height
2935 if ((SafeModulo(dst_copy_extent.height, block_size.height) != 0) &&
2936 (dst_copy_extent.height + region.dstOffset.y != mip_extent.height)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002937 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01733" : "VUID-vkCmdCopyImage-dstImage-01733";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002938 skip |= LogError(dst_state->image, vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04002939 "%s: pRegion[%d] dst_copy_extent height (%d) must be a multiple of the compressed "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07002940 "texture block height (%d), or when added to dstOffset.y (%d) must equal the image subresource "
2941 "height (%d).",
Jeff Leger178b1e52020-10-05 12:22:23 -04002942 func_name, i, dst_copy_extent.height, block_size.height, region.dstOffset.y, mip_extent.height);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002943 }
2944
Dave Houltonee281a52017-12-08 13:51:02 -07002945 // Extent depth must be a multiple of block depth, or dst_copy_extent+offset depth must equal subresource depth
2946 uint32_t copy_depth = (slice_override ? depth_slices : dst_copy_extent.depth);
2947 if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.dstOffset.z != mip_extent.depth)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002948 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01734" : "VUID-vkCmdCopyImage-dstImage-01734";
2949 skip |= LogError(dst_state->image, vuid,
2950 "%s: pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
2951 "block depth (%d), or when added to dstOffset.z (%d) must equal the image subresource depth (%d).",
2952 func_name, i, dst_copy_extent.depth, block_size.depth, region.dstOffset.z, mip_extent.depth);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002953 }
2954 } // Compressed
2955 }
2956 return skip;
2957}
2958
Jeff Leger178b1e52020-10-05 12:22:23 -04002959template <typename RegionType>
2960bool CoreChecks::ValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
2961 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
2962 const RegionType *pRegions, CopyCommandVersion version) const {
John Zulaufe2b7bcb2019-07-05 16:08:39 -06002963 const auto *cb_node = GetCBState(commandBuffer);
2964 const auto *src_image_state = GetImageState(srcImage);
2965 const auto *dst_image_state = GetImageState(dstImage);
sfricke-samsungdce5f692020-03-07 13:59:31 -08002966 const VkFormat src_format = src_image_state->createInfo.format;
2967 const VkFormat dst_format = dst_image_state->createInfo.format;
Jeff Leger178b1e52020-10-05 12:22:23 -04002968 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002969 bool skip = false;
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07002970
Jeff Leger178b1e52020-10-05 12:22:23 -04002971 const char *func_name = is_2khr ? "vkCmdCopyImage2KHR()" : "vkCmdCopyImage()";
2972 const CMD_TYPE cmd_type = is_2khr ? CMD_COPYIMAGE2KHR : CMD_COPYIMAGE;
2973 const char *vuid;
2974
2975 skip = ValidateImageCopyData(regionCount, pRegions, src_image_state, dst_image_state, version);
Dave Houlton6f9059e2017-05-02 17:15:13 -06002976
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07002977 VkCommandBuffer command_buffer = cb_node->commandBuffer;
2978
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07002979 for (uint32_t i = 0; i < regionCount; i++) {
Jeff Leger178b1e52020-10-05 12:22:23 -04002980 const RegionType region = pRegions[i];
Dave Houltonee281a52017-12-08 13:51:02 -07002981
2982 // For comp/uncomp copies, the copy extent for the dest image must be adjusted
2983 VkExtent3D src_copy_extent = region.extent;
sfricke-samsungdce5f692020-03-07 13:59:31 -08002984 VkExtent3D dst_copy_extent = GetAdjustedDestImageExtent(src_format, dst_format, region.extent);
Dave Houltonee281a52017-12-08 13:51:02 -07002985
Dave Houlton6f9059e2017-05-02 17:15:13 -06002986 bool slice_override = false;
2987 uint32_t depth_slices = 0;
2988
2989 // Special case for copying between a 1D/2D array and a 3D image
2990 // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
2991 if ((VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType) &&
2992 (VK_IMAGE_TYPE_3D != dst_image_state->createInfo.imageType)) {
Dave Houltonee281a52017-12-08 13:51:02 -07002993 depth_slices = region.dstSubresource.layerCount; // Slice count from 2D subresource
Dave Houlton6f9059e2017-05-02 17:15:13 -06002994 slice_override = (depth_slices != 1);
2995 } else if ((VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType) &&
2996 (VK_IMAGE_TYPE_3D != src_image_state->createInfo.imageType)) {
Dave Houltonee281a52017-12-08 13:51:02 -07002997 depth_slices = region.srcSubresource.layerCount; // Slice count from 2D subresource
Dave Houlton6f9059e2017-05-02 17:15:13 -06002998 slice_override = (depth_slices != 1);
2999 }
3000
Jeff Leger178b1e52020-10-05 12:22:23 -04003001 skip |= ValidateImageSubresourceLayers(cb_node, &region.srcSubresource, func_name, "srcSubresource", i);
3002 skip |= ValidateImageSubresourceLayers(cb_node, &region.dstSubresource, func_name, "dstSubresource", i);
3003 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcSubresource-01696" : "VUID-vkCmdCopyImage-srcSubresource-01696";
3004 skip |=
3005 ValidateImageMipLevel(cb_node, src_image_state, region.srcSubresource.mipLevel, i, func_name, "srcSubresource", vuid);
3006 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstSubresource-01697" : "VUID-vkCmdCopyImage-dstSubresource-01697";
3007 skip |=
3008 ValidateImageMipLevel(cb_node, dst_image_state, region.dstSubresource.mipLevel, i, func_name, "dstSubresource", vuid);
3009 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcSubresource-01698" : "VUID-vkCmdCopyImage-srcSubresource-01698";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07003010 skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, region.srcSubresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04003011 region.srcSubresource.layerCount, i, func_name, "srcSubresource", vuid);
3012 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstSubresource-01699" : "VUID-vkCmdCopyImage-dstSubresource-01699";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07003013 skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, region.dstSubresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04003014 region.dstSubresource.layerCount, i, func_name, "dstSubresource", vuid);
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003015
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06003016 if (device_extensions.vk_khr_maintenance1) {
Dave Houlton6f9059e2017-05-02 17:15:13 -06003017 // No chance of mismatch if we're overriding depth slice count
3018 if (!slice_override) {
3019 // The number of depth slices in srcSubresource and dstSubresource must match
3020 // Depth comes from layerCount for 1D,2D resources, from extent.depth for 3D
3021 uint32_t src_slices =
Dave Houltonee281a52017-12-08 13:51:02 -07003022 (VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType ? src_copy_extent.depth
3023 : region.srcSubresource.layerCount);
Dave Houlton6f9059e2017-05-02 17:15:13 -06003024 uint32_t dst_slices =
Dave Houltonee281a52017-12-08 13:51:02 -07003025 (VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType ? dst_copy_extent.depth
3026 : region.dstSubresource.layerCount);
Dave Houlton6f9059e2017-05-02 17:15:13 -06003027 if (src_slices != dst_slices) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003028 vuid = is_2khr ? "VUID-VkImageCopy2KHR-extent-00140" : "VUID-VkImageCopy-extent-00140";
3029 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003030 "%s: number of depth slices in source (%u) and destination (%u) subresources for pRegions[%u] "
3031 "do not match.",
3032 func_name, src_slices, dst_slices, i);
Dave Houlton6f9059e2017-05-02 17:15:13 -06003033 }
3034 }
3035 } else {
Mike Schuchardt64b5bb72017-03-21 16:33:26 -06003036 // For each region the layerCount member of srcSubresource and dstSubresource must match
Dave Houltonee281a52017-12-08 13:51:02 -07003037 if (region.srcSubresource.layerCount != region.dstSubresource.layerCount) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003038 vuid = is_2khr ? "VUID-VkImageCopy2KHR-layerCount-00138" : "VUID-VkImageCopy-layerCount-00138";
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003039 skip |=
3040 LogError(command_buffer, vuid,
3041 "%s: number of layers in source (%u) and destination (%u) subresources for pRegions[%u] do not match",
3042 func_name, region.srcSubresource.layerCount, region.dstSubresource.layerCount, i);
Mike Schuchardt64b5bb72017-03-21 16:33:26 -06003043 }
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003044 }
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003045
Dave Houltonc991cc92018-03-06 11:08:51 -07003046 // Do multiplane-specific checks, if extension enabled
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06003047 if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003048 if ((!FormatIsMultiplane(src_format)) && (!FormatIsMultiplane(dst_format))) {
3049 // If neither image is multi-plane the aspectMask member of src and dst must match
3050 if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
3051 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01551" : "VUID-vkCmdCopyImage-srcImage-01551";
3052 skip |= LogError(command_buffer, vuid,
3053 "%s: Copy between non-multiplane images with differing aspectMasks in pRegions[%u] with "
3054 "source (0x%x) destination (0x%x).",
3055 func_name, i, region.srcSubresource.aspectMask, region.dstSubresource.aspectMask);
3056 }
3057 } else {
3058 // Source image multiplane checks
3059 uint32_t planes = FormatPlaneCount(src_format);
3060 VkImageAspectFlags aspect = region.srcSubresource.aspectMask;
3061 if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT)) {
3062 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01552" : "VUID-vkCmdCopyImage-srcImage-01552";
3063 skip |= LogError(command_buffer, vuid,
3064 "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) is invalid for 2-plane format.", func_name,
3065 i, aspect);
3066 }
3067 if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT) &&
3068 (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT)) {
3069 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01553" : "VUID-vkCmdCopyImage-srcImage-01553";
3070 skip |= LogError(command_buffer, vuid,
3071 "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) is invalid for 3-plane format.", func_name,
3072 i, aspect);
3073 }
3074 // Single-plane to multi-plane
3075 if ((!FormatIsMultiplane(src_format)) && (FormatIsMultiplane(dst_format)) &&
3076 (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
3077 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01557" : "VUID-vkCmdCopyImage-dstImage-01557";
3078 skip |= LogError(command_buffer, vuid,
3079 "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) is not VK_IMAGE_ASPECT_COLOR_BIT.",
3080 func_name, i, aspect);
3081 }
Dave Houltonc991cc92018-03-06 11:08:51 -07003082
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003083 // Dest image multiplane checks
3084 planes = FormatPlaneCount(dst_format);
3085 aspect = region.dstSubresource.aspectMask;
3086 if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT)) {
3087 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01554" : "VUID-vkCmdCopyImage-dstImage-01554";
3088 skip |= LogError(command_buffer, vuid,
3089 "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) is invalid for 2-plane format.", func_name,
3090 i, aspect);
3091 }
3092 if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT) &&
3093 (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT)) {
3094 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01555" : "VUID-vkCmdCopyImage-dstImage-01555";
3095 skip |= LogError(command_buffer, vuid,
3096 "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) is invalid for 3-plane format.", func_name,
3097 i, aspect);
3098 }
3099 // Multi-plane to single-plane
3100 if ((FormatIsMultiplane(src_format)) && (!FormatIsMultiplane(dst_format)) &&
3101 (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
3102 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01556" : "VUID-vkCmdCopyImage-srcImage-01556";
3103 skip |= LogError(command_buffer, vuid,
3104 "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) is not VK_IMAGE_ASPECT_COLOR_BIT.",
3105 func_name, i, aspect);
3106 }
3107 }
3108 } else {
3109 // !vk_khr_sampler_ycbcr_conversion
Dave Houltonf5217612018-02-02 16:18:52 -07003110 // not multi-plane, the aspectMask member of srcSubresource and dstSubresource must match
3111 if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003112 vuid = is_2khr ? "VUID-VkImageCopy2KHR-aspectMask-00137" : "VUID-VkImageCopy-aspectMask-00137";
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003113 skip |= LogError(
3114 command_buffer, vuid,
3115 "%s: Copy between images with differing aspectMasks in pRegions[%u] with source (0x%x) destination (0x%x).",
3116 func_name, i, region.srcSubresource.aspectMask, region.dstSubresource.aspectMask);
Dave Houltonf5217612018-02-02 16:18:52 -07003117 }
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003118 }
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003119
Dave Houlton4eaaf3a2017-03-14 11:31:20 -06003120 // For each region, the aspectMask member of srcSubresource must be present in the source image
sfricke-samsungdce5f692020-03-07 13:59:31 -08003121 if (!VerifyAspectsPresent(region.srcSubresource.aspectMask, src_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003122 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-aspectMask-00142" : "VUID-vkCmdCopyImage-aspectMask-00142";
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003123 skip |=
3124 LogError(command_buffer, vuid,
3125 "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) cannot specify aspects not present in source image.",
3126 func_name, i, region.srcSubresource.aspectMask);
Dave Houlton4eaaf3a2017-03-14 11:31:20 -06003127 }
3128
3129 // For each region, the aspectMask member of dstSubresource must be present in the destination image
sfricke-samsungdce5f692020-03-07 13:59:31 -08003130 if (!VerifyAspectsPresent(region.dstSubresource.aspectMask, dst_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003131 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-aspectMask-00143" : "VUID-vkCmdCopyImage-aspectMask-00143";
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003132 skip |= LogError(
3133 command_buffer, vuid,
3134 "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) cannot specify aspects not present in destination image.",
3135 func_name, i, region.dstSubresource.aspectMask);
Dave Houlton4eaaf3a2017-03-14 11:31:20 -06003136 }
3137
Dave Houltonfc1a4052017-04-27 14:32:45 -06003138 // Each dimension offset + extent limits must fall with image subresource extent
Dave Houltonee281a52017-12-08 13:51:02 -07003139 VkExtent3D subresource_extent = GetImageSubresourceExtent(src_image_state, &(region.srcSubresource));
3140 if (slice_override) src_copy_extent.depth = depth_slices;
3141 uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &src_copy_extent, &subresource_extent);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003142 if (extent_check & kXBit) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003143 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-00144" : "VUID-vkCmdCopyImage-srcOffset-00144";
3144 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003145 "%s: Source image pRegion[%u] x-dimension offset [%1d] + extent [%1d] exceeds subResource "
Jeff Leger178b1e52020-10-05 12:22:23 -04003146 "width [%1d].",
3147 func_name, i, region.srcOffset.x, src_copy_extent.width, subresource_extent.width);
Dave Houltonfc1a4052017-04-27 14:32:45 -06003148 }
3149
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003150 if (extent_check & kYBit) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003151 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-00145" : "VUID-vkCmdCopyImage-srcOffset-00145";
3152 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003153 "%s: Source image pRegion[%u] y-dimension offset [%1d] + extent [%1d] exceeds subResource "
Jeff Leger178b1e52020-10-05 12:22:23 -04003154 "height [%1d].",
3155 func_name, i, region.srcOffset.y, src_copy_extent.height, subresource_extent.height);
Dave Houltonfc1a4052017-04-27 14:32:45 -06003156 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003157 if (extent_check & kZBit) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003158 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-00147" : "VUID-vkCmdCopyImage-srcOffset-00147";
3159 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003160 "%s: Source image pRegion[%u] z-dimension offset [%1d] + extent [%1d] exceeds subResource "
Jeff Leger178b1e52020-10-05 12:22:23 -04003161 "depth [%1d].",
3162 func_name, i, region.srcOffset.z, src_copy_extent.depth, subresource_extent.depth);
Dave Houltonfc1a4052017-04-27 14:32:45 -06003163 }
3164
Dave Houltonee281a52017-12-08 13:51:02 -07003165 // Adjust dest extent if necessary
3166 subresource_extent = GetImageSubresourceExtent(dst_image_state, &(region.dstSubresource));
3167 if (slice_override) dst_copy_extent.depth = depth_slices;
3168
3169 extent_check = ExceedsBounds(&(region.dstOffset), &dst_copy_extent, &subresource_extent);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003170 if (extent_check & kXBit) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003171 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-00150" : "VUID-vkCmdCopyImage-dstOffset-00150";
3172 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003173 "%s: Dest image pRegion[%u] x-dimension offset [%1d] + extent [%1d] exceeds subResource "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003174 "width [%1d].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003175 func_name, i, region.dstOffset.x, dst_copy_extent.width, subresource_extent.width);
Dave Houltonfc1a4052017-04-27 14:32:45 -06003176 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003177 if (extent_check & kYBit) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003178 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-00151" : "VUID-vkCmdCopyImage-dstOffset-00151";
3179 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003180 "%s): Dest image pRegion[%u] y-dimension offset [%1d] + extent [%1d] exceeds subResource "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003181 "height [%1d].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003182 func_name, i, region.dstOffset.y, dst_copy_extent.height, subresource_extent.height);
Dave Houltonfc1a4052017-04-27 14:32:45 -06003183 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003184 if (extent_check & kZBit) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003185 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-00153" : "VUID-vkCmdCopyImage-dstOffset-00153";
3186 skip |= LogError(command_buffer, vuid,
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003187 "%s: Dest image pRegion[%u] z-dimension offset [%1d] + extent [%1d] exceeds subResource "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003188 "depth [%1d].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003189 func_name, i, region.dstOffset.z, dst_copy_extent.depth, subresource_extent.depth);
Dave Houltonfc1a4052017-04-27 14:32:45 -06003190 }
3191
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003192 // The union of all source regions, and the union of all destination regions, specified by the elements of regions,
3193 // must not overlap in memory
3194 if (src_image_state->image == dst_image_state->image) {
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07003195 for (uint32_t j = 0; j < regionCount; j++) {
3196 if (RegionIntersects(&region, &pRegions[j], src_image_state->createInfo.imageType,
sfricke-samsungdce5f692020-03-07 13:59:31 -08003197 FormatIsMultiplane(src_format))) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003198 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-pRegions-00124" : "VUID-vkCmdCopyImage-pRegions-00124";
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003199 skip |= LogError(command_buffer, vuid, "%s: pRegion[%u] src overlaps with pRegions[%u].", func_name, i, j);
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003200 }
3201 }
3202 }
sfricke-samsung48172ca2020-02-13 23:38:11 -08003203
3204 // Check depth for 2D as post Maintaince 1 requires both while prior only required one to be 2D
3205 if (device_extensions.vk_khr_maintenance1) {
3206 if (((VK_IMAGE_TYPE_2D == src_image_state->createInfo.imageType) &&
3207 (VK_IMAGE_TYPE_2D == dst_image_state->createInfo.imageType)) &&
3208 (src_copy_extent.depth != 1)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003209 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01790" : "VUID-vkCmdCopyImage-srcImage-01790";
3210 skip |= LogError(command_buffer, vuid,
3211 "%s: pRegion[%u] both srcImage and dstImage are 2D and extent.depth is %u and has to be 1",
3212 func_name, i, src_copy_extent.depth);
sfricke-samsung48172ca2020-02-13 23:38:11 -08003213 }
3214 } else {
3215 if (((VK_IMAGE_TYPE_2D == src_image_state->createInfo.imageType) ||
3216 (VK_IMAGE_TYPE_2D == dst_image_state->createInfo.imageType)) &&
3217 (src_copy_extent.depth != 1)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003218 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01789" : "VUID-vkCmdCopyImage-srcImage-01789";
3219 skip |= LogError(command_buffer, vuid,
3220 "%s: pRegion[%u] either srcImage or dstImage is 2D and extent.depth is %u and has to be 1",
3221 func_name, i, src_copy_extent.depth);
sfricke-samsung48172ca2020-02-13 23:38:11 -08003222 }
3223 }
3224
3225 // Check if 2D with 3D and depth not equal to 2D layerCount
3226 if ((VK_IMAGE_TYPE_2D == src_image_state->createInfo.imageType) &&
3227 (VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType) &&
3228 (src_copy_extent.depth != region.srcSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003229 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01791" : "VUID-vkCmdCopyImage-srcImage-01791";
3230 skip |= LogError(command_buffer, vuid,
3231 "%s: pRegion[%u] srcImage is 2D, dstImage is 3D and extent.depth is %u and has to be "
sfricke-samsung48172ca2020-02-13 23:38:11 -08003232 "srcSubresource.layerCount (%u)",
Jeff Leger178b1e52020-10-05 12:22:23 -04003233 func_name, i, src_copy_extent.depth, region.srcSubresource.layerCount);
sfricke-samsung48172ca2020-02-13 23:38:11 -08003234 } else if ((VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType) &&
3235 (VK_IMAGE_TYPE_2D == dst_image_state->createInfo.imageType) &&
3236 (src_copy_extent.depth != region.dstSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003237 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01792" : "VUID-vkCmdCopyImage-dstImage-01792";
3238 skip |= LogError(command_buffer, vuid,
3239 "%s: pRegion[%u] srcImage is 3D, dstImage is 2D and extent.depth is %u and has to be "
sfricke-samsung48172ca2020-02-13 23:38:11 -08003240 "dstSubresource.layerCount (%u)",
Jeff Leger178b1e52020-10-05 12:22:23 -04003241 func_name, i, src_copy_extent.depth, region.dstSubresource.layerCount);
sfricke-samsung48172ca2020-02-13 23:38:11 -08003242 }
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003243
3244 // Check for multi-plane format compatiblity
3245 if (FormatIsMultiplane(src_format) || FormatIsMultiplane(dst_format)) {
3246 size_t src_format_size = 0;
3247 size_t dst_format_size = 0;
3248 if (FormatIsMultiplane(src_format)) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003249 const VkFormat plane_format = FindMultiplaneCompatibleFormat(src_format, region.srcSubresource.aspectMask);
3250 src_format_size = FormatElementSize(plane_format);
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003251 } else {
3252 src_format_size = FormatElementSize(src_format);
3253 }
3254 if (FormatIsMultiplane(dst_format)) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003255 const VkFormat plane_format = FindMultiplaneCompatibleFormat(dst_format, region.dstSubresource.aspectMask);
3256 dst_format_size = FormatElementSize(plane_format);
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003257 } else {
3258 dst_format_size = FormatElementSize(dst_format);
3259 }
3260 // If size is still zero, then format is invalid and will be caught in another VU
3261 if ((src_format_size != dst_format_size) && (src_format_size != 0) && (dst_format_size != 0)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003262 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-None-01549" : "VUID-vkCmdCopyImage-None-01549";
3263 skip |= LogError(command_buffer, vuid,
3264 "%s: pRegions[%u] called with non-compatible image formats. "
3265 "The src format %s with aspectMask %s is not compatible with dst format %s aspectMask %s.",
3266 func_name, i, string_VkFormat(src_format),
3267 string_VkImageAspectFlags(region.srcSubresource.aspectMask).c_str(), string_VkFormat(dst_format),
3268 string_VkImageAspectFlags(region.dstSubresource.aspectMask).c_str());
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003269 }
3270 }
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003271 }
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003272
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003273 // The formats of non-multiplane src_image and dst_image must be compatible. Formats are considered compatible if their texel
3274 // size in bytes is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT
3275 // because because both texels are 4 bytes in size.
3276 if (!FormatIsMultiplane(src_format) && !FormatIsMultiplane(dst_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003277 const char *compatible_vuid =
3278 (device_extensions.vk_khr_sampler_ycbcr_conversion)
3279 ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01548" : "VUID-vkCmdCopyImage-srcImage-01548")
3280 : (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00135" : "VUID-vkCmdCopyImage-srcImage-00135");
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003281 // Depth/stencil formats must match exactly.
3282 if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
3283 if (src_format != dst_format) {
3284 skip |= LogError(command_buffer, compatible_vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04003285 "%s: Depth/stencil formats must match exactly for src (%s) and dst (%s).", func_name,
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003286 string_VkFormat(src_format), string_VkFormat(dst_format));
3287 }
3288 } else {
Jeff Leger178b1e52020-10-05 12:22:23 -04003289 if (FormatElementSize(src_format) != FormatElementSize(dst_format)) {
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003290 skip |= LogError(command_buffer, compatible_vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04003291 "%s: Unmatched image format sizes. "
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003292 "The src format %s has size of %zu and dst format %s has size of %zu.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003293 func_name, string_VkFormat(src_format), FormatElementSize(src_format), string_VkFormat(dst_format),
sfricke-samsung99dc12c2020-04-23 01:52:01 -07003294 FormatElementSize(dst_format));
3295 }
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003296 }
3297 }
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003298
Dave Houlton33c22b72017-02-28 13:16:02 -07003299 // Source and dest image sample counts must match
3300 if (src_image_state->createInfo.samples != dst_image_state->createInfo.samples) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003301 std::stringstream ss;
3302 ss << func_name << " called on image pair with non-identical sample counts.";
3303 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00136" : "VUID-vkCmdCopyImage-srcImage-00136";
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08003304 skip |=
3305 LogError(command_buffer, vuid, "%s: The src image sample count (%s) dose not match the dst image sample count (%s).",
3306 func_name, string_VkSampleCountFlagBits(src_image_state->createInfo.samples),
3307 string_VkSampleCountFlagBits(dst_image_state->createInfo.samples));
Dave Houlton33c22b72017-02-28 13:16:02 -07003308 }
3309
Tony-LunarG5a066372021-01-21 10:31:34 -07003310 vuid = (device_extensions.vk_khr_sampler_ycbcr_conversion)
3311 ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01546" : "VUID-vkCmdCopyImage-srcImage-01546")
3312 : (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00127" : "VUID-vkCmdCopyImage-srcImage-00127");
Jeff Leger178b1e52020-10-05 12:22:23 -04003313 skip |= ValidateMemoryIsBoundToImage(src_image_state, func_name, vuid);
Tony-LunarG5a066372021-01-21 10:31:34 -07003314 vuid = (device_extensions.vk_khr_sampler_ycbcr_conversion)
3315 ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01547" : "VUID-vkCmdCopyImage-dstImage-01547")
3316 : (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-00132" : "VUID-vkCmdCopyImage-dstImage-00132");
3317 skip |= ValidateMemoryIsBoundToImage(dst_image_state, func_name, vuid);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003318 // Validate that SRC & DST images have correct usage flags set
Jeff Leger178b1e52020-10-05 12:22:23 -04003319 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00126" : "VUID-vkCmdCopyImage-srcImage-00126";
3320 skip |= ValidateImageUsageFlags(src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
3321 "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
3322 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-00131" : "VUID-vkCmdCopyImage-dstImage-00131";
3323 skip |= ValidateImageUsageFlags(dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
3324 "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
3325 vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-01825" : "VUID-vkCmdCopyImage-commandBuffer-01825";
3326 skip |= ValidateProtectedImage(cb_node, src_image_state, func_name, vuid);
3327 vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-01826" : "VUID-vkCmdCopyImage-commandBuffer-01826";
3328 skip |= ValidateProtectedImage(cb_node, dst_image_state, func_name, vuid);
3329 vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-01827" : "VUID-vkCmdCopyImage-commandBuffer-01827";
3330 skip |= ValidateUnprotectedImage(cb_node, dst_image_state, func_name, vuid);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003331
3332 // Validation for VK_EXT_fragment_density_map
3333 if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003334 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-02542" : "VUID-vkCmdCopyImage-dstImage-02542";
3335 skip |=
3336 LogError(command_buffer, vuid,
3337 "%s: srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT", func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003338 }
3339 if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003340 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-02542" : "VUID-vkCmdCopyImage-dstImage-02542";
3341 skip |=
3342 LogError(command_buffer, vuid,
3343 "%s: dstImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT", func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003344 }
3345
Mark Lobodzinski8c193c02020-02-20 09:20:33 -07003346 if (device_extensions.vk_khr_maintenance1) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003347 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01995" : "VUID-vkCmdCopyImage-srcImage-01995";
3348 skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, func_name, vuid);
3349 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01996" : "VUID-vkCmdCopyImage-dstImage-01996";
3350 skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, func_name, vuid);
Cort Stratton186b1a22018-05-01 20:18:06 -04003351 }
Jeff Leger178b1e52020-10-05 12:22:23 -04003352 vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-cmdpool" : "VUID-vkCmdCopyImage-commandBuffer-cmdpool";
3353 skip |= ValidateCmdQueueFlags(cb_node, func_name, VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, vuid);
3354 skip |= ValidateCmd(cb_node, cmd_type, func_name);
3355 vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-renderpass" : "VUID-vkCmdCopyImage-renderpass";
3356 skip |= InsideRenderPass(cb_node, func_name, vuid);
Tobin Ehlisc8266452017-04-07 12:20:30 -06003357 bool hit_error = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04003358
3359 const char *invalid_src_layout_vuid =
3360 (src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3361 ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImageLayout-01917" : "VUID-vkCmdCopyImage-srcImageLayout-01917")
3362 : (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImageLayout-00129" : "VUID-vkCmdCopyImage-srcImageLayout-00129");
3363 const char *invalid_dst_layout_vuid =
3364 (dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3365 ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImageLayout-01395" : "VUID-vkCmdCopyImage-dstImageLayout-01395")
3366 : (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImageLayout-00134" : "VUID-vkCmdCopyImage-dstImageLayout-00134");
3367
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07003368 for (uint32_t i = 0; i < regionCount; ++i) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003369 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImageLayout-00128" : "VUID-vkCmdCopyImage-srcImageLayout-00128";
Mark Lobodzinski8564e442019-03-07 12:49:41 -07003370 skip |= VerifyImageLayout(cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04003371 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, invalid_src_layout_vuid, vuid, &hit_error);
3372 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImageLayout-00133" : "VUID-vkCmdCopyImage-dstImageLayout-00133";
Mark Lobodzinski8564e442019-03-07 12:49:41 -07003373 skip |= VerifyImageLayout(cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04003374 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, invalid_dst_layout_vuid, vuid, &hit_error);
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07003375 skip |= ValidateCopyImageTransferGranularityRequirements(cb_node, src_image_state, dst_image_state, &pRegions[i], i,
Jeff Leger178b1e52020-10-05 12:22:23 -04003376 func_name, version);
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003377 }
3378
Mark Lobodzinskib39d2ec2017-02-02 14:38:47 -07003379 return skip;
3380}
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003381
Jeff Leger178b1e52020-10-05 12:22:23 -04003382bool CoreChecks::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3383 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3384 const VkImageCopy *pRegions) const {
3385 return ValidateCmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions,
3386 COPY_COMMAND_VERSION_1);
3387}
3388
3389bool CoreChecks::PreCallValidateCmdCopyImage2KHR(VkCommandBuffer commandBuffer, const VkCopyImageInfo2KHR *pCopyImageInfo) const {
3390 return ValidateCmdCopyImage(commandBuffer, pCopyImageInfo->srcImage, pCopyImageInfo->srcImageLayout, pCopyImageInfo->dstImage,
3391 pCopyImageInfo->dstImageLayout, pCopyImageInfo->regionCount, pCopyImageInfo->pRegions,
3392 COPY_COMMAND_VERSION_2);
3393}
3394
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07003395void CoreChecks::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3396 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3397 const VkImageCopy *pRegions) {
John Zulauf8f6d4ee2019-07-05 16:31:57 -06003398 StateTracker::PreCallRecordCmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
3399 pRegions);
Mark Lobodzinskicefe42f2019-04-25 12:16:27 -06003400 auto cb_node = GetCBState(commandBuffer);
Mark Lobodzinski8ddc23f2019-03-06 11:48:49 -07003401 auto src_image_state = GetImageState(srcImage);
3402 auto dst_image_state = GetImageState(dstImage);
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07003403
Tobin Ehlise35b66a2017-03-15 12:18:31 -06003404 // Make sure that all image slices are updated to correct layout
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07003405 for (uint32_t i = 0; i < regionCount; ++i) {
John Zulauff660ad62019-03-23 07:16:05 -06003406 SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].srcSubresource, srcImageLayout);
3407 SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
Tobin Ehlise35b66a2017-03-15 12:18:31 -06003408 }
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07003409}
3410
Jeff Leger178b1e52020-10-05 12:22:23 -04003411void CoreChecks::PreCallRecordCmdCopyImage2KHR(VkCommandBuffer commandBuffer, const VkCopyImageInfo2KHR *pCopyImageInfo) {
3412 StateTracker::PreCallRecordCmdCopyImage2KHR(commandBuffer, pCopyImageInfo);
3413 auto cb_node = GetCBState(commandBuffer);
3414 auto src_image_state = GetImageState(pCopyImageInfo->srcImage);
3415 auto dst_image_state = GetImageState(pCopyImageInfo->dstImage);
3416
3417 // Make sure that all image slices are updated to correct layout
3418 for (uint32_t i = 0; i < pCopyImageInfo->regionCount; ++i) {
3419 SetImageInitialLayout(cb_node, *src_image_state, pCopyImageInfo->pRegions[i].srcSubresource,
3420 pCopyImageInfo->srcImageLayout);
3421 SetImageInitialLayout(cb_node, *dst_image_state, pCopyImageInfo->pRegions[i].dstSubresource,
3422 pCopyImageInfo->dstImageLayout);
3423 }
3424}
3425
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003426// Returns true if sub_rect is entirely contained within rect
3427static inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
3428 if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003429 (sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height)) {
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003430 return false;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003431 }
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003432 return true;
3433}
3434
Mark Lobodzinskif933db92019-03-09 12:58:03 -07003435bool CoreChecks::ValidateClearAttachmentExtent(VkCommandBuffer command_buffer, uint32_t attachment_index,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06003436 const FRAMEBUFFER_STATE *framebuffer, uint32_t fb_attachment,
locke-lunargfc78e932020-11-19 17:06:24 -07003437 const VkRect2D &render_area, uint32_t rect_count, const VkClearRect *clear_rects,
3438 const CMD_BUFFER_STATE *primary_cb_state) const {
John Zulauf3a548ef2019-02-01 16:14:07 -07003439 bool skip = false;
John Zulauff2582972019-02-09 14:53:30 -07003440 const IMAGE_VIEW_STATE *image_view_state = nullptr;
3441 if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) && (fb_attachment < framebuffer->createInfo.attachmentCount)) {
locke-lunargfc78e932020-11-19 17:06:24 -07003442 image_view_state = GetActiveAttachmentImageViewState(GetCBState(command_buffer), fb_attachment, primary_cb_state);
John Zulauff2582972019-02-09 14:53:30 -07003443 }
John Zulauf3a548ef2019-02-01 16:14:07 -07003444
3445 for (uint32_t j = 0; j < rect_count; j++) {
3446 if (!ContainsRect(render_area, clear_rects[j].rect)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003447 skip |= LogError(command_buffer, "VUID-vkCmdClearAttachments-pRects-00016",
3448 "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
3449 "the current render pass instance.",
3450 j);
John Zulauf3a548ef2019-02-01 16:14:07 -07003451 }
3452
3453 if (image_view_state) {
3454 // The layers specified by a given element of pRects must be contained within every attachment that
3455 // pAttachments refers to
3456 const auto attachment_layer_count = image_view_state->create_info.subresourceRange.layerCount;
3457 if ((clear_rects[j].baseArrayLayer >= attachment_layer_count) ||
3458 (clear_rects[j].baseArrayLayer + clear_rects[j].layerCount > attachment_layer_count)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003459 skip |= LogError(command_buffer, "VUID-vkCmdClearAttachments-pRects-00017",
3460 "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers "
3461 "of pAttachment[%d].",
3462 j, attachment_index);
John Zulauf3a548ef2019-02-01 16:14:07 -07003463 }
3464 }
3465 }
3466 return skip;
3467}
3468
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07003469bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
3470 const VkClearAttachment *pAttachments, uint32_t rectCount,
Jeff Bolz5c801d12019-10-09 10:38:45 -05003471 const VkClearRect *pRects) const {
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003472 bool skip = false;
John Zulauf441558b2019-08-12 11:47:39 -06003473 const CMD_BUFFER_STATE *cb_node = GetCBState(commandBuffer); // TODO: Should be const, and never modified during validation
Petr Kraus2dffb382019-08-10 02:52:12 +02003474 if (!cb_node) return skip;
3475
3476 skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearAttachments()", VK_QUEUE_GRAPHICS_BIT,
3477 "VUID-vkCmdClearAttachments-commandBuffer-cmdpool");
3478 skip |= ValidateCmd(cb_node, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
Petr Kraus2dffb382019-08-10 02:52:12 +02003479 skip |= OutsideRenderPass(cb_node, "vkCmdClearAttachments()", "VUID-vkCmdClearAttachments-renderpass");
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003480
3481 // Validate that attachment is in reference list of active subpass
3482 if (cb_node->activeRenderPass) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08003483 const VkRenderPassCreateInfo2 *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
John Zulauff2582972019-02-09 14:53:30 -07003484 const uint32_t renderpass_attachment_count = renderpass_create_info->attachmentCount;
Mike Schuchardt2df08912020-12-15 16:28:09 -08003485 const VkSubpassDescription2 *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
locke-lunargaecf2152020-05-12 17:15:41 -06003486 const auto *framebuffer = cb_node->activeFramebuffer.get();
John Zulauf3a548ef2019-02-01 16:14:07 -07003487 const auto &render_area = cb_node->activeRenderPassBeginInfo.renderArea;
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003488
John Zulauf3a548ef2019-02-01 16:14:07 -07003489 for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
3490 auto clear_desc = &pAttachments[attachment_index];
3491 uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
sfricke-samsungfdf91c82020-10-26 03:31:28 -07003492 const VkImageAspectFlags aspect_mask = clear_desc->aspectMask;
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003493
sfricke-samsungfdf91c82020-10-26 03:31:28 -07003494 if (aspect_mask & VK_IMAGE_ASPECT_METADATA_BIT) {
3495 skip |= LogError(commandBuffer, "VUID-VkClearAttachment-aspectMask-00020",
3496 "vkCmdClearAttachments() pAttachments[%u] mask contains VK_IMAGE_ASPECT_METADATA_BIT",
3497 attachment_index);
3498 } else if (aspect_mask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
3499 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
3500 skip |=
3501 LogError(commandBuffer, "VUID-VkClearAttachment-aspectMask-02246",
3502 "vkCmdClearAttachments() pAttachments[%u] mask contains a VK_IMAGE_ASPECT_MEMORY_PLANE_*_BIT_EXT bit",
3503 attachment_index);
3504 } else if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
John Zulauff2582972019-02-09 14:53:30 -07003505 uint32_t color_attachment = VK_ATTACHMENT_UNUSED;
3506 if (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount) {
3507 color_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
3508 if ((color_attachment != VK_ATTACHMENT_UNUSED) && (color_attachment >= renderpass_attachment_count)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003509 skip |= LogError(
3510 commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02501",
3511 "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u is not VK_ATTACHMENT_UNUSED "
3512 "and not a valid attachment for %s attachmentCount=%u. Subpass %u pColorAttachment[%u]=%u.",
3513 attachment_index, clear_desc->colorAttachment,
3514 report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(), cb_node->activeSubpass,
3515 clear_desc->colorAttachment, color_attachment, renderpass_attachment_count);
Lockee9aeebf2019-03-03 23:50:08 -07003516
John Zulauff2582972019-02-09 14:53:30 -07003517 color_attachment = VK_ATTACHMENT_UNUSED; // Defensive, prevent lookup past end of renderpass attachment
3518 }
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003519 } else {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07003520 skip |= LogError(commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02501",
3521 "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u out of range for %s"
3522 " subpass %u. colorAttachmentCount=%u",
3523 attachment_index, clear_desc->colorAttachment,
3524 report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(),
3525 cb_node->activeSubpass, subpass_desc->colorAttachmentCount);
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003526 }
John Zulauff2582972019-02-09 14:53:30 -07003527 fb_attachment = color_attachment;
3528
sfricke-samsungf1f35ce2020-10-26 03:35:35 -07003529 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
3530 (clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
3531 skip |= LogError(commandBuffer, "VUID-VkClearAttachment-aspectMask-00019",
3532 "vkCmdClearAttachments() pAttachments[%u] aspectMask must set only VK_IMAGE_ASPECT_COLOR_BIT "
3533 "of a color attachment.",
3534 attachment_index);
Mark Lobodzinskiac7e51e2017-02-02 15:50:27 -07003535 }
3536 } else { // Must be depth and/or stencil
Tony-LunarG1b2f8302020-10-29 13:26:23 -06003537 bool subpass_depth = false;
3538 bool subpass_stencil = false;
3539 if (subpass_desc->pDepthStencilAttachment &&
3540 (subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
3541 auto index = subpass_desc->pDepthStencilAttachment->attachment;
3542 subpass_depth = FormatHasDepth(renderpass_create_info->pAttachments[index].format);
3543 subpass_stencil = FormatHasStencil(renderpass_create_info->pAttachments[index].format);
3544 }
Mark Lobodzinskiac7e51e2017-02-02 15:50:27 -07003545 if (!subpass_desc->pDepthStencilAttachment ||
Tony-LunarG1b2f8302020-10-29 13:26:23 -06003546 (subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
3547 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) && !subpass_depth) {
sfricke-samsungf1f35ce2020-10-26 03:35:35 -07003548 skip |= LogError(
3549 commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02502",
3550 "vkCmdClearAttachments() pAttachments[%u] aspectMask has VK_IMAGE_ASPECT_DEPTH_BIT but there is no "
Tony-LunarG1b2f8302020-10-29 13:26:23 -06003551 "depth attachment in subpass",
sfricke-samsungf1f35ce2020-10-26 03:35:35 -07003552 attachment_index);
Tony-LunarG1b2f8302020-10-29 13:26:23 -06003553 }
3554 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && !subpass_stencil) {
sfricke-samsungf1f35ce2020-10-26 03:35:35 -07003555 skip |= LogError(
3556 commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02503",
3557 "vkCmdClearAttachments() pAttachments[%u] aspectMask has VK_IMAGE_ASPECT_STENCIL_BIT but there is no "
Tony-LunarG1b2f8302020-10-29 13:26:23 -06003558 "stencil attachment in subpass",
sfricke-samsungf1f35ce2020-10-26 03:35:35 -07003559 attachment_index);
3560 }
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003561 } else {
John Zulauf3a548ef2019-02-01 16:14:07 -07003562 fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003563 }
sfricke-samsung03f11ef2021-01-23 02:02:15 -08003564 if (subpass_depth) {
3565 skip |= ValidateClearDepthStencilValue(commandBuffer, clear_desc->clearValue.depthStencil,
3566 "vkCmdClearAttachments()");
3567 }
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003568 }
John Zulauf3a548ef2019-02-01 16:14:07 -07003569 if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
Mark Lobodzinskif933db92019-03-09 12:58:03 -07003570 skip |= ValidateClearAttachmentExtent(commandBuffer, attachment_index, framebuffer, fb_attachment, render_area,
3571 rectCount, pRects);
John Zulauf441558b2019-08-12 11:47:39 -06003572 }
sfricke-samsung3d0c0b12020-08-04 00:21:37 -07003573
3574 // Once the framebuffer attachment is found, can get the image view state
3575 if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) &&
3576 (fb_attachment < framebuffer->createInfo.attachmentCount)) {
3577 const IMAGE_VIEW_STATE *image_view_state =
locke-lunargfc78e932020-11-19 17:06:24 -07003578 GetActiveAttachmentImageViewState(GetCBState(commandBuffer), fb_attachment);
sfricke-samsung3d0c0b12020-08-04 00:21:37 -07003579 if (image_view_state != nullptr) {
3580 skip |= ValidateProtectedImage(cb_node, image_view_state->image_state.get(), "vkCmdClearAttachments()",
3581 "VUID-vkCmdClearAttachments-commandBuffer-02504");
3582 skip |= ValidateUnprotectedImage(cb_node, image_view_state->image_state.get(), "vkCmdClearAttachments()",
3583 "VUID-vkCmdClearAttachments-commandBuffer-02505");
3584 }
3585 }
John Zulauf441558b2019-08-12 11:47:39 -06003586 }
3587 }
3588 return skip;
3589}
3590
3591void CoreChecks::PreCallRecordCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
3592 const VkClearAttachment *pAttachments, uint32_t rectCount,
3593 const VkClearRect *pRects) {
3594 auto *cb_node = GetCBState(commandBuffer);
3595 if (cb_node->activeRenderPass && (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08003596 const VkRenderPassCreateInfo2 *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
3597 const VkSubpassDescription2 *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
John Zulauf441558b2019-08-12 11:47:39 -06003598 std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy;
3599 for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
3600 const auto clear_desc = &pAttachments[attachment_index];
3601 uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
3602 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
3603 (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount)) {
3604 fb_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
3605 } else if ((clear_desc->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) &&
3606 subpass_desc->pDepthStencilAttachment) {
3607 fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
3608 }
3609 if (fb_attachment != VK_ATTACHMENT_UNUSED) {
John Zulauf3a548ef2019-02-01 16:14:07 -07003610 if (!clear_rect_copy) {
3611 // We need a copy of the clear rectangles that will persist until the last lambda executes
3612 // but we want to create it as lazily as possible
3613 clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount));
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003614 }
John Zulauf441558b2019-08-12 11:47:39 -06003615 // if a secondary level command buffer inherits the framebuffer from the primary command buffer
3616 // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time
Mark Lobodzinskif933db92019-03-09 12:58:03 -07003617 auto val_fn = [this, commandBuffer, attachment_index, fb_attachment, rectCount, clear_rect_copy](
locke-lunargaecf2152020-05-12 17:15:41 -06003618 const CMD_BUFFER_STATE *prim_cb, const FRAMEBUFFER_STATE *fb) {
John Zulauf3a548ef2019-02-01 16:14:07 -07003619 assert(rectCount == clear_rect_copy->size());
John Zulauf3a548ef2019-02-01 16:14:07 -07003620 const auto &render_area = prim_cb->activeRenderPassBeginInfo.renderArea;
3621 bool skip = false;
locke-lunargaecf2152020-05-12 17:15:41 -06003622 skip = ValidateClearAttachmentExtent(commandBuffer, attachment_index, fb, fb_attachment, render_area, rectCount,
locke-lunargfc78e932020-11-19 17:06:24 -07003623 clear_rect_copy->data(), prim_cb);
John Zulauf3a548ef2019-02-01 16:14:07 -07003624 return skip;
3625 };
3626 cb_node->cmd_execute_commands_functions.emplace_back(val_fn);
Mark Lobodzinski2def2bf2017-02-02 15:22:50 -07003627 }
3628 }
3629 }
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07003630}
3631
Jeff Leger178b1e52020-10-05 12:22:23 -04003632template <typename RegionType>
3633bool CoreChecks::ValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3634 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3635 const RegionType *pRegions, CopyCommandVersion version) const {
John Zulaufe2b7bcb2019-07-05 16:08:39 -06003636 const auto *cb_node = GetCBState(commandBuffer);
3637 const auto *src_image_state = GetImageState(srcImage);
3638 const auto *dst_image_state = GetImageState(dstImage);
Jeff Leger178b1e52020-10-05 12:22:23 -04003639 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
3640 const char *func_name = is_2khr ? "vkCmdResolveImage2KHR()" : "vkCmdResolveImage()";
3641 const CMD_TYPE cmd_type = is_2khr ? CMD_RESOLVEIMAGE : CMD_RESOLVEIMAGE2KHR;
3642 const char *vuid;
Mark Lobodzinski9a075c22019-01-10 14:30:39 -07003643
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07003644 bool skip = false;
3645 if (cb_node && src_image_state && dst_image_state) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003646 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00256" : "VUID-vkCmdResolveImage-srcImage-00256";
3647 skip |= ValidateMemoryIsBoundToImage(src_image_state, func_name, vuid);
3648 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00258" : "VUID-vkCmdResolveImage-dstImage-00258";
3649 skip |= ValidateMemoryIsBoundToImage(dst_image_state, func_name, vuid);
3650 vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-cmdpool" : "VUID-vkCmdResolveImage-commandBuffer-cmdpool";
3651 skip |= ValidateCmdQueueFlags(cb_node, func_name, VK_QUEUE_GRAPHICS_BIT, vuid);
3652 skip |= ValidateCmd(cb_node, cmd_type, func_name);
3653 vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-renderpass" : "VUID-vkCmdResolveImage-renderpass";
3654 skip |= InsideRenderPass(cb_node, func_name, vuid);
3655 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-02003" : "VUID-vkCmdResolveImage-dstImage-02003";
3656 skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, func_name, vuid);
3657 vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-01837" : "VUID-vkCmdResolveImage-commandBuffer-01837";
3658 skip |= ValidateProtectedImage(cb_node, src_image_state, func_name, vuid);
3659 vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-01838" : "VUID-vkCmdResolveImage-commandBuffer-01838";
3660 skip |= ValidateProtectedImage(cb_node, dst_image_state, func_name, vuid);
3661 vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-01839" : "VUID-vkCmdResolveImage-commandBuffer-01839";
3662 skip |= ValidateUnprotectedImage(cb_node, dst_image_state, func_name, vuid);
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003663
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003664 // Validation for VK_EXT_fragment_density_map
3665 if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003666 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-02546" : "VUID-vkCmdResolveImage-dstImage-02546";
3667 skip |= LogError(cb_node->commandBuffer, vuid,
3668 "%s: srcImage must not have been created with flags containing "
3669 "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3670 func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003671 }
3672 if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003673 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-02546" : "VUID-vkCmdResolveImage-dstImage-02546";
3674 skip |= LogError(cb_node->commandBuffer, vuid,
3675 "%s: dstImage must not have been created with flags containing "
3676 "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3677 func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003678 }
3679
Cort Stratton7df30962018-05-17 19:45:57 -07003680 bool hit_error = false;
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07003681 const char *invalid_src_layout_vuid =
Jeff Leger178b1e52020-10-05 12:22:23 -04003682 is_2khr ? ((src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3683 ? "VUID-VkResolveImageInfo2KHR-srcImageLayout-01400"
Shannon McPhersonc505df62020-10-20 16:27:11 -06003684 : "VUID-VkResolveImageInfo2KHR-srcImageLayout-00261")
Jeff Leger178b1e52020-10-05 12:22:23 -04003685 : ((src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3686 ? "VUID-vkCmdResolveImage-srcImageLayout-01400"
3687 : "VUID-vkCmdResolveImage-srcImageLayout-00261");
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07003688 const char *invalid_dst_layout_vuid =
Jeff Leger178b1e52020-10-05 12:22:23 -04003689 is_2khr ? ((dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3690 ? "VUID-VkResolveImageInfo2KHR-dstImageLayout-01401"
3691 : "VUID-VkResolveImageInfo2KHR-dstImageLayout-00263")
3692 : ((dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3693 ? "VUID-vkCmdResolveImage-dstImageLayout-01401"
3694 : "VUID-vkCmdResolveImage-dstImageLayout-00263");
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003695 // For each region, the number of layers in the image subresource should not be zero
3696 // For each region, src and dest image aspect must be color only
3697 for (uint32_t i = 0; i < regionCount; i++) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003698 const RegionType region = pRegions[i];
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003699 const VkImageSubresourceLayers src_subresource = region.srcSubresource;
3700 const VkImageSubresourceLayers dst_subresource = region.dstSubresource;
Jeff Leger178b1e52020-10-05 12:22:23 -04003701 skip |= ValidateImageSubresourceLayers(cb_node, &src_subresource, func_name, "srcSubresource", i);
3702 skip |= ValidateImageSubresourceLayers(cb_node, &dst_subresource, func_name, "dstSubresource", i);
3703 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImageLayout-00260" : "VUID-vkCmdResolveImage-srcImageLayout-00260";
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003704 skip |= VerifyImageLayout(cb_node, src_image_state, src_subresource, srcImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04003705 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, invalid_src_layout_vuid, vuid, &hit_error);
3706 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImageLayout-00262" : "VUID-vkCmdResolveImage-dstImageLayout-00262";
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003707 skip |= VerifyImageLayout(cb_node, dst_image_state, dst_subresource, dstImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04003708 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, invalid_dst_layout_vuid, vuid, &hit_error);
3709 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcSubresource-01709" : "VUID-vkCmdResolveImage-srcSubresource-01709";
3710 skip |= ValidateImageMipLevel(cb_node, src_image_state, src_subresource.mipLevel, i, func_name, "srcSubresource", vuid);
3711 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstSubresource-01710" : "VUID-vkCmdResolveImage-dstSubresource-01710";
3712 skip |= ValidateImageMipLevel(cb_node, dst_image_state, dst_subresource.mipLevel, i, func_name, "dstSubresource", vuid);
3713 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcSubresource-01711" : "VUID-vkCmdResolveImage-srcSubresource-01711";
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003714 skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, src_subresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04003715 src_subresource.layerCount, i, func_name, "srcSubresource", vuid);
3716 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstSubresource-01712" : "VUID-vkCmdResolveImage-dstSubresource-01712";
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003717 skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, dst_subresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04003718 dst_subresource.layerCount, i, func_name, "srcSubresource", vuid);
Cort Stratton7df30962018-05-17 19:45:57 -07003719
3720 // layer counts must match
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003721 if (src_subresource.layerCount != dst_subresource.layerCount) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003722 vuid = is_2khr ? "VUID-VkImageResolve2KHR-layerCount-00267" : "VUID-VkImageResolve-layerCount-00267";
3723 skip |=
3724 LogError(cb_node->commandBuffer, vuid,
3725 "%s: layerCount in source and destination subresource of pRegions[%u] does not match.", func_name, i);
Mark Lobodzinski50fbef12017-02-06 15:31:33 -07003726 }
Cort Stratton7df30962018-05-17 19:45:57 -07003727 // For each region, src and dest image aspect must be color only
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003728 if ((src_subresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
3729 (dst_subresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003730 vuid = is_2khr ? "VUID-VkImageResolve2KHR-aspectMask-00266" : "VUID-VkImageResolve-aspectMask-00266";
3731 skip |= LogError(cb_node->commandBuffer, vuid,
3732 "%s: src and dest aspectMasks for pRegions[%u] must specify only VK_IMAGE_ASPECT_COLOR_BIT.",
3733 func_name, i);
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003734 }
3735
3736 const VkImageType src_image_type = src_image_state->createInfo.imageType;
3737 const VkImageType dst_image_type = dst_image_state->createInfo.imageType;
3738
3739 if ((VK_IMAGE_TYPE_3D == src_image_type) || (VK_IMAGE_TYPE_3D == dst_image_type)) {
Shannon McPherson74b341c2020-09-08 15:43:05 -06003740 if ((0 != src_subresource.baseArrayLayer) || (1 != src_subresource.layerCount)) {
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003741 LogObjectList objlist(cb_node->commandBuffer);
3742 objlist.add(src_image_state->image);
3743 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003744 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-04446" : "VUID-vkCmdResolveImage-srcImage-04446";
3745 skip |= LogError(objlist, vuid,
3746 "%s: pRegions[%u] baseArrayLayer must be 0 and layerCount must be 1 for all "
Shannon McPherson74b341c2020-09-08 15:43:05 -06003747 "subresources if the src or dst image is 3D.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003748 func_name, i);
Shannon McPherson74b341c2020-09-08 15:43:05 -06003749 }
3750 if ((0 != dst_subresource.baseArrayLayer) || (1 != dst_subresource.layerCount)) {
3751 LogObjectList objlist(cb_node->commandBuffer);
3752 objlist.add(src_image_state->image);
3753 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003754 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-04447" : "VUID-vkCmdResolveImage-srcImage-04447";
3755 skip |= LogError(objlist, vuid,
3756 "%s: pRegions[%u] baseArrayLayer must be 0 and layerCount must be 1 for all "
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003757 "subresources if the src or dst image is 3D.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003758 func_name, i);
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003759 }
3760 }
3761
3762 if (VK_IMAGE_TYPE_1D == src_image_type) {
3763 if ((pRegions[i].srcOffset.y != 0) || (pRegions[i].extent.height != 1)) {
3764 LogObjectList objlist(cb_node->commandBuffer);
3765 objlist.add(src_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003766 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00271" : "VUID-vkCmdResolveImage-srcImage-00271";
3767 skip |= LogError(objlist, vuid,
3768 "%s: srcImage (%s) is 1D but pRegions[%u] srcOffset.y (%d) is not 0 or "
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003769 "extent.height (%u) is not 1.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003770 func_name, report_data->FormatHandle(src_image_state->image).c_str(), i,
3771 pRegions[i].srcOffset.y, pRegions[i].extent.height);
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003772 }
3773 }
3774 if ((VK_IMAGE_TYPE_1D == src_image_type) || (VK_IMAGE_TYPE_2D == src_image_type)) {
3775 if ((pRegions[i].srcOffset.z != 0) || (pRegions[i].extent.depth != 1)) {
3776 LogObjectList objlist(cb_node->commandBuffer);
3777 objlist.add(src_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003778 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00273" : "VUID-vkCmdResolveImage-srcImage-00273";
3779 skip |= LogError(objlist, vuid,
3780 "%s: srcImage (%s) is 2D but pRegions[%u] srcOffset.z (%d) is not 0 or "
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003781 "extent.depth (%u) is not 1.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003782 func_name, report_data->FormatHandle(src_image_state->image).c_str(), i,
3783 pRegions[i].srcOffset.z, pRegions[i].extent.depth);
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003784 }
3785 }
3786
3787 if (VK_IMAGE_TYPE_1D == dst_image_type) {
3788 if ((pRegions[i].dstOffset.y != 0) || (pRegions[i].extent.height != 1)) {
3789 LogObjectList objlist(cb_node->commandBuffer);
3790 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003791 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00276" : "VUID-vkCmdResolveImage-dstImage-00276";
3792 skip |= LogError(objlist, vuid,
3793 "%s: dstImage (%s) is 1D but pRegions[%u] dstOffset.y (%d) is not 0 or "
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003794 "extent.height (%u) is not 1.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003795 func_name, report_data->FormatHandle(dst_image_state->image).c_str(), i,
3796 pRegions[i].dstOffset.y, pRegions[i].extent.height);
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003797 }
3798 }
3799 if ((VK_IMAGE_TYPE_1D == dst_image_type) || (VK_IMAGE_TYPE_2D == dst_image_type)) {
3800 if ((pRegions[i].dstOffset.z != 0) || (pRegions[i].extent.depth != 1)) {
3801 LogObjectList objlist(cb_node->commandBuffer);
3802 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003803 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00278" : "VUID-vkCmdResolveImage-dstImage-00278";
3804 skip |= LogError(objlist, vuid,
3805 "%s: dstImage (%s) is 2D but pRegions[%u] dstOffset.z (%d) is not 0 or "
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003806 "extent.depth (%u) is not 1.",
Jeff Leger178b1e52020-10-05 12:22:23 -04003807 func_name, report_data->FormatHandle(dst_image_state->image).c_str(), i,
3808 pRegions[i].dstOffset.z, pRegions[i].extent.depth);
sfricke-samsung2e94fb02020-06-05 21:59:28 -07003809 }
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003810 }
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003811
3812 // Each srcImage dimension offset + extent limits must fall with image subresource extent
3813 VkExtent3D subresource_extent = GetImageSubresourceExtent(src_image_state, &src_subresource);
3814 // MipLevel bound is checked already and adding extra errors with a "subresource extent of zero" is confusing to
3815 // developer
3816 if (src_subresource.mipLevel < src_image_state->createInfo.mipLevels) {
3817 uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &(region.extent), &subresource_extent);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003818 if ((extent_check & kXBit) != 0) {
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003819 LogObjectList objlist(cb_node->commandBuffer);
3820 objlist.add(src_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003821 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcOffset-00269" : "VUID-vkCmdResolveImage-srcOffset-00269";
3822 skip |= LogError(objlist, vuid,
3823 "%s: srcImage (%s) pRegions[%u] x-dimension offset [%1d] + extent [%u] "
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003824 "exceeds subResource width [%u].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003825 func_name, report_data->FormatHandle(src_image_state->image).c_str(), i, region.srcOffset.x,
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003826 region.extent.width, subresource_extent.width);
3827 }
3828
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003829 if ((extent_check & kYBit) != 0) {
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003830 LogObjectList objlist(cb_node->commandBuffer);
3831 objlist.add(src_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003832 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcOffset-00270" : "VUID-vkCmdResolveImage-srcOffset-00270";
3833 skip |= LogError(objlist, vuid,
3834 "%s: srcImage (%s) pRegions[%u] y-dimension offset [%1d] + extent [%u] "
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003835 "exceeds subResource height [%u].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003836 func_name, report_data->FormatHandle(src_image_state->image).c_str(), i, region.srcOffset.y,
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003837 region.extent.height, subresource_extent.height);
3838 }
3839
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003840 if ((extent_check & kZBit) != 0) {
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003841 LogObjectList objlist(cb_node->commandBuffer);
3842 objlist.add(src_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003843 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcOffset-00272" : "VUID-vkCmdResolveImage-srcOffset-00272";
3844 skip |= LogError(objlist, vuid,
3845 "%s: srcImage (%s) pRegions[%u] z-dimension offset [%1d] + extent [%u] "
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003846 "exceeds subResource depth [%u].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003847 func_name, report_data->FormatHandle(src_image_state->image).c_str(), i, region.srcOffset.z,
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003848 region.extent.depth, subresource_extent.depth);
3849 }
3850 }
3851
3852 // Each dstImage dimension offset + extent limits must fall with image subresource extent
3853 subresource_extent = GetImageSubresourceExtent(dst_image_state, &dst_subresource);
3854 // MipLevel bound is checked already and adding extra errors with a "subresource extent of zero" is confusing to
3855 // developer
3856 if (dst_subresource.mipLevel < dst_image_state->createInfo.mipLevels) {
3857 uint32_t extent_check = ExceedsBounds(&(region.dstOffset), &(region.extent), &subresource_extent);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003858 if ((extent_check & kXBit) != 0) {
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003859 LogObjectList objlist(cb_node->commandBuffer);
3860 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003861 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstOffset-00274" : "VUID-vkCmdResolveImage-dstOffset-00274";
3862 skip |= LogError(objlist, vuid,
3863 "%s: dstImage (%s) pRegions[%u] x-dimension offset [%1d] + extent [%u] "
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003864 "exceeds subResource width [%u].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003865 func_name, report_data->FormatHandle(dst_image_state->image).c_str(), i, region.srcOffset.x,
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003866 region.extent.width, subresource_extent.width);
3867 }
3868
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003869 if ((extent_check & kYBit) != 0) {
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003870 LogObjectList objlist(cb_node->commandBuffer);
3871 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003872 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstOffset-00275" : "VUID-vkCmdResolveImage-dstOffset-00275";
3873 skip |= LogError(objlist, vuid,
3874 "%s: dstImage (%s) pRegions[%u] y-dimension offset [%1d] + extent [%u] "
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003875 "exceeds subResource height [%u].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003876 func_name, report_data->FormatHandle(dst_image_state->image).c_str(), i, region.srcOffset.y,
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003877 region.extent.height, subresource_extent.height);
3878 }
3879
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07003880 if ((extent_check & kZBit) != 0) {
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003881 LogObjectList objlist(cb_node->commandBuffer);
3882 objlist.add(dst_image_state->image);
Jeff Leger178b1e52020-10-05 12:22:23 -04003883 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstOffset-00277" : "VUID-vkCmdResolveImage-dstOffset-00277";
3884 skip |= LogError(objlist, vuid,
3885 "%s: dstImage (%s) pRegions[%u] z-dimension offset [%1d] + extent [%u] "
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003886 "exceeds subResource depth [%u].",
Jeff Leger178b1e52020-10-05 12:22:23 -04003887 func_name, report_data->FormatHandle(dst_image_state->image).c_str(), i, region.srcOffset.z,
sfricke-samsungdfeb3172020-07-25 21:17:07 -07003888 region.extent.depth, subresource_extent.depth);
3889 }
3890 }
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003891 }
3892
3893 if (src_image_state->createInfo.format != dst_image_state->createInfo.format) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003894 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-01386" : "VUID-vkCmdResolveImage-srcImage-01386";
3895 skip |= LogError(cb_node->commandBuffer, vuid, "%s: srcImage format (%s) and dstImage format (%s) are not the same.",
3896 func_name, string_VkFormat(src_image_state->createInfo.format),
3897 string_VkFormat(dst_image_state->createInfo.format));
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003898 }
3899 if (src_image_state->createInfo.imageType != dst_image_state->createInfo.imageType) {
sfricke-samsungc26350e2020-05-30 12:31:31 -07003900 skip |= LogWarning(cb_node->commandBuffer, kVUID_Core_DrawState_MismatchedImageType,
Jeff Leger178b1e52020-10-05 12:22:23 -04003901 "%s: srcImage type (%s) and dstImage type (%s) are not the same.", func_name,
sfricke-samsungc26350e2020-05-30 12:31:31 -07003902 string_VkImageType(src_image_state->createInfo.imageType),
3903 string_VkImageType(dst_image_state->createInfo.imageType));
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003904 }
3905 if (src_image_state->createInfo.samples == VK_SAMPLE_COUNT_1_BIT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003906 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00257" : "VUID-vkCmdResolveImage-srcImage-00257";
3907 skip |= LogError(cb_node->commandBuffer, vuid, "%s: srcImage sample count is VK_SAMPLE_COUNT_1_BIT.", func_name);
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003908 }
3909 if (dst_image_state->createInfo.samples != VK_SAMPLE_COUNT_1_BIT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003910 vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00259" : "VUID-vkCmdResolveImage-dstImage-00259";
3911 skip |= LogError(cb_node->commandBuffer, vuid, "%s: dstImage sample count (%s) is not VK_SAMPLE_COUNT_1_BIT.",
3912 func_name, string_VkSampleCountFlagBits(dst_image_state->createInfo.samples));
Mark Lobodzinski2a3368e2017-02-06 15:29:37 -07003913 }
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07003914 } else {
3915 assert(0);
3916 }
3917 return skip;
3918}
3919
Jeff Leger178b1e52020-10-05 12:22:23 -04003920bool CoreChecks::PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3921 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3922 const VkImageResolve *pRegions) const {
3923 return ValidateCmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions,
3924 COPY_COMMAND_VERSION_1);
3925}
3926
3927bool CoreChecks::PreCallValidateCmdResolveImage2KHR(VkCommandBuffer commandBuffer,
3928 const VkResolveImageInfo2KHR *pResolveImageInfo) const {
3929 return ValidateCmdResolveImage(commandBuffer, pResolveImageInfo->srcImage, pResolveImageInfo->srcImageLayout,
3930 pResolveImageInfo->dstImage, pResolveImageInfo->dstImageLayout, pResolveImageInfo->regionCount,
3931 pResolveImageInfo->pRegions, COPY_COMMAND_VERSION_2);
3932}
3933
3934template <typename RegionType>
3935bool CoreChecks::ValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3936 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3937 const RegionType *pRegions, VkFilter filter, CopyCommandVersion version) const {
John Zulaufe2b7bcb2019-07-05 16:08:39 -06003938 const auto *cb_node = GetCBState(commandBuffer);
3939 const auto *src_image_state = GetImageState(srcImage);
3940 const auto *dst_image_state = GetImageState(dstImage);
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07003941
Jeff Leger178b1e52020-10-05 12:22:23 -04003942 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
3943 const char *func_name = is_2khr ? "vkCmdBlitImage2KHR()" : "vkCmdBlitImage()";
3944 const CMD_TYPE cmd_type = is_2khr ? CMD_BLITIMAGE : CMD_BLITIMAGE2KHR;
3945
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07003946 bool skip = false;
John Zulauf5c2750c2018-01-30 15:04:56 -07003947 if (cb_node) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003948 skip |= ValidateCmd(cb_node, cmd_type, func_name);
John Zulauf5c2750c2018-01-30 15:04:56 -07003949 }
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07003950 if (cb_node && src_image_state && dst_image_state) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003951 const char *vuid;
3952 const char *location;
3953 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00233" : "VUID-vkCmdBlitImage-srcImage-00233";
3954 location = is_2khr ? "vkCmdBlitImage2KHR(): pBlitImageInfo->srcImage" : "vkCmdBlitImage(): srcImage";
3955 skip |= ValidateImageSampleCount(src_image_state, VK_SAMPLE_COUNT_1_BIT, location, vuid);
3956 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00234" : "VUID-vkCmdBlitImage-dstImage-00234";
3957 location = is_2khr ? "vkCmdBlitImage2KHR(): pBlitImageInfo->dstImage" : "vkCmdBlitImage(): dstImage";
3958 skip |= ValidateImageSampleCount(dst_image_state, VK_SAMPLE_COUNT_1_BIT, location, vuid);
3959 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00220" : "VUID-vkCmdBlitImage-srcImage-00220";
3960 skip |= ValidateMemoryIsBoundToImage(src_image_state, func_name, vuid);
3961 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00225" : "VUID-vkCmdBlitImage-dstImage-00225";
3962 skip |= ValidateMemoryIsBoundToImage(dst_image_state, func_name, vuid);
3963 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00219" : "VUID-vkCmdBlitImage-srcImage-00219";
3964 skip |= ValidateImageUsageFlags(src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
3965 "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
3966 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00224" : "VUID-vkCmdBlitImage-dstImage-00224";
3967 skip |= ValidateImageUsageFlags(dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
3968 "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
3969 vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-cmdpool" : "VUID-vkCmdBlitImage-commandBuffer-cmdpool";
3970 skip |= ValidateCmdQueueFlags(cb_node, func_name, VK_QUEUE_GRAPHICS_BIT, vuid);
3971 skip |= ValidateCmd(cb_node, cmd_type, func_name);
3972 vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-renderpass" : "VUID-vkCmdBlitImage-renderpass";
3973 skip |= InsideRenderPass(cb_node, func_name, vuid);
3974 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-01999" : "VUID-vkCmdBlitImage-srcImage-01999";
3975 skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_BLIT_SRC_BIT, func_name, vuid);
3976 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-02000" : "VUID-vkCmdBlitImage-dstImage-02000";
3977 skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_BLIT_DST_BIT, func_name, vuid);
3978 vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-01834" : "VUID-vkCmdBlitImage-commandBuffer-01834";
3979 skip |= ValidateProtectedImage(cb_node, src_image_state, func_name, vuid);
3980 vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-01835" : "VUID-vkCmdBlitImage-commandBuffer-01835";
3981 skip |= ValidateProtectedImage(cb_node, dst_image_state, func_name, vuid);
3982 vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-01836" : "VUID-vkCmdBlitImage-commandBuffer-01836";
3983 skip |= ValidateUnprotectedImage(cb_node, dst_image_state, func_name, vuid);
sfricke-samsung022fa252020-07-24 03:26:16 -07003984
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003985 // Validation for VK_EXT_fragment_density_map
3986 if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003987 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-02545" : "VUID-vkCmdBlitImage-dstImage-02545";
3988 skip |= LogError(cb_node->commandBuffer, vuid,
3989 "%s: srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3990 func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003991 }
3992 if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04003993 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-02545" : "VUID-vkCmdBlitImage-dstImage-02545";
3994 skip |= LogError(cb_node->commandBuffer, vuid,
3995 "%s: dstImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3996 func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02003997 }
3998
Tobin Ehlisbb03e5f2017-05-11 08:52:51 -06003999 // TODO: Need to validate image layouts, which will include layout validation for shared presentable images
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004000
Dave Houlton33c2d252017-06-09 17:08:32 -06004001 VkFormat src_format = src_image_state->createInfo.format;
4002 VkFormat dst_format = dst_image_state->createInfo.format;
4003 VkImageType src_type = src_image_state->createInfo.imageType;
4004 VkImageType dst_type = dst_image_state->createInfo.imageType;
4005
Cort Stratton186b1a22018-05-01 20:18:06 -04004006 if (VK_FILTER_LINEAR == filter) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004007 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-filter-02001" : "VUID-vkCmdBlitImage-filter-02001";
4008 skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, func_name,
4009 vuid);
Cort Stratton186b1a22018-05-01 20:18:06 -04004010 } else if (VK_FILTER_CUBIC_IMG == filter) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004011 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-filter-02002" : "VUID-vkCmdBlitImage-filter-02002";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004012 skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG,
Jeff Leger178b1e52020-10-05 12:22:23 -04004013 func_name, vuid);
Dave Houlton33c2d252017-06-09 17:08:32 -06004014 }
4015
Mark Lobodzinski1057e442020-02-13 11:57:15 -07004016 if (FormatRequiresYcbcrConversion(src_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004017 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-01561" : "VUID-vkCmdBlitImage-srcImage-01561";
4018 skip |= LogError(device, vuid,
4019 "%s: srcImage format (%s) must not be one of the formats requiring sampler YCBCR "
Mark Lobodzinski1057e442020-02-13 11:57:15 -07004020 "conversion for VK_IMAGE_ASPECT_COLOR_BIT image views",
Jeff Leger178b1e52020-10-05 12:22:23 -04004021 func_name, string_VkFormat(src_format));
Mark Lobodzinski1057e442020-02-13 11:57:15 -07004022 }
4023
4024 if (FormatRequiresYcbcrConversion(dst_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004025 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-01562" : "VUID-vkCmdBlitImage-dstImage-01562";
4026 skip |= LogError(device, vuid,
4027 "%s: dstImage format (%s) must not be one of the formats requiring sampler YCBCR "
Mark Lobodzinski1057e442020-02-13 11:57:15 -07004028 "conversion for VK_IMAGE_ASPECT_COLOR_BIT image views",
Jeff Leger178b1e52020-10-05 12:22:23 -04004029 func_name, string_VkFormat(dst_format));
Mark Lobodzinski1057e442020-02-13 11:57:15 -07004030 }
4031
Dave Houlton33c2d252017-06-09 17:08:32 -06004032 if ((VK_FILTER_CUBIC_IMG == filter) && (VK_IMAGE_TYPE_3D != src_type)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004033 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-filter-00237" : "VUID-vkCmdBlitImage-filter-00237";
4034 skip |= LogError(cb_node->commandBuffer, vuid,
4035 "%s: source image type must be VK_IMAGE_TYPE_3D when cubic filtering is specified.", func_name);
Dave Houlton33c2d252017-06-09 17:08:32 -06004036 }
4037
Dave Houlton33c2d252017-06-09 17:08:32 -06004038 // Validate consistency for unsigned formats
4039 if (FormatIsUInt(src_format) != FormatIsUInt(dst_format)) {
4040 std::stringstream ss;
Jeff Leger178b1e52020-10-05 12:22:23 -04004041 ss << func_name << ": If one of srcImage and dstImage images has unsigned integer format, "
Dave Houlton33c2d252017-06-09 17:08:32 -06004042 << "the other one must also have unsigned integer format. "
4043 << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
Jeff Leger178b1e52020-10-05 12:22:23 -04004044 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00230" : "VUID-vkCmdBlitImage-srcImage-00230";
4045 skip |= LogError(cb_node->commandBuffer, vuid, "%s.", ss.str().c_str());
Dave Houlton33c2d252017-06-09 17:08:32 -06004046 }
4047
4048 // Validate consistency for signed formats
4049 if (FormatIsSInt(src_format) != FormatIsSInt(dst_format)) {
4050 std::stringstream ss;
Jeff Leger178b1e52020-10-05 12:22:23 -04004051 ss << func_name << ": If one of srcImage and dstImage images has signed integer format, "
Dave Houlton33c2d252017-06-09 17:08:32 -06004052 << "the other one must also have signed integer format. "
4053 << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
Jeff Leger178b1e52020-10-05 12:22:23 -04004054 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00229" : "VUID-vkCmdBlitImage-srcImage-00229";
4055 skip |= LogError(cb_node->commandBuffer, vuid, "%s.", ss.str().c_str());
Dave Houlton33c2d252017-06-09 17:08:32 -06004056 }
4057
4058 // Validate filter for Depth/Stencil formats
4059 if (FormatIsDepthOrStencil(src_format) && (filter != VK_FILTER_NEAREST)) {
4060 std::stringstream ss;
Jeff Leger178b1e52020-10-05 12:22:23 -04004061 ss << func_name << ": If the format of srcImage is a depth, stencil, or depth stencil "
Dave Houlton33c2d252017-06-09 17:08:32 -06004062 << "then filter must be VK_FILTER_NEAREST.";
Jeff Leger178b1e52020-10-05 12:22:23 -04004063 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00232" : "VUID-vkCmdBlitImage-srcImage-00232";
4064 skip |= LogError(cb_node->commandBuffer, vuid, "%s.", ss.str().c_str());
Dave Houlton33c2d252017-06-09 17:08:32 -06004065 }
4066
4067 // Validate aspect bits and formats for depth/stencil images
4068 if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
4069 if (src_format != dst_format) {
4070 std::stringstream ss;
Jeff Leger178b1e52020-10-05 12:22:23 -04004071 ss << func_name << ": If one of srcImage and dstImage images has a format of depth, stencil or depth "
Dave Houlton33c2d252017-06-09 17:08:32 -06004072 << "stencil, the other one must have exactly the same format. "
4073 << "Source format is " << string_VkFormat(src_format) << " Destination format is "
4074 << string_VkFormat(dst_format);
Jeff Leger178b1e52020-10-05 12:22:23 -04004075 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00231" : "VUID-vkCmdBlitImage-srcImage-00231";
4076 skip |= LogError(cb_node->commandBuffer, vuid, "%s.", ss.str().c_str());
Dave Houlton33c2d252017-06-09 17:08:32 -06004077 }
Dave Houlton33c2d252017-06-09 17:08:32 -06004078 } // Depth or Stencil
4079
4080 // Do per-region checks
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07004081 const char *invalid_src_layout_vuid =
Jeff Leger178b1e52020-10-05 12:22:23 -04004082 is_2khr ? ((src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
4083 ? "VUID-VkBlitImageInfo2KHR-srcImageLayout-01398"
4084 : "VUID-VkBlitImageInfo2KHR-srcImageLayout-00222")
4085 : ((src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
4086 ? "VUID-vkCmdBlitImage-srcImageLayout-01398"
4087 : "VUID-vkCmdBlitImage-srcImageLayout-00222");
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07004088 const char *invalid_dst_layout_vuid =
Jeff Leger178b1e52020-10-05 12:22:23 -04004089 is_2khr ? ((dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
4090 ? "VUID-VkBlitImageInfo2KHR-dstImageLayout-01399"
4091 : "VUID-VkBlitImageInfo2KHR-dstImageLayout-00227")
4092 : ((dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
4093 ? "VUID-vkCmdBlitImage-dstImageLayout-01399"
4094 : "VUID-vkCmdBlitImage-dstImageLayout-00227");
Mark Lobodzinski9a075c22019-01-10 14:30:39 -07004095 for (uint32_t i = 0; i < regionCount; i++) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004096 const RegionType rgn = pRegions[i];
Norbert Garnys7bd4c2c2017-11-16 10:58:04 +01004097 bool hit_error = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04004098 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImageLayout-00221" : "VUID-vkCmdBlitImage-srcImageLayout-00221";
Mark Lobodzinski8564e442019-03-07 12:49:41 -07004099 skip |= VerifyImageLayout(cb_node, src_image_state, rgn.srcSubresource, srcImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04004100 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, invalid_src_layout_vuid, vuid, &hit_error);
4101 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImageLayout-00226" : "VUID-vkCmdBlitImage-dstImageLayout-00226";
Mark Lobodzinski8564e442019-03-07 12:49:41 -07004102 skip |= VerifyImageLayout(cb_node, dst_image_state, rgn.dstSubresource, dstImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04004103 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, invalid_dst_layout_vuid, vuid, &hit_error);
4104 skip |= ValidateImageSubresourceLayers(cb_node, &rgn.srcSubresource, func_name, "srcSubresource", i);
4105 skip |= ValidateImageSubresourceLayers(cb_node, &rgn.dstSubresource, func_name, "dstSubresource", i);
4106 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcSubresource-01705" : "VUID-vkCmdBlitImage-srcSubresource-01705";
4107 skip |=
4108 ValidateImageMipLevel(cb_node, src_image_state, rgn.srcSubresource.mipLevel, i, func_name, "srcSubresource", vuid);
4109 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstSubresource-01706" : "VUID-vkCmdBlitImage-dstSubresource-01706";
4110 skip |=
4111 ValidateImageMipLevel(cb_node, dst_image_state, rgn.dstSubresource.mipLevel, i, func_name, "dstSubresource", vuid);
4112 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcSubresource-01707" : "VUID-vkCmdBlitImage-srcSubresource-01707";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004113 skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, rgn.srcSubresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04004114 rgn.srcSubresource.layerCount, i, func_name, "srcSubresource", vuid);
4115 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstSubresource-01708" : "VUID-vkCmdBlitImage-dstSubresource-01708";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004116 skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, rgn.dstSubresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04004117 rgn.dstSubresource.layerCount, i, func_name, "dstSubresource", vuid);
Mark Lobodzinski23c81142017-02-06 15:04:23 -07004118 // Warn for zero-sized regions
Dave Houlton48989f32017-05-26 15:01:46 -06004119 if ((rgn.srcOffsets[0].x == rgn.srcOffsets[1].x) || (rgn.srcOffsets[0].y == rgn.srcOffsets[1].y) ||
4120 (rgn.srcOffsets[0].z == rgn.srcOffsets[1].z)) {
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004121 std::stringstream ss;
Jeff Leger178b1e52020-10-05 12:22:23 -04004122 ss << func_name << ": pRegions[" << i << "].srcOffsets specify a zero-volume area.";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004123 skip |= LogWarning(cb_node->commandBuffer, kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004124 }
Dave Houlton48989f32017-05-26 15:01:46 -06004125 if ((rgn.dstOffsets[0].x == rgn.dstOffsets[1].x) || (rgn.dstOffsets[0].y == rgn.dstOffsets[1].y) ||
4126 (rgn.dstOffsets[0].z == rgn.dstOffsets[1].z)) {
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004127 std::stringstream ss;
Jeff Leger178b1e52020-10-05 12:22:23 -04004128 ss << func_name << ": pRegions[" << i << "].dstOffsets specify a zero-volume area.";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004129 skip |= LogWarning(cb_node->commandBuffer, kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004130 }
Mark Lobodzinski23c81142017-02-06 15:04:23 -07004131
4132 // Check that src/dst layercounts match
Dave Houlton48989f32017-05-26 15:01:46 -06004133 if (rgn.srcSubresource.layerCount != rgn.dstSubresource.layerCount) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004134 vuid = is_2khr ? "VUID-VkImageBlit2KHR-layerCount-00239" : "VUID-VkImageBlit-layerCount-00239";
4135 skip |=
4136 LogError(cb_node->commandBuffer, vuid,
4137 "%s: layerCount in source and destination subresource of pRegions[%d] does not match.", func_name, i);
Mark Lobodzinski23c81142017-02-06 15:04:23 -07004138 }
Mark Lobodzinskie7e85fd2017-02-07 13:44:57 -07004139
Dave Houlton48989f32017-05-26 15:01:46 -06004140 if (rgn.srcSubresource.aspectMask != rgn.dstSubresource.aspectMask) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004141 vuid = is_2khr ? "VUID-VkImageBlit2KHR-aspectMask-00238" : "VUID-VkImageBlit-aspectMask-00238";
4142 skip |=
4143 LogError(cb_node->commandBuffer, vuid, "%s: aspectMask members for pRegion[%d] do not match.", func_name, i);
Mark Lobodzinskie7e85fd2017-02-07 13:44:57 -07004144 }
Dave Houlton48989f32017-05-26 15:01:46 -06004145
Dave Houlton33c2d252017-06-09 17:08:32 -06004146 if (!VerifyAspectsPresent(rgn.srcSubresource.aspectMask, src_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004147 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-aspectMask-00241" : "VUID-vkCmdBlitImage-aspectMask-00241";
4148 skip |= LogError(cb_node->commandBuffer, vuid,
4149 "%s: region [%d] source aspectMask (0x%x) specifies aspects not present in source "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004150 "image format %s.",
Jeff Leger178b1e52020-10-05 12:22:23 -04004151 func_name, i, rgn.srcSubresource.aspectMask, string_VkFormat(src_format));
Dave Houlton33c2d252017-06-09 17:08:32 -06004152 }
4153
4154 if (!VerifyAspectsPresent(rgn.dstSubresource.aspectMask, dst_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004155 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-aspectMask-00242" : "VUID-vkCmdBlitImage-aspectMask-00242";
4156 skip |= LogError(cb_node->commandBuffer, vuid,
4157 "%s: region [%d] dest aspectMask (0x%x) specifies aspects not present in dest image format %s.",
4158 func_name, i, rgn.dstSubresource.aspectMask, string_VkFormat(dst_format));
Dave Houlton33c2d252017-06-09 17:08:32 -06004159 }
4160
Dave Houlton48989f32017-05-26 15:01:46 -06004161 // Validate source image offsets
4162 VkExtent3D src_extent = GetImageSubresourceExtent(src_image_state, &(rgn.srcSubresource));
Dave Houlton33c2d252017-06-09 17:08:32 -06004163 if (VK_IMAGE_TYPE_1D == src_type) {
Dave Houlton48989f32017-05-26 15:01:46 -06004164 if ((0 != rgn.srcOffsets[0].y) || (1 != rgn.srcOffsets[1].y)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004165 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00245" : "VUID-vkCmdBlitImage-srcImage-00245";
4166 skip |= LogError(cb_node->commandBuffer, vuid,
4167 "%s: region [%d], source image of type VK_IMAGE_TYPE_1D with srcOffset[].y values "
4168 "of (%1d, %1d). These must be (0, 1).",
4169 func_name, i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y);
Dave Houlton48989f32017-05-26 15:01:46 -06004170 }
4171 }
4172
Dave Houlton33c2d252017-06-09 17:08:32 -06004173 if ((VK_IMAGE_TYPE_1D == src_type) || (VK_IMAGE_TYPE_2D == src_type)) {
Dave Houlton48989f32017-05-26 15:01:46 -06004174 if ((0 != rgn.srcOffsets[0].z) || (1 != rgn.srcOffsets[1].z)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004175 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00247" : "VUID-vkCmdBlitImage-srcImage-00247";
4176 skip |= LogError(cb_node->commandBuffer, vuid,
4177 "%s: region [%d], source image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
4178 "srcOffset[].z values of (%1d, %1d). These must be (0, 1).",
4179 func_name, i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z);
Dave Houlton48989f32017-05-26 15:01:46 -06004180 }
4181 }
4182
Dave Houlton33c2d252017-06-09 17:08:32 -06004183 bool oob = false;
Dave Houlton48989f32017-05-26 15:01:46 -06004184 if ((rgn.srcOffsets[0].x < 0) || (rgn.srcOffsets[0].x > static_cast<int32_t>(src_extent.width)) ||
4185 (rgn.srcOffsets[1].x < 0) || (rgn.srcOffsets[1].x > static_cast<int32_t>(src_extent.width))) {
Dave Houlton33c2d252017-06-09 17:08:32 -06004186 oob = true;
Jeff Leger178b1e52020-10-05 12:22:23 -04004187 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcOffset-00243" : "VUID-vkCmdBlitImage-srcOffset-00243";
4188 skip |= LogError(cb_node->commandBuffer, vuid,
4189 "%s: region [%d] srcOffset[].x values (%1d, %1d) exceed srcSubresource width extent (%1d).",
4190 func_name, i, rgn.srcOffsets[0].x, rgn.srcOffsets[1].x, src_extent.width);
Dave Houlton48989f32017-05-26 15:01:46 -06004191 }
4192 if ((rgn.srcOffsets[0].y < 0) || (rgn.srcOffsets[0].y > static_cast<int32_t>(src_extent.height)) ||
4193 (rgn.srcOffsets[1].y < 0) || (rgn.srcOffsets[1].y > static_cast<int32_t>(src_extent.height))) {
Dave Houlton33c2d252017-06-09 17:08:32 -06004194 oob = true;
Jeff Leger178b1e52020-10-05 12:22:23 -04004195 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcOffset-00244" : "VUID-vkCmdBlitImage-srcOffset-00244";
4196 skip |= LogError(cb_node->commandBuffer, vuid,
4197 "%s: region [%d] srcOffset[].y values (%1d, %1d) exceed srcSubresource height extent (%1d).",
4198 func_name, i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y, src_extent.height);
Dave Houlton48989f32017-05-26 15:01:46 -06004199 }
4200 if ((rgn.srcOffsets[0].z < 0) || (rgn.srcOffsets[0].z > static_cast<int32_t>(src_extent.depth)) ||
4201 (rgn.srcOffsets[1].z < 0) || (rgn.srcOffsets[1].z > static_cast<int32_t>(src_extent.depth))) {
Dave Houlton33c2d252017-06-09 17:08:32 -06004202 oob = true;
Jeff Leger178b1e52020-10-05 12:22:23 -04004203 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcOffset-00246" : "VUID-vkCmdBlitImage-srcOffset-00246";
4204 skip |= LogError(cb_node->commandBuffer, vuid,
4205 "%s: region [%d] srcOffset[].z values (%1d, %1d) exceed srcSubresource depth extent (%1d).",
4206 func_name, i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z, src_extent.depth);
Dave Houlton48989f32017-05-26 15:01:46 -06004207 }
Cort Strattonff1542a2018-05-27 10:49:28 -07004208 if (oob) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004209 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-pRegions-00215" : "VUID-vkCmdBlitImage-pRegions-00215";
4210 skip |= LogError(cb_node->commandBuffer, vuid, "%s: region [%d] source image blit region exceeds image dimensions.",
4211 func_name, i);
Dave Houlton33c2d252017-06-09 17:08:32 -06004212 }
Dave Houlton48989f32017-05-26 15:01:46 -06004213
4214 // Validate dest image offsets
4215 VkExtent3D dst_extent = GetImageSubresourceExtent(dst_image_state, &(rgn.dstSubresource));
Dave Houlton33c2d252017-06-09 17:08:32 -06004216 if (VK_IMAGE_TYPE_1D == dst_type) {
Dave Houlton48989f32017-05-26 15:01:46 -06004217 if ((0 != rgn.dstOffsets[0].y) || (1 != rgn.dstOffsets[1].y)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004218 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00250" : "VUID-vkCmdBlitImage-dstImage-00250";
4219 skip |= LogError(cb_node->commandBuffer, vuid,
4220 "%s: region [%d], dest image of type VK_IMAGE_TYPE_1D with dstOffset[].y values of "
4221 "(%1d, %1d). These must be (0, 1).",
4222 func_name, i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y);
Dave Houlton48989f32017-05-26 15:01:46 -06004223 }
4224 }
4225
Dave Houlton33c2d252017-06-09 17:08:32 -06004226 if ((VK_IMAGE_TYPE_1D == dst_type) || (VK_IMAGE_TYPE_2D == dst_type)) {
Dave Houlton48989f32017-05-26 15:01:46 -06004227 if ((0 != rgn.dstOffsets[0].z) || (1 != rgn.dstOffsets[1].z)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004228 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00252" : "VUID-vkCmdBlitImage-dstImage-00252";
4229 skip |= LogError(cb_node->commandBuffer, vuid,
4230 "%s: region [%d], dest image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004231 "dstOffset[].z values of (%1d, %1d). These must be (0, 1).",
Jeff Leger178b1e52020-10-05 12:22:23 -04004232 func_name, i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z);
Dave Houlton48989f32017-05-26 15:01:46 -06004233 }
4234 }
4235
Dave Houlton33c2d252017-06-09 17:08:32 -06004236 oob = false;
Dave Houlton48989f32017-05-26 15:01:46 -06004237 if ((rgn.dstOffsets[0].x < 0) || (rgn.dstOffsets[0].x > static_cast<int32_t>(dst_extent.width)) ||
4238 (rgn.dstOffsets[1].x < 0) || (rgn.dstOffsets[1].x > static_cast<int32_t>(dst_extent.width))) {
Dave Houlton33c2d252017-06-09 17:08:32 -06004239 oob = true;
Jeff Leger178b1e52020-10-05 12:22:23 -04004240 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstOffset-00248" : "VUID-vkCmdBlitImage-dstOffset-00248";
4241 skip |= LogError(cb_node->commandBuffer, vuid,
4242 "%s: region [%d] dstOffset[].x values (%1d, %1d) exceed dstSubresource width extent (%1d).",
4243 func_name, i, rgn.dstOffsets[0].x, rgn.dstOffsets[1].x, dst_extent.width);
Dave Houlton48989f32017-05-26 15:01:46 -06004244 }
4245 if ((rgn.dstOffsets[0].y < 0) || (rgn.dstOffsets[0].y > static_cast<int32_t>(dst_extent.height)) ||
4246 (rgn.dstOffsets[1].y < 0) || (rgn.dstOffsets[1].y > static_cast<int32_t>(dst_extent.height))) {
Dave Houlton33c2d252017-06-09 17:08:32 -06004247 oob = true;
Jeff Leger178b1e52020-10-05 12:22:23 -04004248 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstOffset-00249" : "VUID-vkCmdBlitImage-dstOffset-00249";
4249 skip |= LogError(cb_node->commandBuffer, vuid,
4250 "%s: region [%d] dstOffset[].y values (%1d, %1d) exceed dstSubresource height extent (%1d).",
4251 func_name, i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y, dst_extent.height);
Dave Houlton48989f32017-05-26 15:01:46 -06004252 }
4253 if ((rgn.dstOffsets[0].z < 0) || (rgn.dstOffsets[0].z > static_cast<int32_t>(dst_extent.depth)) ||
4254 (rgn.dstOffsets[1].z < 0) || (rgn.dstOffsets[1].z > static_cast<int32_t>(dst_extent.depth))) {
Dave Houlton33c2d252017-06-09 17:08:32 -06004255 oob = true;
Jeff Leger178b1e52020-10-05 12:22:23 -04004256 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstOffset-00251" : "VUID-vkCmdBlitImage-dstOffset-00251";
4257 skip |= LogError(cb_node->commandBuffer, vuid,
4258 "%s: region [%d] dstOffset[].z values (%1d, %1d) exceed dstSubresource depth extent (%1d).",
4259 func_name, i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z, dst_extent.depth);
Dave Houlton48989f32017-05-26 15:01:46 -06004260 }
Cort Strattonff1542a2018-05-27 10:49:28 -07004261 if (oob) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004262 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-pRegions-00216" : "VUID-vkCmdBlitImage-pRegions-00216";
4263 skip |= LogError(cb_node->commandBuffer, vuid,
4264 "%s: region [%d] destination image blit region exceeds image dimensions.", func_name, i);
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004265 }
4266
Dave Houlton33c2d252017-06-09 17:08:32 -06004267 if ((VK_IMAGE_TYPE_3D == src_type) || (VK_IMAGE_TYPE_3D == dst_type)) {
4268 if ((0 != rgn.srcSubresource.baseArrayLayer) || (1 != rgn.srcSubresource.layerCount) ||
4269 (0 != rgn.dstSubresource.baseArrayLayer) || (1 != rgn.dstSubresource.layerCount)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04004270 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00240" : "VUID-vkCmdBlitImage-srcImage-00240";
4271 skip |= LogError(cb_node->commandBuffer, vuid,
4272 "%s: region [%d] blit to/from a 3D image type with a non-zero baseArrayLayer, or a "
4273 "layerCount other than 1.",
4274 func_name, i);
Mark Lobodzinski9ad96582017-02-06 14:01:54 -07004275 }
4276 }
Dave Houlton33c2d252017-06-09 17:08:32 -06004277 } // per-region checks
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07004278 } else {
4279 assert(0);
4280 }
4281 return skip;
4282}
4283
Jeff Leger178b1e52020-10-05 12:22:23 -04004284bool CoreChecks::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
4285 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
4286 const VkImageBlit *pRegions, VkFilter filter) const {
4287 return ValidateCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter,
4288 COPY_COMMAND_VERSION_1);
4289}
4290
4291bool CoreChecks::PreCallValidateCmdBlitImage2KHR(VkCommandBuffer commandBuffer, const VkBlitImageInfo2KHR *pBlitImageInfo) const {
4292 return ValidateCmdBlitImage(commandBuffer, pBlitImageInfo->srcImage, pBlitImageInfo->srcImageLayout, pBlitImageInfo->dstImage,
4293 pBlitImageInfo->dstImageLayout, pBlitImageInfo->regionCount, pBlitImageInfo->pRegions,
4294 pBlitImageInfo->filter, COPY_COMMAND_VERSION_2);
4295}
4296
4297template <typename RegionType>
4298void CoreChecks::RecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
4299 VkImageLayout dstImageLayout, uint32_t regionCount, const RegionType *pRegions,
4300 VkFilter filter) {
Mark Lobodzinskicefe42f2019-04-25 12:16:27 -06004301 auto cb_node = GetCBState(commandBuffer);
Mark Lobodzinski8ddc23f2019-03-06 11:48:49 -07004302 auto src_image_state = GetImageState(srcImage);
4303 auto dst_image_state = GetImageState(dstImage);
Mark Lobodzinski9a075c22019-01-10 14:30:39 -07004304
Norbert Garnys7bd4c2c2017-11-16 10:58:04 +01004305 // Make sure that all image slices are updated to correct layout
Mark Lobodzinski9a075c22019-01-10 14:30:39 -07004306 for (uint32_t i = 0; i < regionCount; ++i) {
John Zulauff660ad62019-03-23 07:16:05 -06004307 SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].srcSubresource, srcImageLayout);
4308 SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
Norbert Garnys7bd4c2c2017-11-16 10:58:04 +01004309 }
Mark Lobodzinski8e0c0bf2017-02-06 11:06:26 -07004310}
4311
Jeff Leger178b1e52020-10-05 12:22:23 -04004312void CoreChecks::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
4313 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
4314 const VkImageBlit *pRegions, VkFilter filter) {
4315 StateTracker::PreCallRecordCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
4316 pRegions, filter);
4317 RecordCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
4318}
4319
4320void CoreChecks::PreCallRecordCmdBlitImage2KHR(VkCommandBuffer commandBuffer, const VkBlitImageInfo2KHR *pBlitImageInfo) {
4321 StateTracker::PreCallRecordCmdBlitImage2KHR(commandBuffer, pBlitImageInfo);
4322 RecordCmdBlitImage(commandBuffer, pBlitImageInfo->srcImage, pBlitImageInfo->srcImageLayout, pBlitImageInfo->dstImage,
4323 pBlitImageInfo->dstImageLayout, pBlitImageInfo->regionCount, pBlitImageInfo->pRegions,
4324 pBlitImageInfo->filter);
4325}
4326
John Zulauf2076e812020-01-08 14:55:54 -07004327GlobalImageLayoutRangeMap *GetLayoutRangeMap(GlobalImageLayoutMap *map, const IMAGE_STATE &image_state) {
4328 assert(map);
4329 // This approach allows for a single hash lookup or/create new
4330 auto inserted = map->emplace(std::make_pair(image_state.image, nullptr));
4331 if (inserted.second) {
4332 assert(nullptr == inserted.first->second.get());
locke-lunarg296a3c92020-03-25 01:04:29 -06004333 GlobalImageLayoutRangeMap *layout_map = new GlobalImageLayoutRangeMap(image_state.subresource_encoder.SubresourceCount());
John Zulauf2076e812020-01-08 14:55:54 -07004334 inserted.first->second.reset(layout_map);
4335 return layout_map;
4336 } else {
4337 assert(nullptr != inserted.first->second.get());
4338 return inserted.first->second.get();
4339 }
4340 return nullptr;
4341}
4342
4343const GlobalImageLayoutRangeMap *GetLayoutRangeMap(const GlobalImageLayoutMap &map, VkImage image) {
4344 auto it = map.find(image);
4345 if (it != map.end()) {
4346 return it->second.get();
4347 }
4348 return nullptr;
4349}
4350
Shannon McPherson449fa9c2018-10-25 11:51:07 -06004351// This validates that the initial layout specified in the command buffer for the IMAGE is the same as the global IMAGE layout
John Zulauf2076e812020-01-08 14:55:54 -07004352bool CoreChecks::ValidateCmdBufImageLayouts(const CMD_BUFFER_STATE *pCB, const GlobalImageLayoutMap &globalImageLayoutMap,
4353 GlobalImageLayoutMap *overlayLayoutMap_arg) const {
Mark Lobodzinski90eea5b2020-05-15 12:54:00 -06004354 if (disabled[image_layout_validation]) return false;
Mark Lobodzinskib0dd9472017-02-07 16:38:17 -07004355 bool skip = false;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004356 GlobalImageLayoutMap &overlay_layout_map = *overlayLayoutMap_arg;
John Zulauff660ad62019-03-23 07:16:05 -06004357 // Iterate over the layout maps for each referenced image
John Zulauf2076e812020-01-08 14:55:54 -07004358 GlobalImageLayoutRangeMap empty_map(1);
John Zulauff660ad62019-03-23 07:16:05 -06004359 for (const auto &layout_map_entry : pCB->image_layout_map) {
4360 const auto image = layout_map_entry.first;
4361 const auto *image_state = GetImageState(image);
4362 if (!image_state) continue; // Can't check layouts of a dead image
unknown089cdb82019-07-11 12:58:43 -06004363 const auto &subres_map = layout_map_entry.second;
John Zulauf2076e812020-01-08 14:55:54 -07004364 const auto &initial_layout_map = subres_map->GetInitialLayoutMap();
John Zulauff660ad62019-03-23 07:16:05 -06004365 // Validate the initial_uses for each subresource referenced
John Zulauf2076e812020-01-08 14:55:54 -07004366 if (initial_layout_map.empty()) continue;
4367
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004368 auto *overlay_map = GetLayoutRangeMap(&overlay_layout_map, *image_state);
John Zulauf2076e812020-01-08 14:55:54 -07004369 const auto *global_map = GetLayoutRangeMap(globalImageLayoutMap, image);
4370 if (global_map == nullptr) {
4371 global_map = &empty_map;
4372 }
4373
4374 // Note: don't know if it would matter
4375 // if (global_map->empty() && overlay_map->empty()) // skip this next loop...;
4376
4377 auto pos = initial_layout_map.begin();
4378 const auto end = initial_layout_map.end();
4379 sparse_container::parallel_iterator<const ImageSubresourceLayoutMap::LayoutMap> current_layout(*overlay_map, *global_map,
4380 pos->first.begin);
4381 while (pos != end) {
locke-lunargf155ccf2020-02-18 11:34:15 -07004382 VkImageLayout initial_layout = pos->second;
John Zulauf2076e812020-01-08 14:55:54 -07004383 VkImageLayout image_layout = kInvalidLayout;
John Zulauf2076e812020-01-08 14:55:54 -07004384 if (current_layout->range.empty()) break; // When we are past the end of data in overlay and global... stop looking
locke-lunargf155ccf2020-02-18 11:34:15 -07004385 if (current_layout->pos_A->valid) { // pos_A denotes the overlay map in the parallel iterator
John Zulauf2076e812020-01-08 14:55:54 -07004386 image_layout = current_layout->pos_A->lower_bound->second;
locke-lunargf155ccf2020-02-18 11:34:15 -07004387 } else if (current_layout->pos_B->valid) { // pos_B denotes the global map in the parallel iterator
John Zulauf2076e812020-01-08 14:55:54 -07004388 image_layout = current_layout->pos_B->lower_bound->second;
4389 }
4390 const auto intersected_range = pos->first & current_layout->range;
4391 if (initial_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
4392 // TODO: Set memory invalid which is in mem_tracker currently
4393 } else if (image_layout != initial_layout) {
4394 // Need to look up the inital layout *state* to get a bit more information
4395 const auto *initial_layout_state = subres_map->GetSubresourceInitialLayoutState(pos->first.begin);
4396 assert(initial_layout_state); // There's no way we should have an initial layout without matching state...
4397 bool matches = ImageLayoutMatches(initial_layout_state->aspect_mask, image_layout, initial_layout);
4398 if (!matches) {
John Zulauf2076e812020-01-08 14:55:54 -07004399 // We can report all the errors for the intersected range directly
4400 for (auto index : sparse_container::range_view<decltype(intersected_range)>(intersected_range)) {
locke-lunarg296a3c92020-03-25 01:04:29 -06004401 const auto subresource = image_state->subresource_encoder.Decode(index);
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004402 skip |= LogError(
4403 pCB->commandBuffer, kVUID_Core_DrawState_InvalidImageLayout,
unknown089cdb82019-07-11 12:58:43 -06004404 "Submitted command buffer expects %s (subresource: aspectMask 0x%X array layer %u, mip level %u) "
Mark Lobodzinski23e395e2020-04-09 10:17:31 -06004405 "to be in layout %s--instead, current layout is %s.",
John Zulauf2076e812020-01-08 14:55:54 -07004406 report_data->FormatHandle(image).c_str(), subresource.aspectMask, subresource.arrayLayer,
Mark Lobodzinski23e395e2020-04-09 10:17:31 -06004407 subresource.mipLevel, string_VkImageLayout(initial_layout), string_VkImageLayout(image_layout));
John Zulaufb61ed972019-04-09 16:12:35 -06004408 }
Mark Lobodzinski4a3065e2017-02-07 16:36:03 -07004409 }
4410 }
John Zulauf2076e812020-01-08 14:55:54 -07004411 if (pos->first.includes(intersected_range.end)) {
4412 current_layout.seek(intersected_range.end);
4413 } else {
4414 ++pos;
4415 if (pos != end) {
4416 current_layout.seek(pos->first.begin);
4417 }
4418 }
John Zulauff660ad62019-03-23 07:16:05 -06004419 }
4420
locke-lunargf155ccf2020-02-18 11:34:15 -07004421 // Update all layout set operations (which will be a subset of the initial_layouts)
John Zulauf2076e812020-01-08 14:55:54 -07004422 sparse_container::splice(overlay_map, subres_map->GetCurrentLayoutMap(), sparse_container::value_precedence::prefer_source);
Mark Lobodzinski4a3065e2017-02-07 16:36:03 -07004423 }
John Zulauff660ad62019-03-23 07:16:05 -06004424
Mark Lobodzinskib0dd9472017-02-07 16:38:17 -07004425 return skip;
Mark Lobodzinski4a3065e2017-02-07 16:36:03 -07004426}
Mark Lobodzinskib3829a52017-02-07 16:55:53 -07004427
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06004428void CoreChecks::UpdateCmdBufImageLayouts(CMD_BUFFER_STATE *pCB) {
John Zulauff660ad62019-03-23 07:16:05 -06004429 for (const auto &layout_map_entry : pCB->image_layout_map) {
4430 const auto image = layout_map_entry.first;
John Zulauf2076e812020-01-08 14:55:54 -07004431 const auto &subres_map = layout_map_entry.second;
John Zulauff660ad62019-03-23 07:16:05 -06004432 const auto *image_state = GetImageState(image);
4433 if (!image_state) continue; // Can't set layouts of a dead image
John Zulauf2076e812020-01-08 14:55:54 -07004434 auto *global_map = GetLayoutRangeMap(&imageLayoutMap, *image_state);
4435 sparse_container::splice(global_map, subres_map->GetCurrentLayoutMap(), sparse_container::value_precedence::prefer_source);
Tony Barbourdf013b92017-01-25 12:53:48 -07004436 }
4437}
4438
Mark Lobodzinskic679b032017-02-07 17:11:55 -07004439// ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
Mark Lobodzinski552e4402017-02-07 17:14:53 -07004440// VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that READ_ONLY
4441// layout attachments don't have CLEAR as their loadOp.
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07004442bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
4443 const VkImageLayout first_layout, const uint32_t attachment,
Mike Schuchardt2df08912020-12-15 16:28:09 -08004444 const VkAttachmentDescription2 &attachment_description) const {
Mark Lobodzinski552e4402017-02-07 17:14:53 -07004445 bool skip = false;
Tobias Hectorbbb12282018-10-22 15:17:59 +01004446 const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
4447
Mark Lobodzinskic679b032017-02-07 17:11:55 -07004448 // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
sfricke-samsung55f01952020-03-24 08:16:41 -07004449 // for both loadOp and stencilLoaOp rp2 has it in 1 VU while rp1 has it in 2 VU with half behind Maintenance2 extension
4450 // Each is VUID is below in following order: rp2 -> rp1 with Maintenance2 -> rp1 with no extenstion
Mark Lobodzinskic679b032017-02-07 17:11:55 -07004451 if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
Shannon McPherson3ea65132018-12-05 10:37:39 -07004452 if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4453 (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
4454 (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL))) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004455 skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-pAttachments-02522",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004456 "vkCreateRenderPass2(): Cannot clear attachment %d with invalid first layout %s.", attachment,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004457 string_VkImageLayout(first_layout));
sfricke-samsung55f01952020-03-24 08:16:41 -07004458 } else if ((use_rp2 == false) && (device_extensions.vk_khr_maintenance2) &&
4459 (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)) {
4460 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-01566",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004461 "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
sfricke-samsung55f01952020-03-24 08:16:41 -07004462 string_VkImageLayout(first_layout));
4463 } else if ((use_rp2 == false) && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4464 (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004465 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-00836",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004466 "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004467 string_VkImageLayout(first_layout));
Mark Lobodzinskic679b032017-02-07 17:11:55 -07004468 }
4469 }
sfricke-samsung55f01952020-03-24 08:16:41 -07004470
4471 // Same as above for loadOp, but for stencilLoadOp
4472 if (attachment_description.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
4473 if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4474 (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
4475 (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL))) {
4476 skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-pAttachments-02523",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004477 "vkCreateRenderPass2(): Cannot clear attachment %d with invalid first layout %s.", attachment,
sfricke-samsung55f01952020-03-24 08:16:41 -07004478 string_VkImageLayout(first_layout));
4479 } else if ((use_rp2 == false) && (device_extensions.vk_khr_maintenance2) &&
4480 (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL)) {
4481 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-01567",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004482 "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
sfricke-samsung55f01952020-03-24 08:16:41 -07004483 string_VkImageLayout(first_layout));
4484 } else if ((use_rp2 == false) && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4485 (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
4486 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-02511",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004487 "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004488 string_VkImageLayout(first_layout));
Slawomir Cyganadf2b552018-04-24 17:18:26 +02004489 }
4490 }
4491
Mark Lobodzinski552e4402017-02-07 17:14:53 -07004492 return skip;
Mark Lobodzinskic679b032017-02-07 17:11:55 -07004493}
4494
Mark Lobodzinski96210742017-02-09 10:33:46 -07004495// Helper function to validate correct usage bits set for buffers or images. Verify that (actual & desired) flags != 0 or, if strict
4496// is true, verify that (actual & desired) flags == desired
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004497template <typename T1>
4498bool CoreChecks::ValidateUsageFlags(VkFlags actual, VkFlags desired, VkBool32 strict, const T1 object,
4499 const VulkanTypedHandle &typed_handle, const char *msgCode, char const *func_name,
4500 char const *usage_str) const {
Mark Lobodzinski96210742017-02-09 10:33:46 -07004501 bool correct_usage = false;
Mark Lobodzinski95dbbe52017-02-09 10:40:41 -07004502 bool skip = false;
John Zulauf4fea6622019-04-01 11:38:18 -06004503 const char *type_str = object_string[typed_handle.type];
Mark Lobodzinski96210742017-02-09 10:33:46 -07004504 if (strict) {
4505 correct_usage = ((actual & desired) == desired);
4506 } else {
4507 correct_usage = ((actual & desired) != 0);
4508 }
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004509
Mark Lobodzinski96210742017-02-09 10:33:46 -07004510 if (!correct_usage) {
sfricke-samsungbb971942020-09-10 22:11:56 -07004511 // All callers should have a valid VUID
4512 assert(msgCode != kVUIDUndefined);
4513 skip =
4514 LogError(object, msgCode, "Invalid usage flag for %s used by %s. In this case, %s should have %s set during creation.",
4515 report_data->FormatHandle(typed_handle).c_str(), func_name, type_str, usage_str);
Mark Lobodzinski96210742017-02-09 10:33:46 -07004516 }
Mark Lobodzinski95dbbe52017-02-09 10:40:41 -07004517 return skip;
Mark Lobodzinski96210742017-02-09 10:33:46 -07004518}
4519
4520// Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
4521// where an error will be flagged if usage is not correct
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004522bool CoreChecks::ValidateImageUsageFlags(IMAGE_STATE const *image_state, VkFlags desired, bool strict, const char *msgCode,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06004523 char const *func_name, char const *usage_string) const {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004524 return ValidateUsageFlags(image_state->createInfo.usage, desired, strict, image_state->image,
John Zulauf4fea6622019-04-01 11:38:18 -06004525 VulkanTypedHandle(image_state->image, kVulkanObjectTypeImage), msgCode, func_name, usage_string);
Mark Lobodzinski96210742017-02-09 10:33:46 -07004526}
4527
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004528bool CoreChecks::ValidateImageFormatFeatureFlags(IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
Spencer Fricke6bba8c72020-04-06 07:41:21 -07004529 char const *func_name, const char *vuid) const {
Cort Stratton186b1a22018-05-01 20:18:06 -04004530 bool skip = false;
Spencer Fricke6bba8c72020-04-06 07:41:21 -07004531 const VkFormatFeatureFlags image_format_features = image_state->format_features;
4532 if ((image_format_features & desired) != desired) {
4533 // Same error, but more details if it was an AHB external format
4534 if (image_state->has_ahb_format == true) {
4535 skip |= LogError(image_state->image, vuid,
4536 "In %s, VkFormatFeatureFlags (0x%08X) does not support required feature %s for the external format "
4537 "found in VkAndroidHardwareBufferFormatPropertiesANDROID::formatFeatures used by %s.",
4538 func_name, image_format_features, string_VkFormatFeatureFlags(desired).c_str(),
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004539 report_data->FormatHandle(image_state->image).c_str());
Spencer Fricke6bba8c72020-04-06 07:41:21 -07004540 } else {
4541 skip |= LogError(image_state->image, vuid,
4542 "In %s, VkFormatFeatureFlags (0x%08X) does not support required feature %s for format %u used by %s "
4543 "with tiling %s.",
4544 func_name, image_format_features, string_VkFormatFeatureFlags(desired).c_str(),
4545 image_state->createInfo.format, report_data->FormatHandle(image_state->image).c_str(),
4546 string_VkImageTiling(image_state->createInfo.tiling));
Cort Stratton186b1a22018-05-01 20:18:06 -04004547 }
4548 }
4549 return skip;
4550}
4551
Mark Lobodzinski33a34b82019-04-25 11:38:36 -06004552bool CoreChecks::ValidateImageSubresourceLayers(const CMD_BUFFER_STATE *cb_node, const VkImageSubresourceLayers *subresource_layers,
John Zulaufe2b7bcb2019-07-05 16:08:39 -06004553 char const *func_name, char const *member, uint32_t i) const {
Cort Strattond619a302018-05-17 19:46:32 -07004554 bool skip = false;
sfricke-samsungfdf91c82020-10-26 03:31:28 -07004555 const VkImageAspectFlags apsect_mask = subresource_layers->aspectMask;
Cort Strattond619a302018-05-17 19:46:32 -07004556 // layerCount must not be zero
4557 if (subresource_layers->layerCount == 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004558 skip |= LogError(cb_node->commandBuffer, "VUID-VkImageSubresourceLayers-layerCount-01700",
4559 "In %s, pRegions[%u].%s.layerCount must not be zero.", func_name, i, member);
Cort Strattond619a302018-05-17 19:46:32 -07004560 }
4561 // aspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT
sfricke-samsungfdf91c82020-10-26 03:31:28 -07004562 if (apsect_mask & VK_IMAGE_ASPECT_METADATA_BIT) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004563 skip |= LogError(cb_node->commandBuffer, "VUID-VkImageSubresourceLayers-aspectMask-00168",
4564 "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_METADATA_BIT set.", func_name, i, member);
Cort Strattond619a302018-05-17 19:46:32 -07004565 }
4566 // if aspectMask contains COLOR, it must not contain either DEPTH or STENCIL
sfricke-samsungfdf91c82020-10-26 03:31:28 -07004567 if ((apsect_mask & VK_IMAGE_ASPECT_COLOR_BIT) && (apsect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004568 skip |= LogError(cb_node->commandBuffer, "VUID-VkImageSubresourceLayers-aspectMask-00167",
4569 "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_COLOR_BIT and either VK_IMAGE_ASPECT_DEPTH_BIT or "
4570 "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4571 func_name, i, member);
Cort Strattond619a302018-05-17 19:46:32 -07004572 }
sfricke-samsungfdf91c82020-10-26 03:31:28 -07004573 // aspectMask must not contain VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT
4574 if (apsect_mask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
4575 VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
4576 skip |= LogError(cb_node->commandBuffer, "VUID-VkImageSubresourceLayers-aspectMask-02247",
4577 "In %s, pRegions[%u].%s.aspectMask has a VK_IMAGE_ASPECT_MEMORY_PLANE_*_BIT_EXT bit set.", func_name, i,
4578 member);
4579 }
Cort Strattond619a302018-05-17 19:46:32 -07004580 return skip;
4581}
4582
Mark Lobodzinski96210742017-02-09 10:33:46 -07004583// Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
4584// where an error will be flagged if usage is not correct
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004585bool CoreChecks::ValidateBufferUsageFlags(BUFFER_STATE const *buffer_state, VkFlags desired, bool strict, const char *msgCode,
John Zulauf005c5012019-07-10 17:15:47 -06004586 char const *func_name, char const *usage_string) const {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004587 return ValidateUsageFlags(buffer_state->createInfo.usage, desired, strict, buffer_state->buffer,
John Zulauf4fea6622019-04-01 11:38:18 -06004588 VulkanTypedHandle(buffer_state->buffer, kVulkanObjectTypeBuffer), msgCode, func_name, usage_string);
Mark Lobodzinski96210742017-02-09 10:33:46 -07004589}
4590
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004591bool CoreChecks::ValidateBufferViewRange(const BUFFER_STATE *buffer_state, const VkBufferViewCreateInfo *pCreateInfo,
Jeff Bolz46c0ea02019-10-09 13:06:29 -05004592 const VkPhysicalDeviceLimits *device_limits) const {
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004593 bool skip = false;
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004594
4595 const VkDeviceSize &range = pCreateInfo->range;
4596 if (range != VK_WHOLE_SIZE) {
4597 // Range must be greater than 0
4598 if (range <= 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004599 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-range-00928",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004600 "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004601 ") does not equal VK_WHOLE_SIZE, range must be greater than 0.",
4602 range);
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004603 }
4604 // Range must be a multiple of the element size of format
Petr Kraus5a01b472019-08-10 01:40:28 +02004605 const uint32_t format_size = FormatElementSize(pCreateInfo->format);
4606 if (SafeModulo(range, format_size) != 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004607 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-range-00929",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004608 "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004609 ") does not equal VK_WHOLE_SIZE, range must be a multiple of the element size of the format "
4610 "(%" PRIu32 ").",
4611 range, format_size);
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004612 }
4613 // Range divided by the element size of format must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements
Petr Kraus5a01b472019-08-10 01:40:28 +02004614 if (SafeDivision(range, format_size) > device_limits->maxTexelBufferElements) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004615 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-range-00930",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004616 "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004617 ") does not equal VK_WHOLE_SIZE, range divided by the element size of the format (%" PRIu32
4618 ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").",
4619 range, format_size, device_limits->maxTexelBufferElements);
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004620 }
4621 // The sum of range and offset must be less than or equal to the size of buffer
4622 if (range + pCreateInfo->offset > buffer_state->createInfo.size) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004623 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-offset-00931",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004624 "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004625 ") does not equal VK_WHOLE_SIZE, the sum of offset (%" PRIuLEAST64
4626 ") and range must be less than or equal to the size of the buffer (%" PRIuLEAST64 ").",
4627 range, pCreateInfo->offset, buffer_state->createInfo.size);
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004628 }
janharaldfredriksen-armde71d202020-07-08 12:11:53 +02004629 } else {
4630 const uint32_t format_size = FormatElementSize(pCreateInfo->format);
4631
4632 // Size of buffer - offset, divided by the element size of format must be less than or equal to
4633 // VkPhysicalDeviceLimits::maxTexelBufferElements
4634 if (SafeDivision(buffer_state->createInfo.size - pCreateInfo->offset, format_size) >
4635 device_limits->maxTexelBufferElements) {
4636 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-range-04059",
4637 "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
4638 ") equals VK_WHOLE_SIZE, the buffer's size (%" PRIuLEAST64 ") minus the offset (%" PRIuLEAST64
4639 "), divided by the element size of the format (%" PRIu32
4640 ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").",
4641 range, buffer_state->createInfo.size, pCreateInfo->offset, format_size,
4642 device_limits->maxTexelBufferElements);
4643 }
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004644 }
4645 return skip;
4646}
4647
Jeff Bolz46c0ea02019-10-09 13:06:29 -05004648bool CoreChecks::ValidateBufferViewBuffer(const BUFFER_STATE *buffer_state, const VkBufferViewCreateInfo *pCreateInfo) const {
Shannon McPherson265383a2018-06-21 15:37:52 -06004649 bool skip = false;
Mark Lobodzinski5c048802019-03-07 10:47:31 -07004650 const VkFormatProperties format_properties = GetPDFormatProperties(pCreateInfo->format);
Shannon McPherson265383a2018-06-21 15:37:52 -06004651 if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) &&
4652 !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004653 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-buffer-00933",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004654 "vkCreateBufferView(): If buffer was created with `usage` containing "
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08004655 "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, format (%s) must "
4656 "be supported for uniform texel buffers",
4657 string_VkFormat(pCreateInfo->format));
Shannon McPherson265383a2018-06-21 15:37:52 -06004658 }
4659 if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) &&
4660 !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004661 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-buffer-00934",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004662 "vkCreateBufferView(): If buffer was created with `usage` containing "
sfricke-samsungf3a9b5b2021-01-13 13:05:52 -08004663 "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, format (%s) must "
4664 "be supported for storage texel buffers",
4665 string_VkFormat(pCreateInfo->format));
Shannon McPherson265383a2018-06-21 15:37:52 -06004666 }
4667 return skip;
4668}
4669
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07004670bool CoreChecks::PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
Jeff Bolz5c801d12019-10-09 10:38:45 -05004671 const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) const {
Mark Lobodzinski96210742017-02-09 10:33:46 -07004672 bool skip = false;
Mark Lobodzinski847b60c2017-03-13 09:32:45 -06004673
Dave Houltond8ed0212018-05-16 17:18:24 -06004674 // TODO: Add check for "VUID-vkCreateBuffer-flags-00911" (sparse address space accounting)
Mark Lobodzinski847b60c2017-03-13 09:32:45 -06004675
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07004676 auto chained_devaddr_struct = LvlFindInChain<VkBufferDeviceAddressCreateInfoEXT>(pCreateInfo->pNext);
Jeff Bolz87697532019-01-11 22:54:00 -06004677 if (chained_devaddr_struct) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08004678 if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT) &&
Jeff Bolz87697532019-01-11 22:54:00 -06004679 chained_devaddr_struct->deviceAddress != 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004680 skip |= LogError(device, "VUID-VkBufferCreateInfo-deviceAddress-02604",
4681 "vkCreateBuffer(): Non-zero VkBufferDeviceAddressCreateInfoEXT::deviceAddress "
Mike Schuchardt2df08912020-12-15 16:28:09 -08004682 "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT.");
Jeff Bolz87697532019-01-11 22:54:00 -06004683 }
4684 }
4685
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07004686 auto chained_opaqueaddr_struct = LvlFindInChain<VkBufferOpaqueCaptureAddressCreateInfo>(pCreateInfo->pNext);
Jeff Bolz4563f2a2019-12-10 13:30:30 -06004687 if (chained_opaqueaddr_struct) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08004688 if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT) &&
Jeff Bolz4563f2a2019-12-10 13:30:30 -06004689 chained_opaqueaddr_struct->opaqueCaptureAddress != 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004690 skip |= LogError(device, "VUID-VkBufferCreateInfo-opaqueCaptureAddress-03337",
Mike Schuchardt2df08912020-12-15 16:28:09 -08004691 "vkCreateBuffer(): Non-zero VkBufferOpaqueCaptureAddressCreateInfo::opaqueCaptureAddress"
4692 "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT.");
Jeff Bolz4563f2a2019-12-10 13:30:30 -06004693 }
4694 }
4695
Mike Schuchardt2df08912020-12-15 16:28:09 -08004696 if ((pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT) &&
Jeff Bolz33fc6722020-03-31 12:58:16 -05004697 !enabled_features.core12.bufferDeviceAddressCaptureReplay &&
4698 !enabled_features.buffer_device_address_ext.bufferDeviceAddressCaptureReplay) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004699 skip |= LogError(
4700 device, "VUID-VkBufferCreateInfo-flags-03338",
Jeff Bolz87697532019-01-11 22:54:00 -06004701 "vkCreateBuffer(): the bufferDeviceAddressCaptureReplay device feature is disabled: Buffers cannot be created with "
Mike Schuchardt2df08912020-12-15 16:28:09 -08004702 "the VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT set.");
Jeff Bolz87697532019-01-11 22:54:00 -06004703 }
4704
Mark Lobodzinski08ee03c2019-02-04 10:57:47 -07004705 if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
Mark Lobodzinski314b9162020-07-16 15:33:08 -06004706 skip |= ValidatePhysicalDeviceQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
4707 "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices",
4708 "VUID-VkBufferCreateInfo-sharingMode-01419");
Mark Lobodzinski08ee03c2019-02-04 10:57:47 -07004709 }
4710
sfricke-samsungedce77a2020-07-03 22:35:13 -07004711 if ((pCreateInfo->flags & VK_BUFFER_CREATE_PROTECTED_BIT) != 0) {
4712 if (enabled_features.core11.protectedMemory == VK_FALSE) {
4713 skip |= LogError(device, "VUID-VkBufferCreateInfo-flags-01887",
4714 "vkCreateBuffer(): the protectedMemory device feature is disabled: Buffers cannot be created with the "
4715 "VK_BUFFER_CREATE_PROTECTED_BIT set.");
4716 }
4717 const VkBufferCreateFlags invalid_flags =
4718 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT;
4719 if ((pCreateInfo->flags & invalid_flags) != 0) {
4720 skip |= LogError(device, "VUID-VkBufferCreateInfo-None-01888",
4721 "vkCreateBuffer(): VK_BUFFER_CREATE_PROTECTED_BIT is set so no sparse create flags can be used at "
4722 "same time (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | "
4723 "VK_BUFFER_CREATE_SPARSE_ALIASED_BIT).");
4724 }
4725 }
4726
Mark Lobodzinski96210742017-02-09 10:33:46 -07004727 return skip;
4728}
4729
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07004730bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
Jeff Bolz5c801d12019-10-09 10:38:45 -05004731 const VkAllocationCallbacks *pAllocator, VkBufferView *pView) const {
Mark Lobodzinski95dbbe52017-02-09 10:40:41 -07004732 bool skip = false;
Jeff Bolz46c0ea02019-10-09 13:06:29 -05004733 const BUFFER_STATE *buffer_state = GetBufferState(pCreateInfo->buffer);
Mark Lobodzinski96210742017-02-09 10:33:46 -07004734 // If this isn't a sparse buffer, it needs to have memory backing it at CreateBufferView time
4735 if (buffer_state) {
Mark Lobodzinski0ebe9712019-03-07 13:39:07 -07004736 skip |= ValidateMemoryIsBoundToBuffer(buffer_state, "vkCreateBufferView()", "VUID-VkBufferViewCreateInfo-buffer-00935");
Mark Lobodzinski96210742017-02-09 10:33:46 -07004737 // In order to create a valid buffer view, the buffer must have been created with at least one of the following flags:
4738 // UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004739 skip |= ValidateBufferUsageFlags(buffer_state,
Dave Houltond8ed0212018-05-16 17:18:24 -06004740 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
4741 "VUID-VkBufferViewCreateInfo-buffer-00932", "vkCreateBufferView()",
4742 "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
Shannon McPherson883f6092018-06-14 13:15:25 -06004743
Shannon McPherson0eb84f62018-06-18 16:32:40 -06004744 // Buffer view offset must be less than the size of buffer
4745 if (pCreateInfo->offset >= buffer_state->createInfo.size) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004746 skip |= LogError(buffer_state->buffer, "VUID-VkBufferViewCreateInfo-offset-00925",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004747 "vkCreateBufferView(): VkBufferViewCreateInfo offset (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004748 ") must be less than the size of the buffer (%" PRIuLEAST64 ").",
4749 pCreateInfo->offset, buffer_state->createInfo.size);
Shannon McPherson0eb84f62018-06-18 16:32:40 -06004750 }
4751
Mark Lobodzinski79b5d5b2019-04-19 12:27:10 -06004752 const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
Jeff Bolzd5554e62019-07-19 13:23:52 -05004753 // Buffer view offset must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment
4754 if ((pCreateInfo->offset % device_limits->minTexelBufferOffsetAlignment) != 0 &&
4755 !enabled_features.texel_buffer_alignment_features.texelBufferAlignment) {
sfricke-samsung9b9c8602020-05-16 01:19:53 -07004756 const char *vuid = device_extensions.vk_ext_texel_buffer_alignment ? "VUID-VkBufferViewCreateInfo-offset-02749"
4757 : "VUID-VkBufferViewCreateInfo-offset-00926";
4758 skip |= LogError(buffer_state->buffer, vuid,
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004759 "vkCreateBufferView(): VkBufferViewCreateInfo offset (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004760 ") must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment (%" PRIuLEAST64 ").",
4761 pCreateInfo->offset, device_limits->minTexelBufferOffsetAlignment);
Jeff Bolzd5554e62019-07-19 13:23:52 -05004762 }
4763
4764 if (enabled_features.texel_buffer_alignment_features.texelBufferAlignment) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004765 VkDeviceSize element_size = FormatElementSize(pCreateInfo->format);
4766 if ((element_size % 3) == 0) {
4767 element_size /= 3;
Jeff Bolzd5554e62019-07-19 13:23:52 -05004768 }
4769 if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004770 VkDeviceSize alignment_requirement =
Jeff Bolzd5554e62019-07-19 13:23:52 -05004771 phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes;
4772 if (phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004773 alignment_requirement = std::min(alignment_requirement, element_size);
Jeff Bolzd5554e62019-07-19 13:23:52 -05004774 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004775 if (SafeModulo(pCreateInfo->offset, alignment_requirement) != 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004776 skip |= LogError(
4777 buffer_state->buffer, "VUID-VkBufferViewCreateInfo-buffer-02750",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004778 "vkCreateBufferView(): If buffer was created with usage containing "
4779 "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, "
Jeff Bolzd5554e62019-07-19 13:23:52 -05004780 "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4781 ") must be a multiple of the lesser of "
4782 "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64
4783 ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetSingleTexelAlignment "
4784 "(%" PRId32
4785 ") is VK_TRUE, the size of a texel of the requested format. "
4786 "If the size of a texel is a multiple of three bytes, then the size of a "
4787 "single component of format is used instead",
4788 pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes,
4789 phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment);
4790 }
4791 }
4792 if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004793 VkDeviceSize alignment_requirement =
Jeff Bolzd5554e62019-07-19 13:23:52 -05004794 phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes;
4795 if (phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment) {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004796 alignment_requirement = std::min(alignment_requirement, element_size);
Jeff Bolzd5554e62019-07-19 13:23:52 -05004797 }
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004798 if (SafeModulo(pCreateInfo->offset, alignment_requirement) != 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004799 skip |= LogError(
4800 buffer_state->buffer, "VUID-VkBufferViewCreateInfo-buffer-02751",
sfricke-samsungf8a3a9b2020-06-12 23:51:51 -07004801 "vkCreateBufferView(): If buffer was created with usage containing "
4802 "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, "
Jeff Bolzd5554e62019-07-19 13:23:52 -05004803 "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4804 ") must be a multiple of the lesser of "
4805 "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64
4806 ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetSingleTexelAlignment "
4807 "(%" PRId32
4808 ") is VK_TRUE, the size of a texel of the requested format. "
4809 "If the size of a texel is a multiple of three bytes, then the size of a "
4810 "single component of format is used instead",
4811 pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes,
4812 phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment);
4813 }
4814 }
4815 }
Shannon McPherson4c9505b2018-06-19 15:18:55 -06004816
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004817 skip |= ValidateBufferViewRange(buffer_state, pCreateInfo, device_limits);
Shannon McPherson265383a2018-06-21 15:37:52 -06004818
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07004819 skip |= ValidateBufferViewBuffer(buffer_state, pCreateInfo);
Mark Lobodzinski96210742017-02-09 10:33:46 -07004820 }
Mark Lobodzinski95dbbe52017-02-09 10:40:41 -07004821 return skip;
Mark Lobodzinski96210742017-02-09 10:33:46 -07004822}
4823
Mark Lobodzinski602de982017-02-09 11:01:33 -07004824// For the given format verify that the aspect masks make sense
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07004825bool CoreChecks::ValidateImageAspectMask(VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, const char *func_name,
John Zulauf9d2b6382019-07-25 15:21:36 -06004826 const char *vuid) const {
Mark Lobodzinski602de982017-02-09 11:01:33 -07004827 bool skip = false;
sfricke-samsung79b00482020-04-01 21:15:50 -07004828 const IMAGE_STATE *image_state = GetImageState(image);
4829 // checks color format and (single-plane or non-disjoint)
4830 // if ycbcr extension is not supported then single-plane and non-disjoint are always both true
sfricke-samsung71bc6572020-04-29 15:49:43 -07004831 if ((FormatIsColor(format)) && ((FormatIsMultiplane(format) == false) || (image_state->disjoint == false))) {
Mark Lobodzinski602de982017-02-09 11:01:33 -07004832 if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004833 skip |= LogError(
4834 image, vuid,
4835 "%s: Using format (%s) with aspect flags (%s) but color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set.",
4836 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004837 } else if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != aspect_mask) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004838 skip |= LogError(image, vuid,
4839 "%s: Using format (%s) with aspect flags (%s) but color image formats must have ONLY the "
4840 "VK_IMAGE_ASPECT_COLOR_BIT set.",
4841 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004842 }
Dave Houlton1d2022c2017-03-29 11:43:58 -06004843 } else if (FormatIsDepthAndStencil(format)) {
Mark Lobodzinski602de982017-02-09 11:01:33 -07004844 if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004845 skip |= LogError(image, vuid,
sfricke-samsung7687a482021-01-29 23:19:22 -08004846 "%s: Using format (%s) with aspect flags (%s) but depth/stencil image formats must have at least one "
4847 "of VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT set.",
4848 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004849 } else if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspect_mask) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004850 skip |= LogError(image, vuid,
sfricke-samsung7687a482021-01-29 23:19:22 -08004851 "%s: Using format (%s) with aspect flags (%s) but combination depth/stencil image formats can have "
4852 "only the VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT set.",
4853 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004854 }
Dave Houlton1d2022c2017-03-29 11:43:58 -06004855 } else if (FormatIsDepthOnly(format)) {
Mark Lobodzinski602de982017-02-09 11:01:33 -07004856 if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004857 skip |= LogError(image, vuid,
4858 "%s: Using format (%s) with aspect flags (%s) but depth-only image formats must have the "
4859 "VK_IMAGE_ASPECT_DEPTH_BIT set.",
4860 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004861 } else if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspect_mask) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004862 skip |= LogError(image, vuid,
4863 "%s: Using format (%s) with aspect flags (%s) but depth-only image formats can have only the "
4864 "VK_IMAGE_ASPECT_DEPTH_BIT set.",
4865 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004866 }
Dave Houlton1d2022c2017-03-29 11:43:58 -06004867 } else if (FormatIsStencilOnly(format)) {
Mark Lobodzinski602de982017-02-09 11:01:33 -07004868 if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004869 skip |= LogError(image, vuid,
4870 "%s: Using format (%s) with aspect flags (%s) but stencil-only image formats must have the "
4871 "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4872 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004873 } else if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspect_mask) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004874 skip |= LogError(image, vuid,
4875 "%s: Using format (%s) with aspect flags (%s) but stencil-only image formats can have only the "
4876 "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4877 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07004878 }
Dave Houlton501b15b2018-03-30 15:07:41 -06004879 } else if (FormatIsMultiplane(format)) {
4880 VkImageAspectFlags valid_flags = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
4881 if (3 == FormatPlaneCount(format)) {
4882 valid_flags = valid_flags | VK_IMAGE_ASPECT_PLANE_2_BIT;
4883 }
4884 if ((aspect_mask & valid_flags) != aspect_mask) {
sfricke-samsung7687a482021-01-29 23:19:22 -08004885 skip |= LogError(image, vuid,
4886 "%s: Using format (%s) with aspect flags (%s) but multi-plane image formats may have only "
4887 "VK_IMAGE_ASPECT_COLOR_BIT or VK_IMAGE_ASPECT_PLANE_n_BITs set, where n = [0, 1, 2].",
4888 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
Dave Houlton501b15b2018-03-30 15:07:41 -06004889 }
Mark Lobodzinski602de982017-02-09 11:01:33 -07004890 }
4891 return skip;
4892}
4893
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07004894bool CoreChecks::ValidateImageSubresourceRange(const uint32_t image_mip_count, const uint32_t image_layer_count,
4895 const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004896 const char *param_name, const char *image_layer_count_var_name, const VkImage image,
4897 SubresourceRangeErrorCodes errorCodes) const {
Mark Lobodzinski602de982017-02-09 11:01:33 -07004898 bool skip = false;
Petr Kraus4d718682017-05-18 03:38:41 +02004899
4900 // Validate mip levels
Petr Krausffa94af2017-08-08 21:46:02 +02004901 if (subresourceRange.baseMipLevel >= image_mip_count) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004902 skip |= LogError(image, errorCodes.base_mip_err,
4903 "%s: %s.baseMipLevel (= %" PRIu32
4904 ") is greater or equal to the mip level count of the image (i.e. greater or equal to %" PRIu32 ").",
4905 cmd_name, param_name, subresourceRange.baseMipLevel, image_mip_count);
Petr Krausffa94af2017-08-08 21:46:02 +02004906 }
Petr Kraus4d718682017-05-18 03:38:41 +02004907
Petr Krausffa94af2017-08-08 21:46:02 +02004908 if (subresourceRange.levelCount != VK_REMAINING_MIP_LEVELS) {
4909 if (subresourceRange.levelCount == 0) {
sfricke-samsung40b79e32020-05-24 00:27:26 -07004910 skip |=
4911 LogError(image, "VUID-VkImageSubresourceRange-levelCount-01720", "%s: %s.levelCount is 0.", cmd_name, param_name);
Petr Krausffa94af2017-08-08 21:46:02 +02004912 } else {
4913 const uint64_t necessary_mip_count = uint64_t{subresourceRange.baseMipLevel} + uint64_t{subresourceRange.levelCount};
Petr Kraus4d718682017-05-18 03:38:41 +02004914
Petr Krausffa94af2017-08-08 21:46:02 +02004915 if (necessary_mip_count > image_mip_count) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004916 skip |= LogError(image, errorCodes.mip_count_err,
4917 "%s: %s.baseMipLevel + .levelCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
4918 ") is greater than the mip level count of the image (i.e. greater than %" PRIu32 ").",
4919 cmd_name, param_name, subresourceRange.baseMipLevel, subresourceRange.levelCount,
4920 necessary_mip_count, image_mip_count);
Petr Krausffa94af2017-08-08 21:46:02 +02004921 }
Petr Kraus4d718682017-05-18 03:38:41 +02004922 }
Mark Lobodzinski602de982017-02-09 11:01:33 -07004923 }
Petr Kraus4d718682017-05-18 03:38:41 +02004924
4925 // Validate array layers
Petr Krausffa94af2017-08-08 21:46:02 +02004926 if (subresourceRange.baseArrayLayer >= image_layer_count) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004927 skip |= LogError(image, errorCodes.base_layer_err,
4928 "%s: %s.baseArrayLayer (= %" PRIu32
4929 ") is greater or equal to the %s of the image when it was created (i.e. greater or equal to %" PRIu32 ").",
4930 cmd_name, param_name, subresourceRange.baseArrayLayer, image_layer_count_var_name, image_layer_count);
Petr Krausffa94af2017-08-08 21:46:02 +02004931 }
Petr Kraus4d718682017-05-18 03:38:41 +02004932
Petr Krausffa94af2017-08-08 21:46:02 +02004933 if (subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS) {
4934 if (subresourceRange.layerCount == 0) {
sfricke-samsung40b79e32020-05-24 00:27:26 -07004935 skip |=
4936 LogError(image, "VUID-VkImageSubresourceRange-layerCount-01721", "%s: %s.layerCount is 0.", cmd_name, param_name);
Petr Krausffa94af2017-08-08 21:46:02 +02004937 } else {
4938 const uint64_t necessary_layer_count =
4939 uint64_t{subresourceRange.baseArrayLayer} + uint64_t{subresourceRange.layerCount};
Petr Kraus8423f152017-05-26 01:20:04 +02004940
Petr Krausffa94af2017-08-08 21:46:02 +02004941 if (necessary_layer_count > image_layer_count) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07004942 skip |= LogError(image, errorCodes.layer_count_err,
4943 "%s: %s.baseArrayLayer + .layerCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
4944 ") is greater than the %s of the image when it was created (i.e. greater than %" PRIu32 ").",
4945 cmd_name, param_name, subresourceRange.baseArrayLayer, subresourceRange.layerCount,
4946 necessary_layer_count, image_layer_count_var_name, image_layer_count);
Petr Krausffa94af2017-08-08 21:46:02 +02004947 }
Petr Kraus4d718682017-05-18 03:38:41 +02004948 }
Mark Lobodzinski602de982017-02-09 11:01:33 -07004949 }
Petr Kraus4d718682017-05-18 03:38:41 +02004950
Mark Lobodzinski602de982017-02-09 11:01:33 -07004951 return skip;
4952}
4953
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07004954bool CoreChecks::ValidateCreateImageViewSubresourceRange(const IMAGE_STATE *image_state, bool is_imageview_2d_type,
Jeff Bolz46c0ea02019-10-09 13:06:29 -05004955 const VkImageSubresourceRange &subresourceRange) const {
Tony-LunarG2ec96bb2019-11-26 13:43:02 -07004956 bool is_khr_maintenance1 = IsExtEnabled(device_extensions.vk_khr_maintenance1);
Petr Krausffa94af2017-08-08 21:46:02 +02004957 bool is_image_slicable = image_state->createInfo.imageType == VK_IMAGE_TYPE_3D &&
Mike Schuchardt2df08912020-12-15 16:28:09 -08004958 (image_state->createInfo.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004959 bool is_3_d_to_2_d_map = is_khr_maintenance1 && is_image_slicable && is_imageview_2d_type;
Petr Krausffa94af2017-08-08 21:46:02 +02004960
David McFarland2853f2f2020-11-30 15:50:39 -04004961 uint32_t image_layer_count;
4962
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004963 if (is_3_d_to_2_d_map) {
David McFarland2853f2f2020-11-30 15:50:39 -04004964 const auto layers = LayersFromRange(subresourceRange);
4965 const auto extent = GetImageSubresourceExtent(image_state, &layers);
4966 image_layer_count = extent.depth;
4967 } else {
4968 image_layer_count = image_state->createInfo.arrayLayers;
4969 }
4970
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004971 const auto image_layer_count_var_name = is_3_d_to_2_d_map ? "extent.depth" : "arrayLayers";
Petr Krausffa94af2017-08-08 21:46:02 +02004972
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004973 SubresourceRangeErrorCodes subresource_range_error_codes = {};
4974 subresource_range_error_codes.base_mip_err = "VUID-VkImageViewCreateInfo-subresourceRange-01478";
4975 subresource_range_error_codes.mip_count_err = "VUID-VkImageViewCreateInfo-subresourceRange-01718";
4976 subresource_range_error_codes.base_layer_err =
4977 is_khr_maintenance1
4978 ? (is_3_d_to_2_d_map ? "VUID-VkImageViewCreateInfo-image-02724" : "VUID-VkImageViewCreateInfo-image-01482")
4979 : "VUID-VkImageViewCreateInfo-subresourceRange-01480";
4980 subresource_range_error_codes.layer_count_err = is_khr_maintenance1
4981 ? (is_3_d_to_2_d_map ? "VUID-VkImageViewCreateInfo-subresourceRange-02725"
4982 : "VUID-VkImageViewCreateInfo-subresourceRange-01483")
4983 : "VUID-VkImageViewCreateInfo-subresourceRange-01719";
Petr Krausffa94af2017-08-08 21:46:02 +02004984
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07004985 return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_layer_count, subresourceRange,
Petr Krausffa94af2017-08-08 21:46:02 +02004986 "vkCreateImageView", "pCreateInfo->subresourceRange", image_layer_count_var_name,
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004987 image_state->image, subresource_range_error_codes);
Petr Krausffa94af2017-08-08 21:46:02 +02004988}
4989
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07004990bool CoreChecks::ValidateCmdClearColorSubresourceRange(const IMAGE_STATE *image_state,
John Zulauf07288512019-07-05 11:09:50 -06004991 const VkImageSubresourceRange &subresourceRange,
4992 const char *param_name) const {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07004993 SubresourceRangeErrorCodes subresource_range_error_codes = {};
4994 subresource_range_error_codes.base_mip_err = "VUID-vkCmdClearColorImage-baseMipLevel-01470";
4995 subresource_range_error_codes.mip_count_err = "VUID-vkCmdClearColorImage-pRanges-01692";
4996 subresource_range_error_codes.base_layer_err = "VUID-vkCmdClearColorImage-baseArrayLayer-01472";
4997 subresource_range_error_codes.layer_count_err = "VUID-vkCmdClearColorImage-pRanges-01693";
Petr Krausffa94af2017-08-08 21:46:02 +02004998
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07004999 return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005000 "vkCmdClearColorImage", param_name, "arrayLayers", image_state->image,
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07005001 subresource_range_error_codes);
Petr Krausffa94af2017-08-08 21:46:02 +02005002}
5003
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005004bool CoreChecks::ValidateCmdClearDepthSubresourceRange(const IMAGE_STATE *image_state,
John Zulaufeabb4462019-07-05 14:13:03 -06005005 const VkImageSubresourceRange &subresourceRange,
5006 const char *param_name) const {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07005007 SubresourceRangeErrorCodes subresource_range_error_codes = {};
5008 subresource_range_error_codes.base_mip_err = "VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474";
5009 subresource_range_error_codes.mip_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01694";
5010 subresource_range_error_codes.base_layer_err = "VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476";
5011 subresource_range_error_codes.layer_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01695";
Petr Krausffa94af2017-08-08 21:46:02 +02005012
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005013 return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005014 "vkCmdClearDepthStencilImage", param_name, "arrayLayers", image_state->image,
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07005015 subresource_range_error_codes);
Petr Krausffa94af2017-08-08 21:46:02 +02005016}
5017
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005018bool CoreChecks::ValidateImageBarrierSubresourceRange(const IMAGE_STATE *image_state,
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07005019 const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
John Zulaufa4472282019-08-22 14:44:34 -06005020 const char *param_name) const {
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07005021 SubresourceRangeErrorCodes subresource_range_error_codes = {};
5022 subresource_range_error_codes.base_mip_err = "VUID-VkImageMemoryBarrier-subresourceRange-01486";
5023 subresource_range_error_codes.mip_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01724";
5024 subresource_range_error_codes.base_layer_err = "VUID-VkImageMemoryBarrier-subresourceRange-01488";
5025 subresource_range_error_codes.layer_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01725";
Petr Krausffa94af2017-08-08 21:46:02 +02005026
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005027 return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07005028 cmd_name, param_name, "arrayLayers", image_state->image, subresource_range_error_codes);
Petr Krausffa94af2017-08-08 21:46:02 +02005029}
5030
Jeremy Gebben50e0b412021-02-18 10:39:41 -07005031namespace barrier_queue_families {
5032enum VuIndex {
5033 kSrcOrDstMustBeIgnore,
5034 kSpecialOrIgnoreOnly,
5035 kSrcAndDstValidOrSpecial,
5036 kSrcAndDestMustBeIgnore,
5037 kSrcAndDstBothValid,
5038 kSubmitQueueMustMatchSrcOrDst
5039};
5040static const char *vu_summary[] = {"Source or destination queue family must be ignored.",
5041 "Source or destination queue family must be special or ignored.",
5042 "Destination queue family must be ignored if source queue family is.",
5043 "Destination queue family must be valid, ignored, or special.",
5044 "Source queue family must be valid, ignored, or special.",
5045 "Source and destination queue family must both be ignored.",
5046 "Source and destination queue family must both be ignore or both valid.",
5047 "Source or destination queue family must match submit queue family, if not ignored."};
5048
5049static const std::string kImageErrorCodes[] = {
5050 "VUID-VkImageMemoryBarrier-synchronization2-03857", // kSrcOrDstMustBeIgnore
5051 "VUID-VkImageMemoryBarrier-image-04071", // kSpecialOrIgnoreOnly
5052 "VUID-VkImageMemoryBarrier-image-04072", // kSrcAndDstValidOrSpecial
5053 "VUID-VkImageMemoryBarrier-synchronization2-03856", // kSrcAndDestMustBeIgnore
5054 "VUID-VkImageMemoryBarrier-image-04069", // kSrcAndDstBothValid
5055 "UNASSIGNED-CoreValidation-vkImageMemoryBarrier-sharing-mode-exclusive-same-family", // kSubmitQueueMustMatchSrcOrDst
5056};
5057
5058static const std::string kBufferErrorCodes[] = {
5059 "VUID-VkBufferMemoryBarrier-synchronization2-03853", // kSrcOrDstMustBeIgnore
5060 "VUID-VkBufferMemoryBarrier-buffer-04088", // kSpecialOrIgnoreOnly
5061 "VUID-VkBufferMemoryBarrier-buffer-04089", // kSrcAndDstValidOrSpecial
5062 "VUID-VkBufferMemoryBarrier-synchronization2-03852", // kSrcAndDestMustBeIgnore
5063 "VUID-VkBufferMemoryBarrier-buffer-04086", // kSrcAndDstBothValid
5064 "UNASSIGNED-CoreValidation-vkBufferMemoryBarrier-sharing-mode-exclusive-same-family", // kSubmitQueueMustMatchSrcOrDst
5065};
5066
5067class ValidatorState {
5068 public:
5069 ValidatorState(const ValidationStateTracker *device_data, const char *func_name, const CMD_BUFFER_STATE *cb_state,
5070 const VulkanTypedHandle &barrier_handle, const VkSharingMode sharing_mode)
5071 : device_data_(device_data),
5072 func_name_(func_name),
5073 command_buffer_(cb_state->commandBuffer),
5074 barrier_handle_(barrier_handle),
5075 sharing_mode_(sharing_mode),
5076 val_codes_(barrier_handle.type == kVulkanObjectTypeImage ? kImageErrorCodes : kBufferErrorCodes),
5077 limit_(static_cast<uint32_t>(device_data->physical_device_state->queue_family_properties.size())),
5078 mem_ext_(IsExtEnabled(device_data->device_extensions.vk_khr_external_memory)) {}
5079
5080 // Log the messages using boilerplate from object state, and Vu specific information from the template arg
5081 // One and two family versions, in the single family version, Vu holds the name of the passed parameter
5082 bool LogMsg(VuIndex vu_index, uint32_t family, const char *param_name) const {
5083 const std::string &val_code = val_codes_[vu_index];
5084 const char *annotation = GetFamilyAnnotation(family);
5085 return device_data_->LogError(command_buffer_, val_code,
5086 "%s: Barrier using %s %s created with sharingMode %s, has %s %u%s. %s", func_name_,
5087 GetTypeString(), device_data_->report_data->FormatHandle(barrier_handle_).c_str(),
5088 GetModeString(), param_name, family, annotation, vu_summary[vu_index]);
5089 }
5090
5091 bool LogMsg(VuIndex vu_index, uint32_t src_family, uint32_t dst_family) const {
5092 const std::string &val_code = val_codes_[vu_index];
5093 const char *src_annotation = GetFamilyAnnotation(src_family);
5094 const char *dst_annotation = GetFamilyAnnotation(dst_family);
5095 return device_data_->LogError(
5096 command_buffer_, val_code,
5097 "%s: Barrier using %s %s created with sharingMode %s, has srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
5098 func_name_, GetTypeString(), device_data_->report_data->FormatHandle(barrier_handle_).c_str(), GetModeString(),
5099 src_family, src_annotation, dst_family, dst_annotation, vu_summary[vu_index]);
5100 }
5101
5102 // This abstract Vu can only be tested at submit time, thus we need a callback from the closure containing the needed
5103 // data. Note that the mem_barrier is copied to the closure as the lambda lifespan exceed the guarantees of validity for
5104 // application input.
5105 static bool ValidateAtQueueSubmit(const QUEUE_STATE *queue_state, const ValidationStateTracker *device_data,
5106 uint32_t src_family, uint32_t dst_family, const ValidatorState &val) {
5107 uint32_t queue_family = queue_state->queueFamilyIndex;
5108 if ((src_family != queue_family) && (dst_family != queue_family)) {
5109 const std::string &val_code = val.val_codes_[kSubmitQueueMustMatchSrcOrDst];
5110 const char *src_annotation = val.GetFamilyAnnotation(src_family);
5111 const char *dst_annotation = val.GetFamilyAnnotation(dst_family);
5112 return device_data->LogError(
5113 queue_state->queue, val_code,
5114 "%s: Barrier submitted to queue with family index %u, using %s %s created with sharingMode %s, has "
5115 "srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
5116 "vkQueueSubmit", queue_family, val.GetTypeString(),
5117 device_data->report_data->FormatHandle(val.barrier_handle_).c_str(), val.GetModeString(), src_family,
5118 src_annotation, dst_family, dst_annotation, vu_summary[kSubmitQueueMustMatchSrcOrDst]);
5119 }
5120 return false;
5121 }
5122 // Logical helpers for semantic clarity
5123 inline bool KhrExternalMem() const { return mem_ext_; }
5124 inline bool IsValid(uint32_t queue_family) const { return (queue_family < limit_); }
5125 inline bool IsValidOrSpecial(uint32_t queue_family) const {
5126 return IsValid(queue_family) || (mem_ext_ && QueueFamilyIsExternal(queue_family));
5127 }
5128
5129 // Helpers for LogMsg
5130 const char *GetModeString() const { return string_VkSharingMode(sharing_mode_); }
5131
5132 // Descriptive text for the various types of queue family index
5133 const char *GetFamilyAnnotation(uint32_t family) const {
5134 const char *external = " (VK_QUEUE_FAMILY_EXTERNAL)";
5135 const char *foreign = " (VK_QUEUE_FAMILY_FOREIGN_EXT)";
5136 const char *ignored = " (VK_QUEUE_FAMILY_IGNORED)";
5137 const char *valid = " (VALID)";
5138 const char *invalid = " (INVALID)";
5139 switch (family) {
5140 case VK_QUEUE_FAMILY_EXTERNAL:
5141 return external;
5142 case VK_QUEUE_FAMILY_FOREIGN_EXT:
5143 return foreign;
5144 case VK_QUEUE_FAMILY_IGNORED:
5145 return ignored;
5146 default:
5147 if (IsValid(family)) {
5148 return valid;
5149 }
5150 return invalid;
5151 };
5152 }
5153 const char *GetTypeString() const { return object_string[barrier_handle_.type]; }
5154 VkSharingMode GetSharingMode() const { return sharing_mode_; }
5155
5156 protected:
5157 const ValidationStateTracker *device_data_;
5158 const char *const func_name_;
5159 const VkCommandBuffer command_buffer_;
5160 const VulkanTypedHandle barrier_handle_;
5161 const VkSharingMode sharing_mode_;
5162 const std::string *val_codes_;
5163 const uint32_t limit_;
5164 const bool mem_ext_;
5165};
5166
5167bool Validate(const CoreChecks *device_data, const char *func_name, const CMD_BUFFER_STATE *cb_state, const ValidatorState &val,
5168 const uint32_t src_queue_family, const uint32_t dst_queue_family) {
5169 bool skip = false;
5170
5171 const bool mode_concurrent = val.GetSharingMode() == VK_SHARING_MODE_CONCURRENT;
5172 const bool src_ignored = QueueFamilyIsIgnored(src_queue_family);
5173 const bool dst_ignored = QueueFamilyIsIgnored(dst_queue_family);
5174 if (val.KhrExternalMem()) {
5175 if (mode_concurrent) {
5176 if (!(src_ignored || dst_ignored)) {
5177 skip |= val.LogMsg(kSrcOrDstMustBeIgnore, src_queue_family, dst_queue_family);
5178 }
5179 if ((src_ignored && !(dst_ignored || QueueFamilyIsExternal(dst_queue_family))) ||
5180 (dst_ignored && !(src_ignored || QueueFamilyIsExternal(src_queue_family)))) {
5181 skip |= val.LogMsg(kSpecialOrIgnoreOnly, src_queue_family, dst_queue_family);
5182 }
5183 } else {
5184 // VK_SHARING_MODE_EXCLUSIVE
5185 if (src_queue_family != dst_queue_family) {
5186 if (!val.IsValidOrSpecial(dst_queue_family)) {
5187 skip |= val.LogMsg(kSrcAndDstValidOrSpecial, dst_queue_family, "dstQueueFamilyIndex");
5188 }
5189 if (!val.IsValidOrSpecial(src_queue_family)) {
5190 skip |= val.LogMsg(kSrcAndDstValidOrSpecial, src_queue_family, "srcQueueFamilyIndex");
5191 }
5192 }
5193 }
5194 } else {
5195 // No memory extension
5196 if (mode_concurrent) {
5197 if (!src_ignored || !dst_ignored) {
5198 skip |= val.LogMsg(kSrcAndDestMustBeIgnore, src_queue_family, dst_queue_family);
5199 }
5200 } else {
5201 // VK_SHARING_MODE_EXCLUSIVE
5202 if ((src_queue_family != dst_queue_family) && !(val.IsValid(src_queue_family) && val.IsValid(dst_queue_family))) {
5203 skip |= val.LogMsg(kSrcAndDstBothValid, src_queue_family, dst_queue_family);
5204 }
5205 }
5206 }
5207 return skip;
5208}
5209} // namespace barrier_queue_families
5210
5211bool CoreChecks::ValidateConcurrentBarrierAtSubmit(const ValidationStateTracker *state_data, const QUEUE_STATE *queue_state,
5212 const char *func_name, const CMD_BUFFER_STATE *cb_state,
5213 const VulkanTypedHandle &typed_handle, uint32_t src_queue_family,
5214 uint32_t dst_queue_family) {
5215 using barrier_queue_families::ValidatorState;
5216 ValidatorState val(state_data, func_name, cb_state, typed_handle, VK_SHARING_MODE_CONCURRENT);
5217 return ValidatorState::ValidateAtQueueSubmit(queue_state, state_data, src_queue_family, dst_queue_family, val);
5218}
5219
5220// Type specific wrapper for image barriers
5221bool CoreChecks::ValidateBarrierQueueFamilies(const char *func_name, const CMD_BUFFER_STATE *cb_state,
5222 const VkImageMemoryBarrier &barrier, const IMAGE_STATE *state_data) const {
5223 // State data is required
5224 if (!state_data) {
5225 return false;
5226 }
5227
5228 // Create the validator state from the image state
5229 barrier_queue_families::ValidatorState val(this, func_name, cb_state, VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage),
5230 state_data->createInfo.sharingMode);
5231 const uint32_t src_queue_family = barrier.srcQueueFamilyIndex;
5232 const uint32_t dst_queue_family = barrier.dstQueueFamilyIndex;
5233 return barrier_queue_families::Validate(this, func_name, cb_state, val, src_queue_family, dst_queue_family);
5234}
5235
5236// Type specific wrapper for buffer barriers
5237bool CoreChecks::ValidateBarrierQueueFamilies(const char *func_name, const CMD_BUFFER_STATE *cb_state,
5238 const VkBufferMemoryBarrier &barrier, const BUFFER_STATE *state_data) const {
5239 // State data is required
5240 if (!state_data) {
5241 return false;
5242 }
5243
5244 // Create the validator state from the buffer state
5245 barrier_queue_families::ValidatorState val(
5246 this, func_name, cb_state, VulkanTypedHandle(barrier.buffer, kVulkanObjectTypeBuffer), state_data->createInfo.sharingMode);
5247 const uint32_t src_queue_family = barrier.srcQueueFamilyIndex;
5248 const uint32_t dst_queue_family = barrier.dstQueueFamilyIndex;
5249 return barrier_queue_families::Validate(this, func_name, cb_state, val, src_queue_family, dst_queue_family);
5250}
5251
Spencer Fricke6bba8c72020-04-06 07:41:21 -07005252bool CoreChecks::ValidateImageViewFormatFeatures(const IMAGE_STATE *image_state, const VkFormat view_format,
5253 const VkImageUsageFlags image_usage) const {
5254 // Pass in image_usage here instead of extracting it from image_state in case there's a chained VkImageViewUsageCreateInfo
5255 bool skip = false;
5256
5257 VkFormatFeatureFlags tiling_features = VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM;
5258 const VkImageTiling image_tiling = image_state->createInfo.tiling;
5259
5260 if (image_state->has_ahb_format == true) {
5261 // AHB image view and image share same feature sets
5262 tiling_features = image_state->format_features;
5263 } else if (image_tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
5264 // Parameter validation should catch if this is used without VK_EXT_image_drm_format_modifier
5265 assert(device_extensions.vk_ext_image_drm_format_modifier);
5266 VkImageDrmFormatModifierPropertiesEXT drm_format_properties = {VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
5267 nullptr};
5268 DispatchGetImageDrmFormatModifierPropertiesEXT(device, image_state->image, &drm_format_properties);
5269
5270 VkFormatProperties2 format_properties_2 = {VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, nullptr};
5271 VkDrmFormatModifierPropertiesListEXT drm_properties_list = {VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
5272 nullptr};
5273 format_properties_2.pNext = (void *)&drm_properties_list;
5274 DispatchGetPhysicalDeviceFormatProperties2(physical_device, view_format, &format_properties_2);
5275
5276 for (uint32_t i = 0; i < drm_properties_list.drmFormatModifierCount; i++) {
5277 if ((drm_properties_list.pDrmFormatModifierProperties[i].drmFormatModifier & drm_format_properties.drmFormatModifier) !=
5278 0) {
5279 tiling_features |= drm_properties_list.pDrmFormatModifierProperties[i].drmFormatModifierTilingFeatures;
5280 }
5281 }
5282 } else {
5283 VkFormatProperties format_properties = GetPDFormatProperties(view_format);
5284 tiling_features = (image_tiling == VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
5285 : format_properties.optimalTilingFeatures;
5286 }
5287
5288 if (tiling_features == 0) {
5289 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-None-02273",
5290 "vkCreateImageView(): pCreateInfo->format %s with tiling %s has no supported format features on this "
5291 "physical device.",
5292 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5293 } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
5294 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-usage-02274",
5295 "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5296 "VK_IMAGE_USAGE_SAMPLED_BIT.",
5297 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5298 } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
5299 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-usage-02275",
5300 "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5301 "VK_IMAGE_USAGE_STORAGE_BIT.",
5302 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5303 } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
5304 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-usage-02276",
5305 "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5306 "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.",
5307 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5308 } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
5309 !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
5310 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-usage-02277",
5311 "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5312 "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT.",
5313 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5314 } else if ((image_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
5315 !(tiling_features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))) {
5316 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-usage-02652",
5317 "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5318 "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT or VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.",
5319 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
Tobias Hector6663c9b2020-11-05 10:18:02 +00005320 } else if ((image_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) &&
5321 !(tiling_features & VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR)) {
5322 if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
5323 skip |= LogError(image_state->image, "VUID-VkImageViewCreateInfo-usage-04550",
5324 "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5325 "VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR.",
5326 string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5327 }
Spencer Fricke6bba8c72020-04-06 07:41:21 -07005328 }
5329
5330 return skip;
5331}
5332
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07005333bool CoreChecks::PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
Jeff Bolz5c801d12019-10-09 10:38:45 -05005334 const VkAllocationCallbacks *pAllocator, VkImageView *pView) const {
Mark Lobodzinski602de982017-02-09 11:01:33 -07005335 bool skip = false;
Jeff Bolz46c0ea02019-10-09 13:06:29 -05005336 const IMAGE_STATE *image_state = GetImageState(pCreateInfo->image);
Mark Lobodzinski602de982017-02-09 11:01:33 -07005337 if (image_state) {
ByumjinConffx1c74abf2019-08-14 15:16:40 -07005338 skip |=
5339 ValidateImageUsageFlags(image_state,
5340 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
5341 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
sfricke-samsungbb971942020-09-10 22:11:56 -07005342 VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV |
5343 VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
5344 false, "VUID-VkImageViewCreateInfo-image-04441", "vkCreateImageView()",
ByumjinConffx1c74abf2019-08-14 15:16:40 -07005345 "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT|"
sfricke-samsungbb971942020-09-10 22:11:56 -07005346 "TRANSIENT_ATTACHMENT|SHADING_RATE_IMAGE|FRAGMENT_DENSITY_MAP]_BIT");
Mark Lobodzinski602de982017-02-09 11:01:33 -07005347 // If this isn't a sparse image, it needs to have memory backing it at CreateImageView time
Mark Lobodzinski0ebe9712019-03-07 13:39:07 -07005348 skip |= ValidateMemoryIsBoundToImage(image_state, "vkCreateImageView()", "VUID-VkImageViewCreateInfo-image-01020");
Mark Lobodzinski602de982017-02-09 11:01:33 -07005349 // Checks imported from image layer
Petr Krausffa94af2017-08-08 21:46:02 +02005350 skip |= ValidateCreateImageViewSubresourceRange(
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005351 image_state, pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D || pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY,
Mark Lobodzinskic8c8d0d2019-01-10 12:55:26 -07005352 pCreateInfo->subresourceRange);
Mark Lobodzinski602de982017-02-09 11:01:33 -07005353
5354 VkImageCreateFlags image_flags = image_state->createInfo.flags;
5355 VkFormat image_format = image_state->createInfo.format;
Jeremy Kniagercef491c2017-07-18 11:10:28 -06005356 VkImageUsageFlags image_usage = image_state->createInfo.usage;
Mark Lobodzinskic8c8d0d2019-01-10 12:55:26 -07005357 VkFormat view_format = pCreateInfo->format;
5358 VkImageAspectFlags aspect_mask = pCreateInfo->subresourceRange.aspectMask;
Jeremy Kniager846ab732017-07-10 13:12:04 -06005359 VkImageType image_type = image_state->createInfo.imageType;
Mark Lobodzinskic8c8d0d2019-01-10 12:55:26 -07005360 VkImageViewType view_type = pCreateInfo->viewType;
Mark Lobodzinski602de982017-02-09 11:01:33 -07005361
Dave Houltonbd2e2622018-04-10 16:41:14 -06005362 // If there's a chained VkImageViewUsageCreateInfo struct, modify image_usage to match
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07005363 auto chained_ivuci_struct = LvlFindInChain<VkImageViewUsageCreateInfo>(pCreateInfo->pNext);
Dave Houltonbd2e2622018-04-10 16:41:14 -06005364 if (chained_ivuci_struct) {
Mark Lobodzinski8c193c02020-02-20 09:20:33 -07005365 if (device_extensions.vk_khr_maintenance2) {
Andrew Fobel3abeb992020-01-20 16:33:22 -05005366 if (!device_extensions.vk_ext_separate_stencil_usage) {
5367 if ((image_usage | chained_ivuci_struct->usage) != image_usage) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005368 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02661",
5369 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo, usage must not "
5370 "include any bits that were not set in VkImageCreateInfo::usage used to create image");
Andrew Fobel3abeb992020-01-20 16:33:22 -05005371 }
5372 } else {
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07005373 const auto image_stencil_struct = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_state->createInfo.pNext);
Andrew Fobel3abeb992020-01-20 16:33:22 -05005374 if (image_stencil_struct == nullptr) {
5375 if ((image_usage | chained_ivuci_struct->usage) != image_usage) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005376 skip |= LogError(
5377 pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02662",
Andrew Fobel3abeb992020-01-20 16:33:22 -05005378 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo and image was not created "
5379 "with a VkImageStencilUsageCreateInfo in pNext of vkImageCreateInfo, usage must not include "
5380 "any bits that were not set in VkImageCreateInfo::usage used to create image");
5381 }
5382 } else {
5383 if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) == VK_IMAGE_ASPECT_STENCIL_BIT &&
5384 (image_stencil_struct->stencilUsage | chained_ivuci_struct->usage) !=
5385 image_stencil_struct->stencilUsage) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005386 skip |= LogError(
5387 pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02663",
Andrew Fobel3abeb992020-01-20 16:33:22 -05005388 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo, image was created with a "
5389 "VkImageStencilUsageCreateInfo in pNext of vkImageCreateInfo, and subResourceRange.aspectMask "
5390 "includes VK_IMAGE_ASPECT_STENCIL_BIT, VkImageViewUsageCreateInfo::usage must not include any "
5391 "bits that were not set in VkImageStencilUsageCreateInfo::stencilUsage used to create image");
5392 }
5393 if ((aspect_mask & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
5394 (image_usage | chained_ivuci_struct->usage) != image_usage) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005395 skip |= LogError(
5396 pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02664",
Andrew Fobel3abeb992020-01-20 16:33:22 -05005397 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo, image was created with a "
5398 "VkImageStencilUsageCreateInfo in pNext of vkImageCreateInfo, and subResourceRange.aspectMask "
5399 "includes bits other than VK_IMAGE_ASPECT_STENCIL_BIT, VkImageViewUsageCreateInfo::usage must not "
5400 "include any bits that were not set in VkImageCreateInfo::usage used to create image");
5401 }
5402 }
5403 }
5404 }
5405
Dave Houltonbd2e2622018-04-10 16:41:14 -06005406 image_usage = chained_ivuci_struct->usage;
5407 }
5408
Dave Houlton6f5f20a2018-05-04 12:37:44 -06005409 // Validate VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT state, if view/image formats differ
5410 if ((image_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && (image_format != view_format)) {
Dave Houltonc7988072018-04-16 11:46:56 -06005411 if (FormatIsMultiplane(image_format)) {
Graeme Leese605ca512019-05-08 12:59:44 +01005412 VkFormat compat_format = FindMultiplaneCompatibleFormat(image_format, aspect_mask);
Dave Houltonc7988072018-04-16 11:46:56 -06005413 if (view_format != compat_format) {
Graeme Leese605ca512019-05-08 12:59:44 +01005414 // View format must match the multiplane compatible format
Lenny Komowb79f04a2017-09-18 17:07:00 -06005415 std::stringstream ss;
5416 ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
Graeme Leesed8572aa2019-05-15 14:58:19 +01005417 << " is not compatible with plane " << GetPlaneIndex(aspect_mask) << " of underlying image format "
Dave Houltonc7988072018-04-16 11:46:56 -06005418 << string_VkFormat(image_format) << ", must be " << string_VkFormat(compat_format) << ".";
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005419 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01586", "%s", ss.str().c_str());
Dave Houltonc7988072018-04-16 11:46:56 -06005420 }
5421 } else {
Mike Schuchardt2df08912020-12-15 16:28:09 -08005422 if (!(image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT)) {
Dave Houltonc7988072018-04-16 11:46:56 -06005423 // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
5424 if (FormatCompatibilityClass(image_format) != FormatCompatibilityClass(view_format)) {
sfricke-samsung2ff8b6a2020-03-09 21:54:35 -07005425 const char *error_vuid;
5426 if ((!device_extensions.vk_khr_maintenance2) && (!device_extensions.vk_khr_sampler_ycbcr_conversion)) {
5427 error_vuid = "VUID-VkImageViewCreateInfo-image-01018";
5428 } else if ((device_extensions.vk_khr_maintenance2) &&
5429 (!device_extensions.vk_khr_sampler_ycbcr_conversion)) {
5430 error_vuid = "VUID-VkImageViewCreateInfo-image-01759";
5431 } else if ((!device_extensions.vk_khr_maintenance2) &&
5432 (device_extensions.vk_khr_sampler_ycbcr_conversion)) {
5433 error_vuid = "VUID-VkImageViewCreateInfo-image-01760";
5434 } else {
5435 // both enabled
5436 error_vuid = "VUID-VkImageViewCreateInfo-image-01761";
5437 }
Dave Houltonc7988072018-04-16 11:46:56 -06005438 std::stringstream ss;
5439 ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
locke-lunarg9edc2812019-06-17 23:18:52 -06005440 << " is not in the same format compatibility class as "
5441 << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
Dave Houltonc7988072018-04-16 11:46:56 -06005442 << ". Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
5443 << "can support ImageViews with differing formats but they must be in the same compatibility class.";
sfricke-samsung2ff8b6a2020-03-09 21:54:35 -07005444 skip |= LogError(pCreateInfo->image, error_vuid, "%s", ss.str().c_str());
Dave Houltonc7988072018-04-16 11:46:56 -06005445 }
Lenny Komowb79f04a2017-09-18 17:07:00 -06005446 }
Mark Lobodzinski602de982017-02-09 11:01:33 -07005447 }
5448 } else {
5449 // Format MUST be IDENTICAL to the format the image was created with
Spencer Frickeff160582020-03-16 17:28:14 -07005450 // Unless it is a multi-planar color bit aspect
5451 if ((image_format != view_format) &&
5452 ((FormatIsMultiplane(image_format) == false) || (aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT))) {
5453 const char *vuid = (device_extensions.vk_khr_sampler_ycbcr_conversion) ? "VUID-VkImageViewCreateInfo-image-01762"
5454 : "VUID-VkImageViewCreateInfo-image-01019";
Mark Lobodzinski602de982017-02-09 11:01:33 -07005455 std::stringstream ss;
locke-lunarg9edc2812019-06-17 23:18:52 -06005456 ss << "vkCreateImageView() format " << string_VkFormat(view_format) << " differs from "
Lockee9aeebf2019-03-03 23:50:08 -07005457 << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
Mark Lobodzinski602de982017-02-09 11:01:33 -07005458 << ". Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
Spencer Frickeff160582020-03-16 17:28:14 -07005459 skip |= LogError(pCreateInfo->image, vuid, "%s", ss.str().c_str());
Mark Lobodzinski602de982017-02-09 11:01:33 -07005460 }
5461 }
5462
5463 // Validate correct image aspect bits for desired formats and format consistency
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005464 skip |= ValidateImageAspectMask(image_state->image, image_format, aspect_mask, "vkCreateImageView()");
Jeremy Kniager846ab732017-07-10 13:12:04 -06005465
5466 switch (image_type) {
5467 case VK_IMAGE_TYPE_1D:
5468 if (view_type != VK_IMAGE_VIEW_TYPE_1D && view_type != VK_IMAGE_VIEW_TYPE_1D_ARRAY) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005469 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5470 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5471 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005472 }
5473 break;
5474 case VK_IMAGE_TYPE_2D:
5475 if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
5476 if ((view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) &&
5477 !(image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005478 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01003",
5479 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5480 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005481 } else if (view_type != VK_IMAGE_VIEW_TYPE_CUBE && view_type != VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005482 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5483 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5484 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005485 }
5486 }
5487 break;
5488 case VK_IMAGE_TYPE_3D:
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06005489 if (device_extensions.vk_khr_maintenance1) {
Jeremy Kniager846ab732017-07-10 13:12:04 -06005490 if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
5491 if ((view_type == VK_IMAGE_VIEW_TYPE_2D || view_type == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08005492 if (!(image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)) {
Mark Lobodzinski487a0d12018-03-30 10:09:03 -06005493 skip |=
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005494 LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01005",
5495 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5496 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005497 } else if ((image_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT |
5498 VK_IMAGE_CREATE_SPARSE_ALIASED_BIT))) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005499 skip |= LogError(
5500 pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5501 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s "
5502 "when the VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or "
5503 "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags are enabled.",
5504 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005505 }
5506 } else {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005507 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5508 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5509 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005510 }
5511 }
5512 } else {
5513 if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005514 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5515 "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5516 string_VkImageViewType(view_type), string_VkImageType(image_type));
Jeremy Kniager846ab732017-07-10 13:12:04 -06005517 }
5518 }
5519 break;
5520 default:
5521 break;
5522 }
Jeremy Kniagercef491c2017-07-18 11:10:28 -06005523
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06005524 // External format checks needed when VK_ANDROID_external_memory_android_hardware_buffer enabled
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06005525 if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
Mark Lobodzinskie9b99792019-03-07 16:34:29 -07005526 skip |= ValidateCreateImageViewANDROID(pCreateInfo);
Jeremy Kniagercef491c2017-07-18 11:10:28 -06005527 }
5528
Spencer Fricke6bba8c72020-04-06 07:41:21 -07005529 skip |= ValidateImageViewFormatFeatures(image_state, view_format, image_usage);
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06005530
Tobias Hector6663c9b2020-11-05 10:18:02 +00005531 if (enabled_features.shading_rate_image.shadingRateImage) {
5532 if (image_usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) {
5533 if (view_format != VK_FORMAT_R8_UINT) {
5534 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-02087",
5535 "vkCreateImageView() If image was created with usage containing "
5536 "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, format must be VK_FORMAT_R8_UINT.");
5537 }
Jeff Bolz9af91c52018-09-01 21:53:57 -05005538 }
Tobias Hector6663c9b2020-11-05 10:18:02 +00005539 }
5540
5541 if (enabled_features.shading_rate_image.shadingRateImage ||
5542 enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
5543 if (image_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) {
5544 if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
5545 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-02086",
5546 "vkCreateImageView() If image was created with usage containing "
5547 "VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, viewType must be "
5548 "VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
5549 }
Jeff Bolz9af91c52018-09-01 21:53:57 -05005550 }
5551 }
Jeff Bolz99e3f632020-03-24 22:59:22 -05005552
Tobias Hector6663c9b2020-11-05 10:18:02 +00005553 if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate &&
5554 !phys_dev_ext_props.fragment_shading_rate_props.layeredShadingRateAttachments &&
5555 image_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR &&
5556 pCreateInfo->subresourceRange.layerCount != 1) {
5557 skip |= LogError(device, "VUID-VkImageViewCreateInfo-usage-04551",
5558 "vkCreateImageView(): subresourceRange.layerCount is %u for a shading rate attachment image view.",
5559 pCreateInfo->subresourceRange.layerCount);
5560 }
5561
Jeff Bolz99e3f632020-03-24 22:59:22 -05005562 if (pCreateInfo->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS) {
5563 if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_CUBE &&
5564 image_state->createInfo.arrayLayers - pCreateInfo->subresourceRange.baseArrayLayer != 6) {
5565 skip |= LogError(device, "VUID-VkImageViewCreateInfo-viewType-02962",
5566 "vkCreateImageView(): subresourceRange.layerCount VK_REMAINING_ARRAY_LAYERS=(%d) must be 6",
5567 image_state->createInfo.arrayLayers - pCreateInfo->subresourceRange.baseArrayLayer);
5568 }
5569 if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY &&
5570 ((image_state->createInfo.arrayLayers - pCreateInfo->subresourceRange.baseArrayLayer) % 6) != 0) {
5571 skip |= LogError(
5572 device, "VUID-VkImageViewCreateInfo-viewType-02963",
5573 "vkCreateImageView(): subresourceRange.layerCount VK_REMAINING_ARRAY_LAYERS=(%d) must be a multiple of 6",
5574 image_state->createInfo.arrayLayers - pCreateInfo->subresourceRange.baseArrayLayer);
5575 }
5576 }
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02005577
5578 if (image_usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) {
5579 if (pCreateInfo->subresourceRange.levelCount != 1) {
Shannon McPhersonafe55122020-05-25 16:20:19 -06005580 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-02571",
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02005581 "vkCreateImageView(): If image was created with usage containing "
5582 "VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, subresourceRange.levelCount (%d) must: be 1",
5583 pCreateInfo->subresourceRange.levelCount);
5584 }
5585 }
5586 if (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT) {
5587 if (!enabled_features.fragment_density_map_features.fragmentDensityMapDynamic) {
Shannon McPhersonafe55122020-05-25 16:20:19 -06005588 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-02572",
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02005589 "vkCreateImageView(): If the fragmentDensityMapDynamic feature is not enabled, "
5590 "flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT");
5591 }
5592 } else {
5593 if (image_usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) {
5594 if (image_flags & (VK_IMAGE_CREATE_PROTECTED_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
5595 VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT)) {
Shannon McPherson8d0d1f92020-07-06 11:58:21 -06005596 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-04116",
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02005597 "vkCreateImageView(): If image was created with usage containing "
5598 "VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT flags must not contain any of "
5599 "VK_IMAGE_CREATE_PROTECTED_BIT, VK_IMAGE_CREATE_SPARSE_BINDING_BIT, "
5600 "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or VK_IMAGE_CREATE_SPARSE_ALIASED_BIT");
5601 }
5602 }
5603 }
sfricke-samsung0c4a06f2020-06-27 01:24:32 -07005604
janharaldfredriksen-arm36e17572020-07-07 13:59:28 +02005605 if (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT) {
5606 if (!enabled_features.fragment_density_map2_features.fragmentDensityMapDeferred) {
5607 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-03567",
5608 "vkCreateImageView(): If the fragmentDensityMapDeferred feature is not enabled, "
5609 "flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT");
5610 }
5611 if (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT) {
5612 skip |=
5613 LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-03568",
5614 "vkCreateImageView(): If flags contains VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT, "
5615 "flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT");
5616 }
5617 }
5618 if (device_extensions.vk_ext_fragment_density_map_2) {
5619 if ((image_flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) && (image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) &&
5620 (pCreateInfo->subresourceRange.layerCount >
5621 phys_dev_ext_props.fragment_density_map2_props.maxSubsampledArrayLayers)) {
5622 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-03569",
5623 "vkCreateImageView(): If image was created with flags containing "
5624 "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT and usage containing VK_IMAGE_USAGE_SAMPLED_BIT "
5625 "subresourceRange.layerCount (%d) must: be less than or equal to maxSubsampledArrayLayers (%d)",
5626 pCreateInfo->subresourceRange.layerCount,
5627 phys_dev_ext_props.fragment_density_map2_props.maxSubsampledArrayLayers);
5628 }
5629 }
5630
Mark Lobodzinski1f887d32020-12-30 15:31:33 -07005631 auto astc_decode_mode = LvlFindInChain<VkImageViewASTCDecodeModeEXT>(pCreateInfo->pNext);
sfricke-samsung0c4a06f2020-06-27 01:24:32 -07005632 if ((device_extensions.vk_ext_astc_decode_mode) && (astc_decode_mode != nullptr)) {
5633 if ((enabled_features.astc_decode_features.decodeModeSharedExponent == VK_FALSE) &&
5634 (astc_decode_mode->decodeMode == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) {
5635 skip |= LogError(device, "VUID-VkImageViewASTCDecodeModeEXT-decodeMode-02231",
5636 "vkCreateImageView(): decodeModeSharedExponent is not enabled but "
5637 "VkImageViewASTCDecodeModeEXT::decodeMode is VK_FORMAT_E5B9G9R9_UFLOAT_PACK32.");
5638 }
5639 }
Nathaniel Cesariofe1d5832020-11-13 12:05:55 -07005640
5641 if (ExtEnabled::kNotEnabled != device_extensions.vk_khr_portability_subset) {
5642 // If swizzling is disabled, make sure it isn't used
5643 if ((VK_FALSE == enabled_features.portability_subset_features.imageViewFormatSwizzle) &&
5644 (pCreateInfo->components.r != VK_COMPONENT_SWIZZLE_IDENTITY ||
5645 pCreateInfo->components.g != VK_COMPONENT_SWIZZLE_IDENTITY ||
5646 pCreateInfo->components.b != VK_COMPONENT_SWIZZLE_IDENTITY ||
5647 pCreateInfo->components.a != VK_COMPONENT_SWIZZLE_IDENTITY)) {
5648 skip |= LogError(device, "VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465",
5649 "vkCreateImageView (portability error): swizzle is disabled for this device.");
5650 }
5651
5652 // Ensure ImageView's format has the same number of bits and components as Image's format if format reinterpretation is
5653 // disabled
5654 // TODO (ncesario): This is not correct for some cases (e.g., VK_FORMAT_B10G11R11_UFLOAT_PACK32 and
5655 // VK_FORMAT_E5B9G9R9_UFLOAT_PACK32), but requires additional information that should probably be generated from the
5656 // spec. See Github issue #2361.
5657 if ((VK_FALSE == enabled_features.portability_subset_features.imageViewFormatReinterpretation) &&
5658 ((FormatElementSize(pCreateInfo->format, VK_IMAGE_ASPECT_COLOR_BIT) !=
5659 FormatElementSize(image_state->createInfo.format, VK_IMAGE_ASPECT_COLOR_BIT)) ||
5660 (FormatChannelCount(pCreateInfo->format) != FormatChannelCount(image_state->createInfo.format)))) {
5661 skip |= LogError(device, "VUID-VkImageViewCreateInfo-imageViewFormatReinterpretation-04466",
5662 "vkCreateImageView (portability error): ImageView format must have"
5663 " the same number of components and bits per component as the Image's format");
5664 }
5665 }
Mark Lobodzinski602de982017-02-09 11:01:33 -07005666 }
5667 return skip;
5668}
5669
Jeff Leger178b1e52020-10-05 12:22:23 -04005670template <typename RegionType>
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005671bool CoreChecks::ValidateCmdCopyBufferBounds(const BUFFER_STATE *src_buffer_state, const BUFFER_STATE *dst_buffer_state,
Jeff Leger178b1e52020-10-05 12:22:23 -04005672 uint32_t regionCount, const RegionType *pRegions, CopyCommandVersion version) const {
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005673 bool skip = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04005674 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
5675 const char *func_name = is_2khr ? "vkCmdCopyBuffer2KHR()" : "vkCmdCopyBuffer()";
5676 const char *vuid;
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005677
5678 VkDeviceSize src_buffer_size = src_buffer_state->createInfo.size;
5679 VkDeviceSize dst_buffer_size = dst_buffer_state->createInfo.size;
5680 VkDeviceSize src_min = UINT64_MAX;
5681 VkDeviceSize src_max = 0;
5682 VkDeviceSize dst_min = UINT64_MAX;
5683 VkDeviceSize dst_max = 0;
5684
5685 for (uint32_t i = 0; i < regionCount; i++) {
5686 src_min = std::min(src_min, pRegions[i].srcOffset);
5687 src_max = std::max(src_max, (pRegions[i].srcOffset + pRegions[i].size));
5688 dst_min = std::min(dst_min, pRegions[i].dstOffset);
5689 dst_max = std::max(dst_max, (pRegions[i].dstOffset + pRegions[i].size));
5690
5691 // The srcOffset member of each element of pRegions must be less than the size of srcBuffer
5692 if (pRegions[i].srcOffset >= src_buffer_size) {
Jeff Leger178b1e52020-10-05 12:22:23 -04005693 vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-srcOffset-00113" : "VUID-vkCmdCopyBuffer-srcOffset-00113";
5694 skip |= LogError(src_buffer_state->buffer, vuid,
5695 "%s: pRegions[%d].srcOffset (%" PRIuLEAST64 ") is greater than pRegions[%d].size (%" PRIuLEAST64 ").",
5696 func_name, i, pRegions[i].srcOffset, i, pRegions[i].size);
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005697 }
5698
5699 // The dstOffset member of each element of pRegions must be less than the size of dstBuffer
5700 if (pRegions[i].dstOffset >= dst_buffer_size) {
Jeff Leger178b1e52020-10-05 12:22:23 -04005701 vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-dstOffset-00114" : "VUID-vkCmdCopyBuffer-dstOffset-00114";
5702 skip |= LogError(dst_buffer_state->buffer, vuid,
5703 "%s: pRegions[%d].dstOffset (%" PRIuLEAST64 ") is greater than pRegions[%d].size (%" PRIuLEAST64 ").",
5704 func_name, i, pRegions[i].dstOffset, i, pRegions[i].size);
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005705 }
5706
5707 // The size member of each element of pRegions must be less than or equal to the size of srcBuffer minus srcOffset
5708 if (pRegions[i].size > (src_buffer_size - pRegions[i].srcOffset)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04005709 vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-size-00115" : "VUID-vkCmdCopyBuffer-size-00115";
5710 skip |= LogError(src_buffer_state->buffer, vuid,
5711 "%s: pRegions[%d].size (%" PRIuLEAST64 ") is greater than the source buffer size (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005712 ") minus pRegions[%d].srcOffset (%" PRIuLEAST64 ").",
Jeff Leger178b1e52020-10-05 12:22:23 -04005713 func_name, i, pRegions[i].size, src_buffer_size, i, pRegions[i].srcOffset);
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005714 }
5715
5716 // The size member of each element of pRegions must be less than or equal to the size of dstBuffer minus dstOffset
5717 if (pRegions[i].size > (dst_buffer_size - pRegions[i].dstOffset)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04005718 vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-size-00116" : "VUID-vkCmdCopyBuffer-size-00116";
5719 skip |= LogError(dst_buffer_state->buffer, vuid,
5720 "%s: pRegions[%d].size (%" PRIuLEAST64 ") is greater than the destination buffer size (%" PRIuLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005721 ") minus pRegions[%d].dstOffset (%" PRIuLEAST64 ").",
Jeff Leger178b1e52020-10-05 12:22:23 -04005722 func_name, i, pRegions[i].size, dst_buffer_size, i, pRegions[i].dstOffset);
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005723 }
5724 }
5725
5726 // The union of the source regions, and the union of the destination regions, must not overlap in memory
5727 if (src_buffer_state->buffer == dst_buffer_state->buffer) {
5728 if (((src_min > dst_min) && (src_min < dst_max)) || ((src_max > dst_min) && (src_max < dst_max))) {
Jeff Leger178b1e52020-10-05 12:22:23 -04005729 vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-pRegions-00117" : "VUID-vkCmdCopyBuffer-pRegions-00117";
5730 skip |= LogError(src_buffer_state->buffer, vuid, "%s: Detected overlap between source and dest regions in memory.",
5731 func_name);
Mark Lobodzinski3438ab62019-09-02 14:19:40 -06005732 }
5733 }
5734
5735 return skip;
5736}
5737
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07005738bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
Jeff Bolz5c801d12019-10-09 10:38:45 -05005739 uint32_t regionCount, const VkBufferCopy *pRegions) const {
John Zulaufe3d1c8a2019-08-12 14:34:58 -06005740 const auto cb_node = GetCBState(commandBuffer);
5741 const auto src_buffer_state = GetBufferState(srcBuffer);
5742 const auto dst_buffer_state = GetBufferState(dstBuffer);
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07005743
Mark Lobodzinski680421d2017-02-09 13:06:56 -07005744 bool skip = false;
Mark Lobodzinski0ebe9712019-03-07 13:39:07 -07005745 skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-srcBuffer-00119");
5746 skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-dstBuffer-00121");
Mark Lobodzinski680421d2017-02-09 13:06:56 -07005747 // Validate that SRC & DST buffers have correct usage flags set
Dave Houltond8ed0212018-05-16 17:18:24 -06005748 skip |=
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07005749 ValidateBufferUsageFlags(src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, "VUID-vkCmdCopyBuffer-srcBuffer-00118",
5750 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
Dave Houltond8ed0212018-05-16 17:18:24 -06005751 skip |=
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07005752 ValidateBufferUsageFlags(dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdCopyBuffer-dstBuffer-00120",
5753 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07005754 skip |=
5755 ValidateCmdQueueFlags(cb_node, "vkCmdCopyBuffer()", VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
5756 "VUID-vkCmdCopyBuffer-commandBuffer-cmdpool");
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07005757 skip |= ValidateCmd(cb_node, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
5758 skip |= InsideRenderPass(cb_node, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-renderpass");
Jeff Leger178b1e52020-10-05 12:22:23 -04005759 skip |= ValidateCmdCopyBufferBounds(src_buffer_state, dst_buffer_state, regionCount, pRegions, COPY_COMMAND_VERSION_1);
sfricke-samsung022fa252020-07-24 03:26:16 -07005760 skip |= ValidateProtectedBuffer(cb_node, src_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-commandBuffer-01822");
5761 skip |= ValidateProtectedBuffer(cb_node, dst_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-commandBuffer-01823");
5762 skip |= ValidateUnprotectedBuffer(cb_node, dst_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-commandBuffer-01824");
Mark Lobodzinski680421d2017-02-09 13:06:56 -07005763 return skip;
5764}
Mark Lobodzinskiab9be282017-02-09 12:01:27 -07005765
Jeff Leger178b1e52020-10-05 12:22:23 -04005766bool CoreChecks::PreCallValidateCmdCopyBuffer2KHR(VkCommandBuffer commandBuffer,
5767 const VkCopyBufferInfo2KHR *pCopyBufferInfos) const {
5768 const auto cb_node = GetCBState(commandBuffer);
5769 const auto src_buffer_state = GetBufferState(pCopyBufferInfos->srcBuffer);
5770 const auto dst_buffer_state = GetBufferState(pCopyBufferInfos->dstBuffer);
5771
5772 bool skip = false;
5773 skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state, "vkCmdCopyBuffer2KHR()", "VUID-VkCopyBufferInfo2KHR-srcBuffer-00119");
5774 skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state, "vkCmdCopyBuffer2KHR()", "VUID-VkCopyBufferInfo2KHR-dstBuffer-00121");
5775 // Validate that SRC & DST buffers have correct usage flags set
5776 skip |= ValidateBufferUsageFlags(src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
5777 "VUID-VkCopyBufferInfo2KHR-srcBuffer-00118", "vkCmdCopyBuffer2KHR()",
5778 "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
5779 skip |= ValidateBufferUsageFlags(dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
5780 "VUID-VkCopyBufferInfo2KHR-dstBuffer-00120", "vkCmdCopyBuffer2KHR()",
5781 "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
5782 skip |= ValidateCmdQueueFlags(cb_node, "vkCmdCopyBuffer2KHR()",
5783 VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
5784 "VUID-vkCmdCopyBuffer2KHR-commandBuffer-cmdpool");
5785 skip |= ValidateCmd(cb_node, CMD_COPYBUFFER2KHR, "vkCmdCopyBuffer2KHR()");
5786 skip |= InsideRenderPass(cb_node, "vkCmdCopyBuffer2KHR()", "VUID-vkCmdCopyBuffer2KHR-renderpass");
5787 skip |= ValidateCmdCopyBufferBounds(src_buffer_state, dst_buffer_state, pCopyBufferInfos->regionCount,
5788 pCopyBufferInfos->pRegions, COPY_COMMAND_VERSION_2);
5789 skip |=
5790 ValidateProtectedBuffer(cb_node, src_buffer_state, "vkCmdCopyBuffer2KHR()", "VUID-vkCmdCopyBuffer2KHR-commandBuffer-01822");
5791 skip |=
5792 ValidateProtectedBuffer(cb_node, dst_buffer_state, "vkCmdCopyBuffer2KHR()", "VUID-vkCmdCopyBuffer2KHR-commandBuffer-01823");
5793 skip |= ValidateUnprotectedBuffer(cb_node, dst_buffer_state, "vkCmdCopyBuffer2KHR()",
5794 "VUID-vkCmdCopyBuffer2KHR-commandBuffer-01824");
5795 return skip;
5796}
5797
Jeff Bolz46c0ea02019-10-09 13:06:29 -05005798bool CoreChecks::ValidateIdleBuffer(VkBuffer buffer) const {
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005799 bool skip = false;
Mark Lobodzinski6ed74142019-03-06 11:35:39 -07005800 auto buffer_state = GetBufferState(buffer);
sfricke-samsung9c7d8552020-08-16 22:12:21 -07005801 if (buffer_state) {
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005802 if (buffer_state->in_use.load()) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005803 skip |= LogError(buffer, "VUID-vkDestroyBuffer-buffer-00922", "Cannot free %s that is in use by a command buffer.",
5804 report_data->FormatHandle(buffer).c_str());
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005805 }
5806 }
5807 return skip;
5808}
5809
Jeff Bolz5c801d12019-10-09 10:38:45 -05005810bool CoreChecks::PreCallValidateDestroyImageView(VkDevice device, VkImageView imageView,
5811 const VkAllocationCallbacks *pAllocator) const {
Jeff Bolz46c0ea02019-10-09 13:06:29 -05005812 const IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
John Zulauf4fea6622019-04-01 11:38:18 -06005813 const VulkanTypedHandle obj_struct(imageView, kVulkanObjectTypeImageView);
Mark Lobodzinskic8c8d0d2019-01-10 12:55:26 -07005814
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005815 bool skip = false;
Mark Lobodzinskic8c8d0d2019-01-10 12:55:26 -07005816 if (image_view_state) {
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005817 skip |=
5818 ValidateObjectNotInUse(image_view_state, obj_struct, "vkDestroyImageView", "VUID-vkDestroyImageView-imageView-01026");
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005819 }
5820 return skip;
5821}
5822
Jeff Bolz5c801d12019-10-09 10:38:45 -05005823bool CoreChecks::PreCallValidateDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) const {
Mark Lobodzinski6ed74142019-03-06 11:35:39 -07005824 auto buffer_state = GetBufferState(buffer);
Mark Lobodzinskidd995d22019-01-11 11:05:15 -07005825
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005826 bool skip = false;
Mark Lobodzinskidd995d22019-01-11 11:05:15 -07005827 if (buffer_state) {
Mark Lobodzinskif933db92019-03-09 12:58:03 -07005828 skip |= ValidateIdleBuffer(buffer);
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005829 }
5830 return skip;
5831}
5832
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07005833bool CoreChecks::PreCallValidateDestroyBufferView(VkDevice device, VkBufferView bufferView,
Jeff Bolz5c801d12019-10-09 10:38:45 -05005834 const VkAllocationCallbacks *pAllocator) const {
Mark Lobodzinski31aa9b02019-03-06 11:51:37 -07005835 auto buffer_view_state = GetBufferViewState(bufferView);
John Zulauf4fea6622019-04-01 11:38:18 -06005836 const VulkanTypedHandle obj_struct(bufferView, kVulkanObjectTypeBufferView);
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005837 bool skip = false;
Mark Lobodzinskidd995d22019-01-11 11:05:15 -07005838 if (buffer_view_state) {
Mark Lobodzinski9ddb7182019-03-08 17:31:09 -07005839 skip |= ValidateObjectNotInUse(buffer_view_state, obj_struct, "vkDestroyBufferView",
Dave Houltond8ed0212018-05-16 17:18:24 -06005840 "VUID-vkDestroyBufferView-bufferView-00936");
Mark Lobodzinski306441e2017-02-10 13:48:38 -07005841 }
5842 return skip;
5843}
5844
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07005845bool CoreChecks::PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
Jeff Bolz5c801d12019-10-09 10:38:45 -05005846 VkDeviceSize size, uint32_t data) const {
Mark Lobodzinskicefe42f2019-04-25 12:16:27 -06005847 auto cb_node = GetCBState(commandBuffer);
Mark Lobodzinski6ed74142019-03-06 11:35:39 -07005848 auto buffer_state = GetBufferState(dstBuffer);
Mark Lobodzinskidf0acbf2017-02-10 14:01:27 -07005849 bool skip = false;
Mark Lobodzinski0ebe9712019-03-07 13:39:07 -07005850 skip |= ValidateMemoryIsBoundToBuffer(buffer_state, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-dstBuffer-00031");
Mark Lobodzinskidaea5912019-03-07 14:47:09 -07005851 skip |=
5852 ValidateCmdQueueFlags(cb_node, "vkCmdFillBuffer()", VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
5853 "VUID-vkCmdFillBuffer-commandBuffer-cmdpool");
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07005854 skip |= ValidateCmd(cb_node, CMD_FILLBUFFER, "vkCmdFillBuffer()");
Mark Lobodzinskidf0acbf2017-02-10 14:01:27 -07005855 // Validate that DST buffer has correct usage flags set
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07005856 skip |= ValidateBufferUsageFlags(buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdFillBuffer-dstBuffer-00029",
5857 "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
Mark Lobodzinskifae179e2019-03-08 16:47:08 -07005858 skip |= InsideRenderPass(cb_node, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-renderpass");
Mark Lobodzinski693fbfd2019-12-03 16:06:30 -07005859
sfricke-samsung022fa252020-07-24 03:26:16 -07005860 skip |= ValidateProtectedBuffer(cb_node, buffer_state, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-commandBuffer-01811");
5861 skip |= ValidateUnprotectedBuffer(cb_node, buffer_state, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-commandBuffer-01812");
5862
Mark Lobodzinski693fbfd2019-12-03 16:06:30 -07005863 if (dstOffset >= buffer_state->createInfo.size) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005864 skip |= LogError(dstBuffer, "VUID-vkCmdFillBuffer-dstOffset-00024",
5865 "vkCmdFillBuffer(): dstOffset (0x%" PRIxLEAST64
5866 ") is not less than destination buffer (%s) size (0x%" PRIxLEAST64 ").",
5867 dstOffset, report_data->FormatHandle(dstBuffer).c_str(), buffer_state->createInfo.size);
Mark Lobodzinski693fbfd2019-12-03 16:06:30 -07005868 }
5869
5870 if ((size != VK_WHOLE_SIZE) && (size > (buffer_state->createInfo.size - dstOffset))) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005871 skip |= LogError(dstBuffer, "VUID-vkCmdFillBuffer-size-00027",
5872 "vkCmdFillBuffer(): size (0x%" PRIxLEAST64 ") is greater than dstBuffer (%s) size (0x%" PRIxLEAST64
5873 ") minus dstOffset (0x%" PRIxLEAST64 ").",
5874 size, report_data->FormatHandle(dstBuffer).c_str(), buffer_state->createInfo.size, dstOffset);
Mark Lobodzinski693fbfd2019-12-03 16:06:30 -07005875 }
5876
Mark Lobodzinskidf0acbf2017-02-10 14:01:27 -07005877 return skip;
5878}
5879
Jeff Leger178b1e52020-10-05 12:22:23 -04005880template <typename BufferImageCopyRegionType>
sfricke-samsungd0659242020-08-18 22:38:43 -07005881bool CoreChecks::ValidateBufferImageCopyData(const CMD_BUFFER_STATE *cb_node, uint32_t regionCount,
Jeff Leger178b1e52020-10-05 12:22:23 -04005882 const BufferImageCopyRegionType *pRegions, const IMAGE_STATE *image_state,
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07005883 const char *function, CopyCommandVersion version, bool image_to_buffer) const {
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07005884 bool skip = false;
sfricke-samsung03f6ffd2020-10-21 01:12:08 -07005885 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
5886 const char *vuid;
Jeff Leger178b1e52020-10-05 12:22:23 -04005887
sfricke-samsung125d2b42020-05-28 06:32:43 -07005888 assert(image_state != nullptr);
5889 const VkFormat image_format = image_state->createInfo.format;
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07005890
5891 for (uint32_t i = 0; i < regionCount; i++) {
sfricke-samsung125d2b42020-05-28 06:32:43 -07005892 const VkImageAspectFlags region_aspect_mask = pRegions[i].imageSubresource.aspectMask;
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005893 if (image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
5894 if ((pRegions[i].imageOffset.y != 0) || (pRegions[i].imageExtent.height != 1)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07005895 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00199", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04005896 "%s: pRegion[%d] imageOffset.y is %d and imageExtent.height is %d. For 1D images these must be 0 "
5897 "and 1, respectively.",
5898 function, i, pRegions[i].imageOffset.y, pRegions[i].imageExtent.height);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07005899 }
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005900 }
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07005901
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005902 if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) || (image_state->createInfo.imageType == VK_IMAGE_TYPE_2D)) {
5903 if ((pRegions[i].imageOffset.z != 0) || (pRegions[i].imageExtent.depth != 1)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07005904 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00201", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04005905 "%s: pRegion[%d] imageOffset.z is %d and imageExtent.depth is %d. For 1D and 2D images these "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005906 "must be 0 and 1, respectively.",
5907 function, i, pRegions[i].imageOffset.z, pRegions[i].imageExtent.depth);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07005908 }
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005909 }
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07005910
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005911 if (image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
5912 if ((0 != pRegions[i].imageSubresource.baseArrayLayer) || (1 != pRegions[i].imageSubresource.layerCount)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07005913 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00213", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04005914 "%s: pRegion[%d] imageSubresource.baseArrayLayer is %d and imageSubresource.layerCount is %d. "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005915 "For 3D images these must be 0 and 1, respectively.",
5916 function, i, pRegions[i].imageSubresource.baseArrayLayer, pRegions[i].imageSubresource.layerCount);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005917 }
5918 }
5919
5920 // If the the calling command's VkImage parameter's format is not a depth/stencil format,
Dave Houltona585d132019-01-18 13:05:42 -07005921 // then bufferOffset must be a multiple of the calling command's VkImage parameter's element size
sfricke-samsung8feecc12021-01-23 03:28:38 -08005922 const uint32_t element_size = FormatElementSize(image_format, region_aspect_mask);
5923 const VkDeviceSize bufferOffset = pRegions[i].bufferOffset;
Locke497739c2019-03-08 11:50:47 -07005924
sfricke-samsung8feecc12021-01-23 03:28:38 -08005925 if (FormatIsDepthOrStencil(image_format)) {
5926 if (SafeModulo(bufferOffset, 4) != 0) {
5927 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("04053", image_to_buffer, is_2khr),
5928 "%s: pRegion[%d] bufferOffset 0x%" PRIxLEAST64
5929 " must be a multiple 4 if using a depth/stencil format (%s).",
5930 function, i, bufferOffset, string_VkFormat(image_format));
5931 }
5932 } else {
5933 // If not depth/stencil and not multi-plane
5934 if (!FormatIsMultiplane(image_format) && (SafeModulo(bufferOffset, element_size) != 0)) {
5935 vuid = (device_extensions.vk_khr_sampler_ycbcr_conversion)
5936 ? GetBufferImageCopyCommandVUID("01558", image_to_buffer, is_2khr)
5937 : GetBufferImageCopyCommandVUID("00193", image_to_buffer, is_2khr);
5938 skip |= LogError(image_state->image, vuid,
5939 "%s: pRegion[%d] bufferOffset 0x%" PRIxLEAST64
5940 " must be a multiple of this format's texel size (%" PRIu32 ").",
5941 function, i, bufferOffset, element_size);
5942 }
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005943 }
5944
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005945 // BufferRowLength must be 0, or greater than or equal to the width member of imageExtent
5946 if ((pRegions[i].bufferRowLength != 0) && (pRegions[i].bufferRowLength < pRegions[i].imageExtent.width)) {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07005947 vuid = (is_2khr) ? "VUID-VkBufferImageCopy2KHR-bufferRowLength-00195" : "VUID-VkBufferImageCopy-bufferRowLength-00195";
Mark Lobodzinski487a0d12018-03-30 10:09:03 -06005948 skip |=
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07005949 LogError(image_state->image, vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04005950 "%s: pRegion[%d] bufferRowLength (%d) must be zero or greater-than-or-equal-to imageExtent.width (%d).",
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005951 function, i, pRegions[i].bufferRowLength, pRegions[i].imageExtent.width);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005952 }
5953
5954 // BufferImageHeight must be 0, or greater than or equal to the height member of imageExtent
5955 if ((pRegions[i].bufferImageHeight != 0) && (pRegions[i].bufferImageHeight < pRegions[i].imageExtent.height)) {
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07005956 vuid =
5957 (is_2khr) ? "VUID-VkBufferImageCopy2KHR-bufferImageHeight-00196" : "VUID-VkBufferImageCopy-bufferImageHeight-00196";
Jeff Leger178b1e52020-10-05 12:22:23 -04005958 skip |=
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07005959 LogError(image_state->image, vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04005960 "%s: pRegion[%d] bufferImageHeight (%d) must be zero or greater-than-or-equal-to imageExtent.height (%d).",
5961 function, i, pRegions[i].bufferImageHeight, pRegions[i].imageExtent.height);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005962 }
5963
Mark Lobodzinskia8f6f5b2019-06-14 07:41:19 -06005964 // Calculate adjusted image extent, accounting for multiplane image factors
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005965 VkExtent3D adjusted_image_extent = GetImageSubresourceExtent(image_state, &pRegions[i].imageSubresource);
Mark Lobodzinskia8f6f5b2019-06-14 07:41:19 -06005966 // imageOffset.x and (imageExtent.width + imageOffset.x) must both be >= 0 and <= image subresource width
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005967 if ((pRegions[i].imageOffset.x < 0) || (pRegions[i].imageOffset.x > static_cast<int32_t>(adjusted_image_extent.width)) ||
Mark Lobodzinski72b1a222020-03-18 11:36:10 -06005968 ((pRegions[i].imageOffset.x + static_cast<int32_t>(pRegions[i].imageExtent.width)) >
5969 static_cast<int32_t>(adjusted_image_extent.width))) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07005970 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00197", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04005971 "%s: Both pRegion[%d] imageoffset.x (%d) and (imageExtent.width + imageOffset.x) (%d) must be >= "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005972 "zero or <= image subresource width (%d).",
5973 function, i, pRegions[i].imageOffset.x, (pRegions[i].imageOffset.x + pRegions[i].imageExtent.width),
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005974 adjusted_image_extent.width);
Mark Lobodzinskia8f6f5b2019-06-14 07:41:19 -06005975 }
5976
5977 // imageOffset.y and (imageExtent.height + imageOffset.y) must both be >= 0 and <= image subresource height
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005978 if ((pRegions[i].imageOffset.y < 0) || (pRegions[i].imageOffset.y > static_cast<int32_t>(adjusted_image_extent.height)) ||
Mark Lobodzinski72b1a222020-03-18 11:36:10 -06005979 ((pRegions[i].imageOffset.y + static_cast<int32_t>(pRegions[i].imageExtent.height)) >
5980 static_cast<int32_t>(adjusted_image_extent.height))) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07005981 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00198", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04005982 "%s: Both pRegion[%d] imageoffset.y (%d) and (imageExtent.height + imageOffset.y) (%d) must be >= "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005983 "zero or <= image subresource height (%d).",
5984 function, i, pRegions[i].imageOffset.y, (pRegions[i].imageOffset.y + pRegions[i].imageExtent.height),
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005985 adjusted_image_extent.height);
Mark Lobodzinskia8f6f5b2019-06-14 07:41:19 -06005986 }
5987
5988 // imageOffset.z and (imageExtent.depth + imageOffset.z) must both be >= 0 and <= image subresource depth
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005989 if ((pRegions[i].imageOffset.z < 0) || (pRegions[i].imageOffset.z > static_cast<int32_t>(adjusted_image_extent.depth)) ||
Mark Lobodzinski72b1a222020-03-18 11:36:10 -06005990 ((pRegions[i].imageOffset.z + static_cast<int32_t>(pRegions[i].imageExtent.depth)) >
5991 static_cast<int32_t>(adjusted_image_extent.depth))) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07005992 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00200", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04005993 "%s: Both pRegion[%d] imageoffset.z (%d) and (imageExtent.depth + imageOffset.z) (%d) must be >= "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07005994 "zero or <= image subresource depth (%d).",
5995 function, i, pRegions[i].imageOffset.z, (pRegions[i].imageOffset.z + pRegions[i].imageExtent.depth),
Mark Lobodzinski27c824b2020-03-18 11:26:59 -06005996 adjusted_image_extent.depth);
Mark Lobodzinskia8f6f5b2019-06-14 07:41:19 -06005997 }
5998
Dave Houlton9dae7ec2017-03-01 16:23:25 -07005999 // subresource aspectMask must have exactly 1 bit set
6000 const int num_bits = sizeof(VkFlags) * CHAR_BIT;
sfricke-samsung125d2b42020-05-28 06:32:43 -07006001 std::bitset<num_bits> aspect_mask_bits(region_aspect_mask);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006002 if (aspect_mask_bits.count() != 1) {
sfricke-samsung03f6ffd2020-10-21 01:12:08 -07006003 vuid = (is_2khr) ? "VUID-VkBufferImageCopy2KHR-aspectMask-00212" : "VUID-VkBufferImageCopy-aspectMask-00212";
6004 skip |= LogError(image_state->image, vuid,
Jeff Leger178b1e52020-10-05 12:22:23 -04006005 "%s: aspectMasks for imageSubresource in pRegion[%d] must have only a single bit set.", function, i);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006006 }
6007
6008 // image subresource aspect bit must match format
sfricke-samsung125d2b42020-05-28 06:32:43 -07006009 if (!VerifyAspectsPresent(region_aspect_mask, image_format)) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006010 skip |=
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006011 LogError(image_state->image, GetBufferImageCopyCommandVUID("00211", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006012 "%s: pRegion[%d] subresource aspectMask 0x%x specifies aspects that are not present in image format 0x%x.",
6013 function, i, region_aspect_mask, image_format);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006014 }
6015
6016 // Checks that apply only to compressed images
sfricke-samsung125d2b42020-05-28 06:32:43 -07006017 if (FormatIsCompressed(image_format) || FormatIsSinglePlane_422(image_format)) {
6018 auto block_size = FormatTexelBlockExtent(image_format);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006019
6020 // BufferRowLength must be a multiple of block width
Dave Houlton1d2022c2017-03-29 11:43:58 -06006021 if (SafeModulo(pRegions[i].bufferRowLength, block_size.width) != 0) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006022 skip |=
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006023 LogError(image_state->image, GetBufferImageCopyCommandVUID("00203", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006024 "%s: pRegion[%d] bufferRowLength (%d) must be a multiple of the compressed image's texel width (%d)..",
6025 function, i, pRegions[i].bufferRowLength, block_size.width);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006026 }
6027
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006028 // BufferRowHeight must be a multiple of block height
Dave Houlton1d2022c2017-03-29 11:43:58 -06006029 if (SafeModulo(pRegions[i].bufferImageHeight, block_size.height) != 0) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006030 skip |= LogError(
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006031 image_state->image, GetBufferImageCopyCommandVUID("00204", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006032 "%s: pRegion[%d] bufferImageHeight (%d) must be a multiple of the compressed image's texel height (%d)..",
Mark Lobodzinski487a0d12018-03-30 10:09:03 -06006033 function, i, pRegions[i].bufferImageHeight, block_size.height);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006034 }
6035
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006036 // image offsets must be multiples of block dimensions
Dave Houlton1d2022c2017-03-29 11:43:58 -06006037 if ((SafeModulo(pRegions[i].imageOffset.x, block_size.width) != 0) ||
6038 (SafeModulo(pRegions[i].imageOffset.y, block_size.height) != 0) ||
6039 (SafeModulo(pRegions[i].imageOffset.z, block_size.depth) != 0)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006040 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00205", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006041 "%s: pRegion[%d] imageOffset(x,y) (%d, %d) must be multiples of the compressed image's texel "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006042 "width & height (%d, %d)..",
6043 function, i, pRegions[i].imageOffset.x, pRegions[i].imageOffset.y, block_size.width,
6044 block_size.height);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006045 }
6046
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006047 // bufferOffset must be a multiple of block size (linear bytes)
sfricke-samsung125d2b42020-05-28 06:32:43 -07006048 uint32_t block_size_in_bytes = FormatElementSize(image_format);
sfricke-samsung8feecc12021-01-23 03:28:38 -08006049 if (SafeModulo(bufferOffset, block_size_in_bytes) != 0) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006050 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00206", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006051 "%s: pRegion[%d] bufferOffset (0x%" PRIxLEAST64
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006052 ") must be a multiple of the compressed image's texel block size (%" PRIu32 ")..",
sfricke-samsung8feecc12021-01-23 03:28:38 -08006053 function, i, bufferOffset, block_size_in_bytes);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006054 }
Dave Houlton67e9b532017-03-02 17:00:10 -07006055
6056 // imageExtent width must be a multiple of block width, or extent+offset width must equal subresource width
Dave Houlton75967fc2017-03-06 17:21:16 -07006057 VkExtent3D mip_extent = GetImageSubresourceExtent(image_state, &(pRegions[i].imageSubresource));
Dave Houlton1d2022c2017-03-29 11:43:58 -06006058 if ((SafeModulo(pRegions[i].imageExtent.width, block_size.width) != 0) &&
Dave Houlton75967fc2017-03-06 17:21:16 -07006059 (pRegions[i].imageExtent.width + pRegions[i].imageOffset.x != mip_extent.width)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006060 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00207", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006061 "%s: pRegion[%d] extent width (%d) must be a multiple of the compressed texture block width "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006062 "(%d), or when added to offset.x (%d) must equal the image subresource width (%d)..",
6063 function, i, pRegions[i].imageExtent.width, block_size.width, pRegions[i].imageOffset.x,
6064 mip_extent.width);
Dave Houlton67e9b532017-03-02 17:00:10 -07006065 }
6066
6067 // imageExtent height must be a multiple of block height, or extent+offset height must equal subresource height
Dave Houlton1d2022c2017-03-29 11:43:58 -06006068 if ((SafeModulo(pRegions[i].imageExtent.height, block_size.height) != 0) &&
Dave Houlton75967fc2017-03-06 17:21:16 -07006069 (pRegions[i].imageExtent.height + pRegions[i].imageOffset.y != mip_extent.height)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006070 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00208", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006071 "%s: pRegion[%d] extent height (%d) must be a multiple of the compressed texture block height "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006072 "(%d), or when added to offset.y (%d) must equal the image subresource height (%d)..",
6073 function, i, pRegions[i].imageExtent.height, block_size.height, pRegions[i].imageOffset.y,
6074 mip_extent.height);
Dave Houlton67e9b532017-03-02 17:00:10 -07006075 }
6076
6077 // imageExtent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
Dave Houlton1d2022c2017-03-29 11:43:58 -06006078 if ((SafeModulo(pRegions[i].imageExtent.depth, block_size.depth) != 0) &&
Dave Houlton75967fc2017-03-06 17:21:16 -07006079 (pRegions[i].imageExtent.depth + pRegions[i].imageOffset.z != mip_extent.depth)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006080 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("00209", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006081 "%s: pRegion[%d] extent width (%d) must be a multiple of the compressed texture block depth "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006082 "(%d), or when added to offset.z (%d) must equal the image subresource depth (%d)..",
6083 function, i, pRegions[i].imageExtent.depth, block_size.depth, pRegions[i].imageOffset.z,
6084 mip_extent.depth);
Dave Houlton67e9b532017-03-02 17:00:10 -07006085 }
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006086 }
sfricke-samsung552d5e12020-01-07 22:00:20 -08006087
6088 // Checks that apply only to multi-planar format images
sfricke-samsung125d2b42020-05-28 06:32:43 -07006089 if (FormatIsMultiplane(image_format)) {
sfricke-samsung552d5e12020-01-07 22:00:20 -08006090 // VK_IMAGE_ASPECT_PLANE_2_BIT valid only for image formats with three planes
sfricke-samsung125d2b42020-05-28 06:32:43 -07006091 if ((FormatPlaneCount(image_format) < 3) && (region_aspect_mask == VK_IMAGE_ASPECT_PLANE_2_BIT)) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006092 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("01560", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006093 "%s: pRegion[%d] subresource aspectMask cannot be VK_IMAGE_ASPECT_PLANE_2_BIT unless image "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006094 "format has three planes.",
6095 function, i);
sfricke-samsung552d5e12020-01-07 22:00:20 -08006096 }
6097
6098 // image subresource aspectMask must be VK_IMAGE_ASPECT_PLANE_*_BIT
sfricke-samsung125d2b42020-05-28 06:32:43 -07006099 if (0 ==
6100 (region_aspect_mask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT))) {
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006101 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("01560", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006102 "%s: pRegion[%d] subresource aspectMask for multi-plane image formats must have a "
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006103 "VK_IMAGE_ASPECT_PLANE_*_BIT when copying to or from.",
6104 function, i);
sfricke-samsung125d2b42020-05-28 06:32:43 -07006105 } else {
6106 // Know aspect mask is valid
6107 const VkFormat compatible_format = FindMultiplaneCompatibleFormat(image_format, region_aspect_mask);
6108 const uint32_t compatible_size = FormatElementSize(compatible_format);
sfricke-samsung8feecc12021-01-23 03:28:38 -08006109 if (SafeModulo(bufferOffset, compatible_size) != 0) {
sfricke-samsung125d2b42020-05-28 06:32:43 -07006110 skip |= LogError(
sfricke-samsung2e5b16c2020-10-31 22:14:15 -07006111 image_state->image, GetBufferImageCopyCommandVUID("01559", image_to_buffer, is_2khr),
Jeff Leger178b1e52020-10-05 12:22:23 -04006112 "%s: pRegion[%d]->bufferOffset is 0x%" PRIxLEAST64
sfricke-samsung125d2b42020-05-28 06:32:43 -07006113 " but must be a multiple of the multi-plane compatible format's texel size (%u) for plane %u (%s).",
sfricke-samsung8feecc12021-01-23 03:28:38 -08006114 function, i, bufferOffset, element_size, GetPlaneIndex(region_aspect_mask),
sfricke-samsung125d2b42020-05-28 06:32:43 -07006115 string_VkFormat(compatible_format));
6116 }
sfricke-samsung552d5e12020-01-07 22:00:20 -08006117 }
6118 }
sfricke-samsung8feecc12021-01-23 03:28:38 -08006119
6120 // TODO - Don't use ValidateCmdQueueFlags due to currently not having way to add more descriptive message
6121 const COMMAND_POOL_STATE *command_pool = cb_node->command_pool.get();
6122 assert(command_pool != nullptr);
6123 const uint32_t queue_family_index = command_pool->queueFamilyIndex;
6124 const VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[queue_family_index].queueFlags;
6125 if (((queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) == 0) && (SafeModulo(bufferOffset, 4) != 0)) {
6126 LogObjectList objlist(cb_node->commandBuffer);
6127 objlist.add(command_pool->commandPool);
6128 skip |= LogError(image_state->image, GetBufferImageCopyCommandVUID("04052", image_to_buffer, is_2khr),
6129 "%s: pRegion[%d] bufferOffset 0x%" PRIxLEAST64
6130 " must be a multiple 4 because the command buffer %s was allocated from the command pool %s "
6131 "which was created with queueFamilyIndex %u, which doesn't contain the VK_QUEUE_GRAPHICS_BIT or "
6132 "VK_QUEUE_COMPUTE_BIT flag.",
6133 function, i, bufferOffset, report_data->FormatHandle(cb_node->commandBuffer).c_str(),
6134 report_data->FormatHandle(command_pool->commandPool).c_str(), queue_family_index);
6135 }
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006136 }
6137
6138 return skip;
6139}
6140
Jeff Leger178b1e52020-10-05 12:22:23 -04006141template <typename BufferImageCopyRegionType>
6142bool CoreChecks::ValidateImageBounds(const IMAGE_STATE *image_state, const uint32_t regionCount,
6143 const BufferImageCopyRegionType *pRegions, const char *func_name, const char *msg_code) const {
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006144 bool skip = false;
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006145 const VkImageCreateInfo *image_info = &(image_state->createInfo);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006146
6147 for (uint32_t i = 0; i < regionCount; i++) {
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006148 VkExtent3D extent = pRegions[i].imageExtent;
6149 VkOffset3D offset = pRegions[i].imageOffset;
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006150
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006151 if (IsExtentSizeZero(&extent)) // Warn on zero area subresource
6152 {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006153 skip |= LogWarning(image_state->image, kVUID_Core_Image_ZeroAreaSubregion,
6154 "%s: pRegion[%d] imageExtent of {%1d, %1d, %1d} has zero area", func_name, i, extent.width,
6155 extent.height, extent.depth);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006156 }
6157
6158 VkExtent3D image_extent = GetImageSubresourceExtent(image_state, &(pRegions[i].imageSubresource));
6159
6160 // If we're using a compressed format, valid extent is rounded up to multiple of block size (per 18.1)
unknown948b6ba2019-09-19 17:32:54 -06006161 if (FormatIsCompressed(image_info->format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
Dave Houltona585d132019-01-18 13:05:42 -07006162 auto block_extent = FormatTexelBlockExtent(image_info->format);
Dave Houlton9dae7ec2017-03-01 16:23:25 -07006163 if (image_extent.width % block_extent.width) {
6164 image_extent.width += (block_extent.width - (image_extent.width % block_extent.width));
6165 }
6166 if (image_extent.height % block_extent.height) {
6167 image_extent.height += (block_extent.height - (image_extent.height % block_extent.height));
6168 }
6169 if (image_extent.depth % block_extent.depth) {
6170 image_extent.depth += (block_extent.depth - (image_extent.depth % block_extent.depth));
6171 }
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006172 }
6173
Dave Houltonfc1a4052017-04-27 14:32:45 -06006174 if (0 != ExceedsBounds(&offset, &extent, &image_extent)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006175 skip |= LogError(image_state->image, msg_code, "%s: pRegion[%d] exceeds image bounds..", func_name, i);
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006176 }
6177 }
6178
6179 return skip;
6180}
6181
Jeff Leger178b1e52020-10-05 12:22:23 -04006182template <typename BufferImageCopyRegionType>
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006183bool CoreChecks::ValidateBufferBounds(const IMAGE_STATE *image_state, const BUFFER_STATE *buff_state, uint32_t regionCount,
Jeff Leger178b1e52020-10-05 12:22:23 -04006184 const BufferImageCopyRegionType *pRegions, const char *func_name,
6185 const char *msg_code) const {
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006186 bool skip = false;
6187
6188 VkDeviceSize buffer_size = buff_state->createInfo.size;
6189
6190 for (uint32_t i = 0; i < regionCount; i++) {
locke-lunarga19c71d2020-03-02 18:17:04 -07006191 VkDeviceSize max_buffer_offset =
6192 GetBufferSizeFromCopyImage(pRegions[i], image_state->createInfo.format) + pRegions[i].bufferOffset;
6193 if (buffer_size < max_buffer_offset) {
6194 skip |=
6195 LogError(device, msg_code, "%s: pRegion[%d] exceeds buffer size of %" PRIu64 " bytes..", func_name, i, buffer_size);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006196 }
6197 }
6198
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006199 return skip;
6200}
6201
Jeff Leger178b1e52020-10-05 12:22:23 -04006202template <typename BufferImageCopyRegionType>
6203bool CoreChecks::ValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6204 VkBuffer dstBuffer, uint32_t regionCount, const BufferImageCopyRegionType *pRegions,
6205 CopyCommandVersion version) const {
John Zulaufe3d1c8a2019-08-12 14:34:58 -06006206 const auto cb_node = GetCBState(commandBuffer);
6207 const auto src_image_state = GetImageState(srcImage);
6208 const auto dst_buffer_state = GetBufferState(dstBuffer);
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07006209
Jeff Leger178b1e52020-10-05 12:22:23 -04006210 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
6211 const char *func_name = is_2khr ? "vkCmdCopyImageToBuffer2KHR()" : "vkCmdCopyImageToBuffer()";
6212 const CMD_TYPE cmd_type = is_2khr ? CMD_COPYIMAGETOBUFFER2KHR : CMD_COPYIMAGETOBUFFER;
6213 const char *vuid;
6214
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07006215 bool skip = ValidateBufferImageCopyData(cb_node, regionCount, pRegions, src_image_state, func_name, version, true);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006216
6217 // Validate command buffer state
Jeff Leger178b1e52020-10-05 12:22:23 -04006218 skip |= ValidateCmd(cb_node, cmd_type, func_name);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006219
6220 // Command pool must support graphics, compute, or transfer operations
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07006221 const auto pool = cb_node->command_pool.get();
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006222
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07006223 VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pool->queueFamilyIndex].queueFlags;
Mark Lobodzinskif6dd3762019-02-27 12:11:59 -07006224
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006225 if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006226 vuid =
6227 is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-cmdpool" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-cmdpool";
6228 skip |= LogError(cb_node->createInfo.commandPool, vuid,
6229 "Cannot call %s on a command buffer allocated from a pool without graphics, compute, "
6230 "or transfer capabilities.",
6231 func_name);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006232 }
Jeff Leger178b1e52020-10-05 12:22:23 -04006233 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-pRegions-00182" : "VUID-vkCmdCopyImageToBuffer-pRegions-00182";
6234 skip |= ValidateImageBounds(src_image_state, regionCount, pRegions, func_name, vuid);
6235 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-pRegions-00183" : "VUID-vkCmdCopyImageToBuffer-pRegions-00183";
6236 skip |= ValidateBufferBounds(src_image_state, dst_buffer_state, regionCount, pRegions, func_name, vuid);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006237
Jeff Leger178b1e52020-10-05 12:22:23 -04006238 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00188" : "VUID-vkCmdCopyImageToBuffer-srcImage-00188";
6239 const char *location = is_2khr ? "vkCmdCopyImageToBuffer2KHR(): srcImage" : "vkCmdCopyImageToBuffer(): srcImage";
6240 skip |= ValidateImageSampleCount(src_image_state, VK_SAMPLE_COUNT_1_BIT, location, vuid);
6241
6242 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00187" : "VUID-vkCmdCopyImageToBuffer-srcImage-00187";
6243 skip |= ValidateMemoryIsBoundToImage(src_image_state, func_name, vuid);
6244 vuid = is_2khr ? "vkCmdCopyImageToBuffer-dstBuffer2KHR-00192" : "vkCmdCopyImageToBuffer dstBuffer-00192";
6245 skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state, func_name, vuid);
Mark Lobodzinski033c90b2017-02-15 13:58:23 -07006246
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006247 // Validate that SRC image & DST buffer have correct usage flags set
Jeff Leger178b1e52020-10-05 12:22:23 -04006248 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00186" : "VUID-vkCmdCopyImageToBuffer-srcImage-00186";
6249 skip |= ValidateImageUsageFlags(src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
Dave Houltond8ed0212018-05-16 17:18:24 -06006250 "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
Jeff Leger178b1e52020-10-05 12:22:23 -04006251 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-dstBuffer-00191" : "VUID-vkCmdCopyImageToBuffer-dstBuffer-00191";
6252 skip |= ValidateBufferUsageFlags(dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
Dave Houltond8ed0212018-05-16 17:18:24 -06006253 "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
Jeff Leger178b1e52020-10-05 12:22:23 -04006254 vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-01831" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-01831";
6255 skip |= ValidateProtectedImage(cb_node, src_image_state, func_name, vuid);
6256 vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-01832" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-01832";
6257 skip |= ValidateProtectedBuffer(cb_node, dst_buffer_state, func_name, vuid);
6258 vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-01833" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-01833";
6259 skip |= ValidateUnprotectedBuffer(cb_node, dst_buffer_state, func_name, vuid);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02006260
6261 // Validation for VK_EXT_fragment_density_map
6262 if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006263 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-02544" : "VUID-vkCmdCopyImageToBuffer-srcImage-02544";
6264 skip |= LogError(cb_node->commandBuffer, vuid,
6265 "%s: srcImage must not have been created with flags containing "
6266 "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
6267 func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02006268 }
6269
Mark Lobodzinski8c193c02020-02-20 09:20:33 -07006270 if (device_extensions.vk_khr_maintenance1) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006271 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-01998" : "VUID-vkCmdCopyImageToBuffer-srcImage-01998";
6272 skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, func_name, vuid);
Cort Stratton186b1a22018-05-01 20:18:06 -04006273 }
Jeff Leger178b1e52020-10-05 12:22:23 -04006274 vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer-renderpass" : "VUID-vkCmdCopyImageToBuffer-renderpass";
6275 skip |= InsideRenderPass(cb_node, func_name, vuid);
Tobin Ehlisc8266452017-04-07 12:20:30 -06006276 bool hit_error = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04006277
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06006278 const char *src_invalid_layout_vuid = (src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
Jeff Leger178b1e52020-10-05 12:22:23 -04006279 ? (vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImageLayout-01397"
6280 : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-01397")
6281 : (vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImageLayout-00190"
6282 : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190");
6283
Mark Lobodzinski033c90b2017-02-15 13:58:23 -07006284 for (uint32_t i = 0; i < regionCount; ++i) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006285 skip |= ValidateImageSubresourceLayers(cb_node, &pRegions[i].imageSubresource, func_name, "imageSubresource", i);
6286 vuid =
6287 is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImageLayout-00189" : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00189";
Mark Lobodzinski8564e442019-03-07 12:49:41 -07006288 skip |= VerifyImageLayout(cb_node, src_image_state, pRegions[i].imageSubresource, srcImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04006289 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, src_invalid_layout_vuid, vuid, &hit_error);
6290 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-01794" : "VUID-vkCmdCopyImageToBuffer-imageOffset-01794";
6291 skip |= ValidateCopyBufferImageTransferGranularityRequirements(cb_node, src_image_state, &pRegions[i], i, func_name, vuid);
6292 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-imageSubresource-01703"
6293 : "VUID-vkCmdCopyImageToBuffer-imageSubresource-01703";
6294 skip |= ValidateImageMipLevel(cb_node, src_image_state, pRegions[i].imageSubresource.mipLevel, i, func_name,
6295 "imageSubresource", vuid);
6296 vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-imageSubresource-01704"
6297 : "VUID-vkCmdCopyImageToBuffer-imageSubresource-01704";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07006298 skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, pRegions[i].imageSubresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04006299 pRegions[i].imageSubresource.layerCount, i, func_name, "imageSubresource", vuid);
Mark Lobodzinski033c90b2017-02-15 13:58:23 -07006300 }
6301 return skip;
6302}
6303
Jeff Leger178b1e52020-10-05 12:22:23 -04006304bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6305 VkBuffer dstBuffer, uint32_t regionCount,
6306 const VkBufferImageCopy *pRegions) const {
6307 return ValidateCmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions,
6308 COPY_COMMAND_VERSION_1);
6309}
6310
6311bool CoreChecks::PreCallValidateCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer,
6312 const VkCopyImageToBufferInfo2KHR *pCopyImageToBufferInfo) const {
6313 return ValidateCmdCopyImageToBuffer(commandBuffer, pCopyImageToBufferInfo->srcImage, pCopyImageToBufferInfo->srcImageLayout,
6314 pCopyImageToBufferInfo->dstBuffer, pCopyImageToBufferInfo->regionCount,
6315 pCopyImageToBufferInfo->pRegions, COPY_COMMAND_VERSION_2);
6316}
6317
John Zulauf1686f232019-07-09 16:27:11 -06006318void CoreChecks::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6319 VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
6320 StateTracker::PreCallRecordCmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
6321
6322 auto cb_node = GetCBState(commandBuffer);
6323 auto src_image_state = GetImageState(srcImage);
John Zulauff660ad62019-03-23 07:16:05 -06006324 // Make sure that all image slices record referenced layout
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07006325 for (uint32_t i = 0; i < regionCount; ++i) {
John Zulauff660ad62019-03-23 07:16:05 -06006326 SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].imageSubresource, srcImageLayout);
Tobin Ehlise35b66a2017-03-15 12:18:31 -06006327 }
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006328}
6329
Jeff Leger178b1e52020-10-05 12:22:23 -04006330void CoreChecks::PreCallRecordCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer,
6331 const VkCopyImageToBufferInfo2KHR *pCopyImageToBufferInfo) {
6332 StateTracker::PreCallRecordCmdCopyImageToBuffer2KHR(commandBuffer, pCopyImageToBufferInfo);
6333
6334 auto cb_node = GetCBState(commandBuffer);
6335 auto src_image_state = GetImageState(pCopyImageToBufferInfo->srcImage);
6336 // Make sure that all image slices record referenced layout
6337 for (uint32_t i = 0; i < pCopyImageToBufferInfo->regionCount; ++i) {
6338 SetImageInitialLayout(cb_node, *src_image_state, pCopyImageToBufferInfo->pRegions[i].imageSubresource,
6339 pCopyImageToBufferInfo->srcImageLayout);
6340 }
6341}
6342
6343template <typename RegionType>
6344bool CoreChecks::ValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
6345 VkImageLayout dstImageLayout, uint32_t regionCount, const RegionType *pRegions,
6346 CopyCommandVersion version) const {
John Zulaufe3d1c8a2019-08-12 14:34:58 -06006347 const auto cb_node = GetCBState(commandBuffer);
6348 const auto src_buffer_state = GetBufferState(srcBuffer);
6349 const auto dst_image_state = GetImageState(dstImage);
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07006350
Jeff Leger178b1e52020-10-05 12:22:23 -04006351 const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
6352 const char *func_name = is_2khr ? "vkCmdCopyBufferToImage2KHR()" : "vkCmdCopyBufferToImage()";
6353 const CMD_TYPE cmd_type = is_2khr ? CMD_COPYBUFFERTOIMAGE2KHR : CMD_COPYBUFFERTOIMAGE;
6354 const char *vuid;
6355
sfricke-samsung88ac6fe2020-10-24 10:00:13 -07006356 bool skip = ValidateBufferImageCopyData(cb_node, regionCount, pRegions, dst_image_state, func_name, version, false);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006357
6358 // Validate command buffer state
Jeff Leger178b1e52020-10-05 12:22:23 -04006359 skip |= ValidateCmd(cb_node, cmd_type, func_name);
Mark Lobodzinskid2b2f612017-02-15 13:45:18 -07006360
sfricke-samsungea4fd142020-10-17 23:51:59 -07006361 vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage2KHR-commandBuffer-cmdpool" : "VUID-vkCmdCopyBufferToImage-commandBuffer-cmdpool";
6362 skip |= ValidateCmdQueueFlags(cb_node, func_name, VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, vuid);
6363
Jeff Leger178b1e52020-10-05 12:22:23 -04006364 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-pRegions-00172" : "VUID-vkCmdCopyBufferToImage-pRegions-00172";
6365 skip |= ValidateImageBounds(dst_image_state, regionCount, pRegions, func_name, vuid);
6366 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-pRegions-00171" : "VUID-vkCmdCopyBufferToImage-pRegions-00171";
6367 skip |= ValidateBufferBounds(dst_image_state, src_buffer_state, regionCount, pRegions, func_name, vuid);
6368
6369 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00179" : "VUID-vkCmdCopyBufferToImage-dstImage-00179";
6370 const char *location = is_2khr ? "vkCmdCopyBufferToImage2KHR(): dstImage" : "vkCmdCopyBufferToImage(): dstImage";
6371 skip |= ValidateImageSampleCount(dst_image_state, VK_SAMPLE_COUNT_1_BIT, location, vuid);
6372 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-srcBuffer-00176" : "VUID-vkCmdCopyBufferToImage-srcBuffer-00176";
6373 skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state, func_name, vuid);
6374 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00178" : "VUID-vkCmdCopyBufferToImage-dstImage-00178";
6375 skip |= ValidateMemoryIsBoundToImage(dst_image_state, func_name, vuid);
6376 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-srcBuffer-00174" : "VUID-vkCmdCopyBufferToImage-srcBuffer-00174";
6377 skip |= ValidateBufferUsageFlags(src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
Dave Houltond8ed0212018-05-16 17:18:24 -06006378 "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
Jeff Leger178b1e52020-10-05 12:22:23 -04006379 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00177" : "VUID-vkCmdCopyBufferToImage-dstImage-00177";
6380 skip |= ValidateImageUsageFlags(dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
Dave Houltond8ed0212018-05-16 17:18:24 -06006381 "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
Jeff Leger178b1e52020-10-05 12:22:23 -04006382 vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage2KHR-commandBuffer-01828" : "VUID-vkCmdCopyBufferToImage-commandBuffer-01828";
6383 skip |= ValidateProtectedBuffer(cb_node, src_buffer_state, func_name, vuid);
6384 vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage2KHR-commandBuffer-01829" : "VUID-vkCmdCopyBufferToImage-commandBuffer-01829";
6385 skip |= ValidateProtectedImage(cb_node, dst_image_state, func_name, vuid);
6386 vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage-commandBuffer-01830" : "VUID-vkCmdCopyBufferToImage-commandBuffer-01830";
6387 skip |= ValidateUnprotectedImage(cb_node, dst_image_state, func_name, vuid);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02006388
6389 // Validation for VK_EXT_fragment_density_map
6390 if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006391 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-02543" : "VUID-vkCmdCopyBufferToImage-dstImage-02543";
6392 skip |= LogError(cb_node->commandBuffer, vuid,
6393 "%s: dstImage must not have been created with flags containing "
6394 "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
6395 func_name);
janharaldfredriksen-arm3b793772020-05-12 18:55:53 +02006396 }
6397
Mark Lobodzinski8c193c02020-02-20 09:20:33 -07006398 if (device_extensions.vk_khr_maintenance1) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006399 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-01997" : "VUID-vkCmdCopyBufferToImage-dstImage-01997";
6400 skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, func_name, vuid);
Cort Stratton186b1a22018-05-01 20:18:06 -04006401 }
Jeff Leger178b1e52020-10-05 12:22:23 -04006402 vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage2KHR-renderpass" : "VUID-vkCmdCopyBufferToImage-renderpass";
6403 skip |= InsideRenderPass(cb_node, func_name, vuid);
Tobin Ehlisc8266452017-04-07 12:20:30 -06006404 bool hit_error = false;
Jeff Leger178b1e52020-10-05 12:22:23 -04006405
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06006406 const char *dst_invalid_layout_vuid = (dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
Jeff Leger178b1e52020-10-05 12:22:23 -04006407 ? (is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImageLayout-01396"
6408 : "VUID-vkCmdCopyBufferToImage-dstImageLayout-01396")
6409 : (is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImageLayout-00181"
6410 : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00181");
6411
Mark Lobodzinski033c90b2017-02-15 13:58:23 -07006412 for (uint32_t i = 0; i < regionCount; ++i) {
Jeff Leger178b1e52020-10-05 12:22:23 -04006413 skip |= ValidateImageSubresourceLayers(cb_node, &pRegions[i].imageSubresource, func_name, "imageSubresource", i);
6414 vuid =
6415 is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImageLayout-00180" : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00180";
Mark Lobodzinski8564e442019-03-07 12:49:41 -07006416 skip |= VerifyImageLayout(cb_node, dst_image_state, pRegions[i].imageSubresource, dstImageLayout,
Jeff Leger178b1e52020-10-05 12:22:23 -04006417 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, dst_invalid_layout_vuid, vuid, &hit_error);
6418 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-01793" : "VUID-vkCmdCopyBufferToImage-imageOffset-01793";
6419 skip |= ValidateCopyBufferImageTransferGranularityRequirements(cb_node, dst_image_state, &pRegions[i], i, func_name, vuid);
6420 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-imageSubresource-01701"
6421 : "VUID-vkCmdCopyBufferToImage-imageSubresource-01701";
6422 skip |= ValidateImageMipLevel(cb_node, dst_image_state, pRegions[i].imageSubresource.mipLevel, i, func_name,
6423 "imageSubresource", vuid);
6424 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-imageSubresource-01702"
6425 : "VUID-vkCmdCopyBufferToImage-imageSubresource-01702";
Mark Lobodzinskifbeb0ca2019-03-09 11:48:22 -07006426 skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, pRegions[i].imageSubresource.baseArrayLayer,
Jeff Leger178b1e52020-10-05 12:22:23 -04006427 pRegions[i].imageSubresource.layerCount, i, func_name, "imageSubresource", vuid);
sfricke-samsungea4fd142020-10-17 23:51:59 -07006428
6429 // TODO - Don't use ValidateCmdQueueFlags due to currently not having way to add more descriptive message
6430 const COMMAND_POOL_STATE *command_pool = cb_node->command_pool.get();
6431 assert(command_pool != nullptr);
6432 const uint32_t queue_family_index = command_pool->queueFamilyIndex;
6433 const VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[queue_family_index].queueFlags;
6434 const VkImageAspectFlags region_aspect_mask = pRegions[i].imageSubresource.aspectMask;
6435 if (((queue_flags & VK_QUEUE_GRAPHICS_BIT) == 0) &&
6436 ((region_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0)) {
6437 LogObjectList objlist(cb_node->commandBuffer);
6438 objlist.add(command_pool->commandPool);
6439 vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-commandBuffer-04477"
6440 : "VUID-vkCmdCopyBufferToImage-commandBuffer-04477";
6441 skip |= LogError(dst_image_state->image, vuid,
6442 "%s(): pRegion[%d] subresource aspectMask 0x%x specifies VK_IMAGE_ASPECT_DEPTH_BIT or "
6443 "VK_IMAGE_ASPECT_STENCIL_BIT but the command buffer %s was allocated from the command pool %s "
6444 "which was created with queueFamilyIndex %u, which doesn't contain the VK_QUEUE_GRAPHICS_BIT flag.",
6445 func_name, i, region_aspect_mask, report_data->FormatHandle(cb_node->commandBuffer).c_str(),
6446 report_data->FormatHandle(command_pool->commandPool).c_str(), queue_family_index);
6447 }
Mark Lobodzinski033c90b2017-02-15 13:58:23 -07006448 }
6449 return skip;
6450}
6451
Jeff Leger178b1e52020-10-05 12:22:23 -04006452bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
6453 VkImageLayout dstImageLayout, uint32_t regionCount,
6454 const VkBufferImageCopy *pRegions) const {
6455 return ValidateCmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions,
6456 COPY_COMMAND_VERSION_1);
6457}
6458
6459bool CoreChecks::PreCallValidateCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer,
6460 const VkCopyBufferToImageInfo2KHR *pCopyBufferToImageInfo) const {
6461 return ValidateCmdCopyBufferToImage(commandBuffer, pCopyBufferToImageInfo->srcBuffer, pCopyBufferToImageInfo->dstImage,
6462 pCopyBufferToImageInfo->dstImageLayout, pCopyBufferToImageInfo->regionCount,
6463 pCopyBufferToImageInfo->pRegions, COPY_COMMAND_VERSION_2);
6464}
6465
John Zulauf1686f232019-07-09 16:27:11 -06006466void CoreChecks::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
6467 VkImageLayout dstImageLayout, uint32_t regionCount,
6468 const VkBufferImageCopy *pRegions) {
6469 StateTracker::PreCallRecordCmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
6470
6471 auto cb_node = GetCBState(commandBuffer);
6472 auto dst_image_state = GetImageState(dstImage);
John Zulauff660ad62019-03-23 07:16:05 -06006473 // Make sure that all image slices are record referenced layout
Mark Lobodzinskib7eafbe2019-01-10 13:40:39 -07006474 for (uint32_t i = 0; i < regionCount; ++i) {
John Zulauff660ad62019-03-23 07:16:05 -06006475 SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
Tobin Ehlise35b66a2017-03-15 12:18:31 -06006476 }
Mark Lobodzinskiab9ea3e2017-02-15 12:59:00 -07006477}
Mike Weiblen672b58b2017-02-21 14:32:53 -07006478
Jeff Leger178b1e52020-10-05 12:22:23 -04006479void CoreChecks::PreCallRecordCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer,
6480 const VkCopyBufferToImageInfo2KHR *pCopyBufferToImageInfo2KHR) {
6481 StateTracker::PreCallRecordCmdCopyBufferToImage2KHR(commandBuffer, pCopyBufferToImageInfo2KHR);
6482
6483 auto cb_node = GetCBState(commandBuffer);
6484 auto dst_image_state = GetImageState(pCopyBufferToImageInfo2KHR->dstImage);
6485 // Make sure that all image slices are record referenced layout
6486 for (uint32_t i = 0; i < pCopyBufferToImageInfo2KHR->regionCount; ++i) {
6487 SetImageInitialLayout(cb_node, *dst_image_state, pCopyBufferToImageInfo2KHR->pRegions[i].imageSubresource,
6488 pCopyBufferToImageInfo2KHR->dstImageLayout);
6489 }
6490}
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07006491bool CoreChecks::PreCallValidateGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
Jeff Bolz5c801d12019-10-09 10:38:45 -05006492 VkSubresourceLayout *pLayout) const {
Mike Weiblen672b58b2017-02-21 14:32:53 -07006493 bool skip = false;
6494 const VkImageAspectFlags sub_aspect = pSubresource->aspectMask;
6495
Dave Houlton1d960ff2018-01-19 12:17:05 -07006496 // The aspectMask member of pSubresource must only have a single bit set
Mike Weiblen672b58b2017-02-21 14:32:53 -07006497 const int num_bits = sizeof(sub_aspect) * CHAR_BIT;
6498 std::bitset<num_bits> aspect_mask_bits(sub_aspect);
6499 if (aspect_mask_bits.count() != 1) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006500 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-aspectMask-00997",
6501 "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must have exactly 1 bit set.");
Mike Weiblen672b58b2017-02-21 14:32:53 -07006502 }
6503
John Zulaufa26d3c82019-08-14 16:09:08 -06006504 const IMAGE_STATE *image_entry = GetImageState(image);
Mike Weiblen672b58b2017-02-21 14:32:53 -07006505 if (!image_entry) {
6506 return skip;
6507 }
6508
Mark Lobodzinski6f358172019-10-02 11:09:12 -06006509 // Image must have been created with tiling equal to VK_IMAGE_TILING_LINEAR
6510 if (device_extensions.vk_ext_image_drm_format_modifier) {
6511 if ((image_entry->createInfo.tiling != VK_IMAGE_TILING_LINEAR) &&
6512 (image_entry->createInfo.tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006513 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-image-02270",
6514 "vkGetImageSubresourceLayout(): Image must have tiling of VK_IMAGE_TILING_LINEAR or "
6515 "VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT.");
Mark Lobodzinski6f358172019-10-02 11:09:12 -06006516 }
6517 } else {
6518 if (image_entry->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006519 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-image-00996",
6520 "vkGetImageSubresourceLayout(): Image must have tiling of VK_IMAGE_TILING_LINEAR.");
Mark Lobodzinski6f358172019-10-02 11:09:12 -06006521 }
Mike Weiblen672b58b2017-02-21 14:32:53 -07006522 }
6523
Dave Houlton1d960ff2018-01-19 12:17:05 -07006524 // mipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created
Mike Weiblen672b58b2017-02-21 14:32:53 -07006525 if (pSubresource->mipLevel >= image_entry->createInfo.mipLevels) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006526 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-mipLevel-01716",
6527 "vkGetImageSubresourceLayout(): pSubresource.mipLevel (%d) must be less than %d.", pSubresource->mipLevel,
6528 image_entry->createInfo.mipLevels);
Mike Weiblen672b58b2017-02-21 14:32:53 -07006529 }
6530
Dave Houlton1d960ff2018-01-19 12:17:05 -07006531 // arrayLayer must be less than the arrayLayers specified in VkImageCreateInfo when the image was created
Mike Weiblen672b58b2017-02-21 14:32:53 -07006532 if (pSubresource->arrayLayer >= image_entry->createInfo.arrayLayers) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006533 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-arrayLayer-01717",
6534 "vkGetImageSubresourceLayout(): pSubresource.arrayLayer (%d) must be less than %d.",
6535 pSubresource->arrayLayer, image_entry->createInfo.arrayLayers);
Mike Weiblen672b58b2017-02-21 14:32:53 -07006536 }
6537
Dave Houlton1d960ff2018-01-19 12:17:05 -07006538 // subresource's aspect must be compatible with image's format.
Mike Weiblen672b58b2017-02-21 14:32:53 -07006539 const VkFormat img_format = image_entry->createInfo.format;
Mark Lobodzinski9824cac2019-10-02 13:19:38 -06006540 if (image_entry->createInfo.tiling == VK_IMAGE_TILING_LINEAR) {
6541 if (FormatIsMultiplane(img_format)) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08006542 VkImageAspectFlags allowed_flags = (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
Mark Lobodzinski9824cac2019-10-02 13:19:38 -06006543 const char *vuid = "VUID-vkGetImageSubresourceLayout-format-01581"; // 2-plane version
6544 if (FormatPlaneCount(img_format) > 2u) {
Mike Schuchardt2df08912020-12-15 16:28:09 -08006545 allowed_flags |= VK_IMAGE_ASPECT_PLANE_2_BIT;
Mark Lobodzinski9824cac2019-10-02 13:19:38 -06006546 vuid = "VUID-vkGetImageSubresourceLayout-format-01582"; // 3-plane version
6547 }
6548 if (sub_aspect != (sub_aspect & allowed_flags)) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006549 skip |= LogError(image, vuid,
6550 "vkGetImageSubresourceLayout(): For multi-planar images, VkImageSubresource.aspectMask (0x%" PRIx32
6551 ") must be a single-plane specifier flag.",
6552 sub_aspect);
Mark Lobodzinski9824cac2019-10-02 13:19:38 -06006553 }
6554 } else if (FormatIsColor(img_format)) {
6555 if (sub_aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006556 skip |= LogError(image, kVUID_Core_DrawState_InvalidImageAspect,
6557 "vkGetImageSubresourceLayout(): For color formats, VkImageSubresource.aspectMask must be "
6558 "VK_IMAGE_ASPECT_COLOR.");
Mark Lobodzinski9824cac2019-10-02 13:19:38 -06006559 }
6560 } else if (FormatIsDepthOrStencil(img_format)) {
6561 if ((sub_aspect != VK_IMAGE_ASPECT_DEPTH_BIT) && (sub_aspect != VK_IMAGE_ASPECT_STENCIL_BIT)) {
6562 }
Dave Houlton1d960ff2018-01-19 12:17:05 -07006563 }
Mark Lobodzinski9824cac2019-10-02 13:19:38 -06006564 } else if (image_entry->createInfo.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
6565 if ((sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT) && (sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT) &&
6566 (sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT) && (sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
6567 // TODO: This VU also needs to ensure that the DRM index is in range and valid.
Mark Lobodzinski4fc2bb42020-01-31 14:21:21 -07006568 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-tiling-02271",
6569 "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must be "
6570 "VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT.");
Mike Weiblen672b58b2017-02-21 14:32:53 -07006571 }
6572 }
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06006573
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06006574 if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
Mark Lobodzinskie9b99792019-03-07 16:34:29 -07006575 skip |= ValidateGetImageSubresourceLayoutANDROID(image);
Dave Houlton0d4ad6f2018-09-05 14:53:34 -06006576 }
6577
Mike Weiblen672b58b2017-02-21 14:32:53 -07006578 return skip;
6579}
sfricke-samsung022fa252020-07-24 03:26:16 -07006580
6581// Validates the image is allowed to be protected
6582bool CoreChecks::ValidateProtectedImage(const CMD_BUFFER_STATE *cb_state, const IMAGE_STATE *image_state, const char *cmd_name,
locke-lunarg351c9d82020-10-23 14:43:21 -06006583 const char *vuid, const char *more_message) const {
sfricke-samsung022fa252020-07-24 03:26:16 -07006584 bool skip = false;
6585 if ((cb_state->unprotected == true) && (image_state->unprotected == false)) {
6586 LogObjectList objlist(cb_state->commandBuffer);
6587 objlist.add(image_state->image);
locke-lunarg351c9d82020-10-23 14:43:21 -06006588 skip |= LogError(objlist, vuid, "%s: command buffer %s is unprotected while image %s is a protected image.%s", cmd_name,
sfricke-samsung022fa252020-07-24 03:26:16 -07006589 report_data->FormatHandle(cb_state->commandBuffer).c_str(),
locke-lunarg351c9d82020-10-23 14:43:21 -06006590 report_data->FormatHandle(image_state->image).c_str(), more_message);
sfricke-samsung022fa252020-07-24 03:26:16 -07006591 }
6592 return skip;
6593}
6594
6595// Validates the image is allowed to be unprotected
6596bool CoreChecks::ValidateUnprotectedImage(const CMD_BUFFER_STATE *cb_state, const IMAGE_STATE *image_state, const char *cmd_name,
locke-lunarg351c9d82020-10-23 14:43:21 -06006597 const char *vuid, const char *more_message) const {
sfricke-samsung022fa252020-07-24 03:26:16 -07006598 bool skip = false;
6599 if ((cb_state->unprotected == false) && (image_state->unprotected == true)) {
6600 LogObjectList objlist(cb_state->commandBuffer);
6601 objlist.add(image_state->image);
locke-lunarg351c9d82020-10-23 14:43:21 -06006602 skip |= LogError(objlist, vuid, "%s: command buffer %s is protected while image %s is an unprotected image.%s", cmd_name,
sfricke-samsung022fa252020-07-24 03:26:16 -07006603 report_data->FormatHandle(cb_state->commandBuffer).c_str(),
locke-lunarg351c9d82020-10-23 14:43:21 -06006604 report_data->FormatHandle(image_state->image).c_str(), more_message);
sfricke-samsung022fa252020-07-24 03:26:16 -07006605 }
6606 return skip;
6607}
6608
6609// Validates the buffer is allowed to be protected
6610bool CoreChecks::ValidateProtectedBuffer(const CMD_BUFFER_STATE *cb_state, const BUFFER_STATE *buffer_state, const char *cmd_name,
locke-lunarg351c9d82020-10-23 14:43:21 -06006611 const char *vuid, const char *more_message) const {
sfricke-samsung022fa252020-07-24 03:26:16 -07006612 bool skip = false;
6613 if ((cb_state->unprotected == true) && (buffer_state->unprotected == false)) {
6614 LogObjectList objlist(cb_state->commandBuffer);
6615 objlist.add(buffer_state->buffer);
locke-lunarg351c9d82020-10-23 14:43:21 -06006616 skip |= LogError(objlist, vuid, "%s: command buffer %s is unprotected while buffer %s is a protected buffer.%s", cmd_name,
sfricke-samsung022fa252020-07-24 03:26:16 -07006617 report_data->FormatHandle(cb_state->commandBuffer).c_str(),
locke-lunarg351c9d82020-10-23 14:43:21 -06006618 report_data->FormatHandle(buffer_state->buffer).c_str(), more_message);
sfricke-samsung022fa252020-07-24 03:26:16 -07006619 }
6620 return skip;
6621}
6622
6623// Validates the buffer is allowed to be unprotected
6624bool CoreChecks::ValidateUnprotectedBuffer(const CMD_BUFFER_STATE *cb_state, const BUFFER_STATE *buffer_state, const char *cmd_name,
locke-lunarg351c9d82020-10-23 14:43:21 -06006625 const char *vuid, const char *more_message) const {
sfricke-samsung022fa252020-07-24 03:26:16 -07006626 bool skip = false;
6627 if ((cb_state->unprotected == false) && (buffer_state->unprotected == true)) {
6628 LogObjectList objlist(cb_state->commandBuffer);
6629 objlist.add(buffer_state->buffer);
locke-lunarg351c9d82020-10-23 14:43:21 -06006630 skip |= LogError(objlist, vuid, "%s: command buffer %s is protected while buffer %s is an unprotected buffer.%s", cmd_name,
sfricke-samsung022fa252020-07-24 03:26:16 -07006631 report_data->FormatHandle(cb_state->commandBuffer).c_str(),
locke-lunarg351c9d82020-10-23 14:43:21 -06006632 report_data->FormatHandle(buffer_state->buffer).c_str(), more_message);
sfricke-samsung022fa252020-07-24 03:26:16 -07006633 }
6634 return skip;
6635}