1 /* 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.
5  * Modifications Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
6  *
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>
20  * Author: Dave Houlton <daveh@lunarg.com>
21  * Shannon McPherson <shannon@lunarg.com>
22  * Author: Tobias Hector <tobias.hector@amd.com>
23  */
24 
25 #include <cmath>
26 #include <set>
27 #include <sstream>
28 #include <string>
29 #include <iostream>
30 
31 #include "vk_enum_string_helper.h"
32 #include "vk_format_utils.h"
33 #include "vk_layer_data.h"
34 #include "vk_layer_utils.h"
35 #include "vk_layer_logging.h"
36 #include "vk_typemap_helper.h"
37 
38 #include "chassis.h"
39 #include "core_validation.h"
40 #include "core_error_location.h"
41 #include "shader_validation.h"
42 #include "descriptor_sets.h"
43 #include "buffer_validation.h"
44 #include "sync_utils.h"
45 #include "sync_vuid_maps.h"
46 
47 // All VUID from copy_bufferimage_to_imagebuffer_common.txt
GetBufferImageCopyCommandVUID(std::string id,bool image_to_buffer,bool copy2)48 static const char *GetBufferImageCopyCommandVUID(std::string id, bool image_to_buffer, bool copy2) {
49     // clang-format off
50     static const std::map<std::string, std::array<const char *, 4>> copy_imagebuffer_vuid = {
51         {"00193", {
52             "VUID-vkCmdCopyBufferToImage-bufferOffset-00193",      // !copy2 & !image_to_buffer
53             "VUID-vkCmdCopyImageToBuffer-bufferOffset-00193",      // !copy2 &  image_to_buffer
54             "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-00193", //  copy2 & !image_to_buffer
55             "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-00193", //  copy2 &  image_to_buffer
56         }},
57         {"01558", {
58             "VUID-vkCmdCopyBufferToImage-bufferOffset-01558",
59             "VUID-vkCmdCopyImageToBuffer-bufferOffset-01558",
60             "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-01558",
61             "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-01558",
62         }},
63         {"01559", {
64             "VUID-vkCmdCopyBufferToImage-bufferOffset-01559",
65             "VUID-vkCmdCopyImageToBuffer-bufferOffset-01559",
66             "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-01559",
67             "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-01559",
68         }},
69         {"00197", {
70             "VUID-vkCmdCopyBufferToImage-pRegions-06218",
71             "VUID-vkCmdCopyImageToBuffer-pRegions-06221",
72             "VUID-VkCopyBufferToImageInfo2KHR-pRegions-06223",
73             "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00197",
74         }},
75         {"00198", {
76             "VUID-vkCmdCopyBufferToImage-pRegions-06219",
77             "VUID-vkCmdCopyImageToBuffer-pRegions-06222",
78             "VUID-VkCopyBufferToImageInfo2KHR-pRegions-06224",
79             "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00198",
80         }},
81         {"00199", {
82             "VUID-vkCmdCopyBufferToImage-srcImage-00199",
83             "VUID-vkCmdCopyImageToBuffer-srcImage-00199",
84             "VUID-VkCopyBufferToImageInfo2KHR-srcImage-00199",
85             "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00199",
86         }},
87         {"00200", {
88             "VUID-vkCmdCopyBufferToImage-imageOffset-00200",
89             "VUID-vkCmdCopyImageToBuffer-imageOffset-00200",
90             "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-00200",
91             "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00200",
92         }},
93         {"00201", {
94             "VUID-vkCmdCopyBufferToImage-srcImage-00201",
95             "VUID-vkCmdCopyImageToBuffer-srcImage-00201",
96             "VUID-VkCopyBufferToImageInfo2KHR-srcImage-00201",
97             "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00201",
98         }},
99         {"00203", {
100             "VUID-vkCmdCopyBufferToImage-bufferRowLength-00203",
101             "VUID-vkCmdCopyImageToBuffer-bufferRowLength-00203",
102             "VUID-VkCopyBufferToImageInfo2KHR-bufferRowLength-00203",
103             "VUID-VkCopyImageToBufferInfo2KHR-bufferRowLength-00203",
104         }},
105         {"00204", {
106             "VUID-vkCmdCopyBufferToImage-bufferImageHeight-00204",
107             "VUID-vkCmdCopyImageToBuffer-bufferImageHeight-00204",
108             "VUID-VkCopyBufferToImageInfo2KHR-bufferImageHeight-00204",
109             "VUID-VkCopyImageToBufferInfo2KHR-bufferImageHeight-00204",
110         }},
111         {"00205", {
112             "VUID-vkCmdCopyBufferToImage-imageOffset-00205",
113             "VUID-vkCmdCopyImageToBuffer-imageOffset-00205",
114             "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-00205",
115             "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-00205",
116         }},
117         {"00206", {
118             "VUID-vkCmdCopyBufferToImage-bufferOffset-00206",
119             "VUID-vkCmdCopyImageToBuffer-bufferOffset-00206",
120             "VUID-VkCopyBufferToImageInfo2KHR-bufferOffset-00206",
121             "VUID-VkCopyImageToBufferInfo2KHR-bufferOffset-00206",
122         }},
123         {"00207", {
124             "VUID-vkCmdCopyBufferToImage-imageExtent-00207",
125             "VUID-vkCmdCopyImageToBuffer-imageExtent-00207",
126             "VUID-VkCopyBufferToImageInfo2KHR-imageExtent-00207",
127             "VUID-VkCopyImageToBufferInfo2KHR-imageExtent-00207",
128         }},
129         {"00208", {
130             "VUID-vkCmdCopyBufferToImage-imageExtent-00208",
131             "VUID-vkCmdCopyImageToBuffer-imageExtent-00208",
132             "VUID-VkCopyBufferToImageInfo2KHR-imageExtent-00208",
133             "VUID-VkCopyImageToBufferInfo2KHR-imageExtent-00208",
134         }},
135         {"00209", {
136             "VUID-vkCmdCopyBufferToImage-imageExtent-00209",
137             "VUID-vkCmdCopyImageToBuffer-imageExtent-00209",
138             "VUID-VkCopyBufferToImageInfo2KHR-imageExtent-00209",
139             "VUID-VkCopyImageToBufferInfo2KHR-imageExtent-00209",
140         }},
141         {"00211", {
142             "VUID-vkCmdCopyBufferToImage-aspectMask-00211",
143             "VUID-vkCmdCopyImageToBuffer-aspectMask-00211",
144             "VUID-VkCopyBufferToImageInfo2KHR-aspectMask-00211",
145             "VUID-VkCopyImageToBufferInfo2KHR-aspectMask-00211",
146         }},
147         {"01560", {
148             "VUID-vkCmdCopyBufferToImage-aspectMask-01560",
149             "VUID-vkCmdCopyImageToBuffer-aspectMask-01560",
150             "VUID-VkCopyBufferToImageInfo2KHR-aspectMask-01560",
151             "VUID-VkCopyImageToBufferInfo2KHR-aspectMask-01560",
152         }},
153         {"00213", {
154             "VUID-vkCmdCopyBufferToImage-baseArrayLayer-00213",
155             "VUID-vkCmdCopyImageToBuffer-baseArrayLayer-00213",
156             "VUID-VkCopyBufferToImageInfo2KHR-baseArrayLayer-00213",
157             "VUID-VkCopyImageToBufferInfo2KHR-baseArrayLayer-00213",
158         }},
159         {"04052", {
160             "VUID-vkCmdCopyBufferToImage-commandBuffer-04052",
161             "VUID-vkCmdCopyImageToBuffer-commandBuffer-04052",
162             "VUID-VkCopyBufferToImageInfo2KHR-commandBuffer-04052",
163             "VUID-VkCopyImageToBufferInfo2KHR-commandBuffer-04052",
164         }},
165         {"04053", {
166             "VUID-vkCmdCopyBufferToImage-srcImage-04053",
167             "VUID-vkCmdCopyImageToBuffer-srcImage-04053",
168             "VUID-VkCopyBufferToImageInfo2KHR-srcImage-04053",
169             "VUID-VkCopyImageToBufferInfo2KHR-srcImage-04053",
170         }}
171     };
172     // clang-format on
173 
174     uint8_t index = 0;
175     index |= uint8_t((image_to_buffer) ? 0x1 : 0);
176     index |= uint8_t((copy2) ? 0x2 : 0);
177     return copy_imagebuffer_vuid.at(id).at(index);
178 }
179 
NormalizeDepthImageLayout(VkImageLayout layout)180 static VkImageLayout NormalizeDepthImageLayout(VkImageLayout layout) {
181     switch (layout) {
182         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
183         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
184             return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL;
185 
186         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
187         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
188             return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
189 
190         default:
191             return layout;
192     }
193 }
194 
NormalizeStencilImageLayout(VkImageLayout layout)195 static VkImageLayout NormalizeStencilImageLayout(VkImageLayout layout) {
196     switch (layout) {
197         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
198         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
199             return VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL;
200 
201         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
202         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
203             return VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
204 
205         default:
206             return layout;
207     }
208 }
209 
NormalizeSynchronization2Layout(const VkImageAspectFlags aspect_mask,VkImageLayout layout)210 static VkImageLayout NormalizeSynchronization2Layout(const VkImageAspectFlags aspect_mask, VkImageLayout layout) {
211     if (layout == VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR) {
212         if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
213             layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
214         } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
215             layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
216         } else if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
217             layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
218         } else if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
219             layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
220         }
221     } else if (layout == VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR) {
222         if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
223             layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
224         } else if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
225             layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
226         } else if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
227             layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL;
228         } else if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
229             layout = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL;
230         }
231     }
232     return layout;
233 }
234 
ImageLayoutMatches(const VkImageAspectFlags aspect_mask,VkImageLayout a,VkImageLayout b)235 static bool ImageLayoutMatches(const VkImageAspectFlags aspect_mask, VkImageLayout a, VkImageLayout b) {
236     bool matches = (a == b);
237     if (!matches) {
238         a = NormalizeSynchronization2Layout(aspect_mask, a);
239         b = NormalizeSynchronization2Layout(aspect_mask, b);
240         matches = (a == b);
241         if (!matches) {
242             // Relaxed rules when referencing *only* the depth or stencil aspects.
243             // When accessing both, normalize layouts for aspects separately.
244             if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
245                 matches = NormalizeDepthImageLayout(a) == NormalizeDepthImageLayout(b) &&
246                           NormalizeStencilImageLayout(a) == NormalizeStencilImageLayout(b);
247             } else if (aspect_mask == VK_IMAGE_ASPECT_DEPTH_BIT) {
248                 matches = NormalizeDepthImageLayout(a) == NormalizeDepthImageLayout(b);
249             } else if (aspect_mask == VK_IMAGE_ASPECT_STENCIL_BIT) {
250                 matches = NormalizeStencilImageLayout(a) == NormalizeStencilImageLayout(b);
251             }
252         }
253     }
254     return matches;
255 }
256 
257 // Utility type for ForRange callbacks
258 struct LayoutUseCheckAndMessage {
259     const static VkImageAspectFlags kDepthOrStencil = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
260     const ImageSubresourceLayoutMap *layout_map;
261     const VkImageAspectFlags aspect_mask;
262     const char *message;
263     VkImageLayout layout;
264 
265     LayoutUseCheckAndMessage() = delete;
LayoutUseCheckAndMessageLayoutUseCheckAndMessage266     LayoutUseCheckAndMessage(const ImageSubresourceLayoutMap *layout_map_, const VkImageAspectFlags aspect_mask_ = 0)
267         : layout_map(layout_map_), aspect_mask{aspect_mask_}, message(nullptr), layout(kInvalidLayout) {}
CheckLayoutUseCheckAndMessage268     bool Check(const VkImageSubresource &subres, VkImageLayout check, VkImageLayout current_layout, VkImageLayout initial_layout) {
269         message = nullptr;
270         layout = kInvalidLayout;  // Success status
271         if (current_layout != kInvalidLayout && !ImageLayoutMatches(aspect_mask, check, current_layout)) {
272             message = "previous known";
273             layout = current_layout;
274         } else if ((initial_layout != kInvalidLayout) && !ImageLayoutMatches(aspect_mask, check, initial_layout)) {
275             // To check the relaxed rule matching we need to see how the initial use was used
276             const auto initial_layout_state = layout_map->GetSubresourceInitialLayoutState(subres);
277             assert(initial_layout_state);  // If we have an initial layout, we better have a state for it
278             if (!((initial_layout_state->aspect_mask & kDepthOrStencil) &&
279                   ImageLayoutMatches(initial_layout_state->aspect_mask, check, initial_layout))) {
280                 message = "previously used";
281                 layout = initial_layout;
282             }
283         }
284         return layout == kInvalidLayout;
285     }
286 };
287 
OverlapSubresource(const IMAGE_VIEW_STATE & compare_view) const288 bool IMAGE_VIEW_STATE::OverlapSubresource(const IMAGE_VIEW_STATE &compare_view) const {
289     if (image_view() == compare_view.image_view()) {
290         return true;
291     }
292     if (image_state->image() != compare_view.image_state->image()) {
293         return false;
294     }
295     if (normalized_subresource_range.aspectMask != compare_view.normalized_subresource_range.aspectMask) {
296         return false;
297     }
298 
299     // compare if overlap mip level
300     if ((normalized_subresource_range.baseMipLevel < compare_view.normalized_subresource_range.baseMipLevel) &&
301         ((normalized_subresource_range.baseMipLevel + normalized_subresource_range.levelCount) <=
302          compare_view.normalized_subresource_range.baseMipLevel)) {
303         return false;
304     }
305 
306     if ((normalized_subresource_range.baseMipLevel > compare_view.normalized_subresource_range.baseMipLevel) &&
307         (normalized_subresource_range.baseMipLevel >=
308          (compare_view.normalized_subresource_range.baseMipLevel + compare_view.normalized_subresource_range.levelCount))) {
309         return false;
310     }
311 
312     // compare if overlap array layer
313     if ((normalized_subresource_range.baseArrayLayer < compare_view.normalized_subresource_range.baseArrayLayer) &&
314         ((normalized_subresource_range.baseArrayLayer + normalized_subresource_range.layerCount) <=
315          compare_view.normalized_subresource_range.baseArrayLayer)) {
316         return false;
317     }
318 
319     if ((normalized_subresource_range.baseArrayLayer > compare_view.normalized_subresource_range.baseArrayLayer) &&
320         (normalized_subresource_range.baseArrayLayer >=
321          (compare_view.normalized_subresource_range.baseArrayLayer + compare_view.normalized_subresource_range.layerCount))) {
322         return false;
323     }
324     return true;
325 }
326 
FullMipChainLevels(uint32_t height,uint32_t width,uint32_t depth)327 uint32_t FullMipChainLevels(uint32_t height, uint32_t width, uint32_t depth) {
328     // uint cast applies floor()
329     return 1u + static_cast<uint32_t>(log2(std::max({height, width, depth})));
330 }
331 
FullMipChainLevels(VkExtent3D extent)332 uint32_t FullMipChainLevels(VkExtent3D extent) { return FullMipChainLevels(extent.height, extent.width, extent.depth); }
333 
FullMipChainLevels(VkExtent2D extent)334 uint32_t FullMipChainLevels(VkExtent2D extent) { return FullMipChainLevels(extent.height, extent.width); }
335 
FindLayouts(const IMAGE_STATE & image_state,std::vector<VkImageLayout> & layouts) const336 bool CoreChecks::FindLayouts(const IMAGE_STATE &image_state, std::vector<VkImageLayout> &layouts) const {
337     const auto *layout_range_map = GetLayoutRangeMap(imageLayoutMap, image_state);
338     if (!layout_range_map) return false;
339     // TODO: FindLayouts function should mutate into a ValidatePresentableLayout with the loop wrapping the LogError
340     //       from the caller. You can then use decode to add the subresource of the range::begin to the error message.
341 
342     // TODO: what is this test and what is it supposed to do?! -- the logic doesn't match the comment below?!
343 
344     // TODO: Make this robust for >1 aspect mask. Now it will just say ignore potential errors in this case.
345     if (layout_range_map->size() >= (image_state.createInfo.arrayLayers * image_state.createInfo.mipLevels + 1)) {
346         return false;
347     }
348 
349     for (const auto &entry : *layout_range_map) {
350         layouts.push_back(entry.second);
351     }
352     return true;
353 }
354 
ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version,VkImageLayout layout,const IMAGE_VIEW_STATE & image_view_state,VkFramebuffer framebuffer,VkRenderPass renderpass,uint32_t attachment_index,const char * variable_name) const355 bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version, VkImageLayout layout,
356                                                                       const IMAGE_VIEW_STATE &image_view_state,
357                                                                       VkFramebuffer framebuffer, VkRenderPass renderpass,
358                                                                       uint32_t attachment_index, const char *variable_name) const {
359     bool skip = false;
360     const auto &image_view = image_view_state.Handle();
361     const auto *image_state = image_view_state.image_state.get();
362     const auto &image = image_state->Handle();
363     const char *vuid;
364     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
365     const char *function_name = use_rp2 ? "vkCmdBeginRenderPass2()" : "vkCmdBeginRenderPass()";
366 
367     if (!image_state) {
368         LogObjectList objlist(image);
369         objlist.add(renderpass);
370         objlist.add(framebuffer);
371         objlist.add(image_view);
372         skip |=
373             LogError(image, "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
374                      "%s: RenderPass %s uses %s where pAttachments[%" PRIu32 "] = %s, which refers to an invalid image",
375                      function_name, report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(framebuffer).c_str(),
376                      attachment_index, report_data->FormatHandle(image_view).c_str());
377         return skip;
378     }
379 
380     auto image_usage = image_state->createInfo.usage;
381     const auto stencil_usage_info = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_state->createInfo.pNext);
382     if (stencil_usage_info) {
383         image_usage |= stencil_usage_info->stencilUsage;
384     }
385 
386     // Check for layouts that mismatch image usages in the framebuffer
387     if (layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
388         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03094" : "VUID-vkCmdBeginRenderPass-initialLayout-00895";
389         LogObjectList objlist(image);
390         objlist.add(renderpass);
391         objlist.add(framebuffer);
392         objlist.add(image_view);
393         skip |= LogError(objlist, vuid,
394                          "%s: Layout/usage mismatch for attachment %u in %s"
395                          " - the %s is %s but the image attached to %s via %s"
396                          " was not created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT",
397                          function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
398                          string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
399                          report_data->FormatHandle(image_view).c_str());
400     }
401 
402     if (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
403         !(image_usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
404         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03097" : "VUID-vkCmdBeginRenderPass-initialLayout-00897";
405         LogObjectList objlist(image);
406         objlist.add(renderpass);
407         objlist.add(framebuffer);
408         objlist.add(image_view);
409         skip |= LogError(objlist, vuid,
410                          "%s: Layout/usage mismatch for attachment %u in %s"
411                          " - the %s is %s but the image attached to %s via %s"
412                          " was not created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT or VK_IMAGE_USAGE_SAMPLED_BIT",
413                          function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
414                          string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
415                          report_data->FormatHandle(image_view).c_str());
416     }
417 
418     if (layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
419         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03098" : "VUID-vkCmdBeginRenderPass-initialLayout-00898";
420         LogObjectList objlist(image);
421         objlist.add(renderpass);
422         objlist.add(framebuffer);
423         objlist.add(image_view);
424         skip |= LogError(objlist, vuid,
425                          "%s: Layout/usage mismatch for attachment %u in %s"
426                          " - the %s is %s but the image attached to %s via %s"
427                          " was not created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT",
428                          function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
429                          string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
430                          report_data->FormatHandle(image_view).c_str());
431     }
432 
433     if (layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
434         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03099" : "VUID-vkCmdBeginRenderPass-initialLayout-00899";
435         LogObjectList objlist(image);
436         objlist.add(renderpass);
437         objlist.add(framebuffer);
438         objlist.add(image_view);
439         skip |= LogError(objlist, vuid,
440                          "%s: Layout/usage mismatch for attachment %u in %s"
441                          " - the %s is %s but the image attached to %s via %s"
442                          " was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT",
443                          function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
444                          string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
445                          report_data->FormatHandle(image_view).c_str());
446     }
447 
448     if (IsExtEnabled(device_extensions.vk_khr_maintenance2)) {
449         if ((layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
450              layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
451              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
452              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
453             !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
454             vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2-initialLayout-03096" : "VUID-vkCmdBeginRenderPass-initialLayout-01758";
455             LogObjectList objlist(image);
456             objlist.add(renderpass);
457             objlist.add(framebuffer);
458             objlist.add(image_view);
459             skip |= LogError(objlist, vuid,
460                              "%s: Layout/usage mismatch for attachment %u in %s"
461                              " - the %s is %s but the image attached to %s via %s"
462                              " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
463                              function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
464                              string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
465                              report_data->FormatHandle(image_view).c_str());
466         }
467     } else {
468         // The create render pass 2 extension requires maintenance 2 (the previous branch), so no vuid switch needed here.
469         if ((layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
470              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
471             !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
472             LogObjectList objlist(image);
473             objlist.add(renderpass);
474             objlist.add(framebuffer);
475             objlist.add(image_view);
476             skip |= LogError(objlist, "VUID-vkCmdBeginRenderPass-initialLayout-00896",
477                              "%s: Layout/usage mismatch for attachment %u in %s"
478                              " - the %s is %s but the image attached to %s via %s"
479                              " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
480                              function_name, attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
481                              string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
482                              report_data->FormatHandle(image_view).c_str());
483         }
484     }
485     return skip;
486 }
487 
VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version,const CMD_BUFFER_STATE * pCB,const VkRenderPassBeginInfo * pRenderPassBegin,const FRAMEBUFFER_STATE * framebuffer_state) const488 bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version, const CMD_BUFFER_STATE *pCB,
489                                                        const VkRenderPassBeginInfo *pRenderPassBegin,
490                                                        const FRAMEBUFFER_STATE *framebuffer_state) const {
491     bool skip = false;
492     const auto render_pass_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
493     const auto *render_pass_info = render_pass_state->createInfo.ptr();
494     auto render_pass = render_pass_state->renderPass();
495     auto const &framebuffer_info = framebuffer_state->createInfo;
496     const VkImageView *attachments = framebuffer_info.pAttachments;
497 
498     auto framebuffer = framebuffer_state->framebuffer();
499 
500     if (render_pass_info->attachmentCount != framebuffer_info.attachmentCount) {
501         skip |= LogError(pCB->commandBuffer(), kVUID_Core_DrawState_InvalidRenderpass,
502                          "You cannot start a render pass using a framebuffer with a different number of attachments.");
503     }
504 
505     const auto *attachment_info = LvlFindInChain<VkRenderPassAttachmentBeginInfo>(pRenderPassBegin->pNext);
506     if (((framebuffer_info.flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) != 0) && attachment_info != nullptr) {
507         attachments = attachment_info->pAttachments;
508     }
509 
510     if (attachments != nullptr) {
511         const auto *const_p_cb = static_cast<const CMD_BUFFER_STATE *>(pCB);
512         for (uint32_t i = 0; i < render_pass_info->attachmentCount; ++i) {
513             auto image_view = attachments[i];
514             auto view_state = Get<IMAGE_VIEW_STATE>(image_view);
515 
516             if (!view_state) {
517                 LogObjectList objlist(pRenderPassBegin->renderPass);
518                 objlist.add(framebuffer_state->framebuffer());
519                 objlist.add(image_view);
520                 skip |= LogError(objlist, "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
521                                  "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle",
522                                  report_data->FormatHandle(framebuffer_state->framebuffer()).c_str(), i,
523                                  report_data->FormatHandle(image_view).c_str());
524                 continue;
525             }
526 
527             const VkImage image = view_state->create_info.image;
528             const auto *image_state = view_state->image_state.get();
529 
530             if (!image_state) {
531                 LogObjectList objlist(pRenderPassBegin->renderPass);
532                 objlist.add(framebuffer_state->framebuffer());
533                 objlist.add(image_view);
534                 objlist.add(image);
535                 skip |= LogError(objlist, "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
536                                  "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] =  %s references non-extant %s.",
537                                  report_data->FormatHandle(framebuffer_state->framebuffer()).c_str(), i,
538                                  report_data->FormatHandle(image_view).c_str(), report_data->FormatHandle(image).c_str());
539                 continue;
540             }
541             auto attachment_initial_layout = render_pass_info->pAttachments[i].initialLayout;
542             auto final_layout = render_pass_info->pAttachments[i].finalLayout;
543 
544             // Default to expecting stencil in the same layout.
545             auto attachment_stencil_initial_layout = attachment_initial_layout;
546 
547             // If a separate layout is specified, look for that.
548             const auto *attachment_description_stencil_layout =
549                 LvlFindInChain<VkAttachmentDescriptionStencilLayout>(render_pass_info->pAttachments[i].pNext);
550             if (attachment_description_stencil_layout) {
551                 attachment_stencil_initial_layout = attachment_description_stencil_layout->stencilInitialLayout;
552             }
553 
554             const ImageSubresourceLayoutMap *subresource_map = nullptr;
555             bool has_queried_map = false;
556             bool subres_skip = false;
557 
558             for (uint32_t aspect_index = 0; aspect_index < 32; aspect_index++) {
559                 VkImageAspectFlags test_aspect = 1u << aspect_index;
560                 if ((view_state->normalized_subresource_range.aspectMask & test_aspect) == 0) {
561                     continue;
562                 }
563 
564                 // Allow for differing depth and stencil layouts
565                 VkImageLayout check_layout = attachment_initial_layout;
566                 if (test_aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
567                     check_layout = attachment_stencil_initial_layout;
568                 }
569 
570                 if (check_layout != VK_IMAGE_LAYOUT_UNDEFINED) {  // If no layout information for image yet, will be checked at QueueSubmit time
571                     if (!has_queried_map) {
572                         // Cast pCB to const because we don't want to create entries that don't exist here (in case the key changes to something
573                         // in common with the non-const version.)
574                         // The lookup is expensive, so cache it.
575                         subresource_map = const_p_cb->GetImageSubresourceLayoutMap(*image_state);
576                         has_queried_map = true;
577                     }
578 
579                     if (subresource_map) {
580                         auto normalized_range = view_state->normalized_subresource_range;
581                         normalized_range.aspectMask = test_aspect;
582                         auto pos = subresource_map->Find(normalized_range);
583                         LayoutUseCheckAndMessage layout_check(subresource_map, test_aspect);
584 
585                         // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to the next "constant value" range
586                         for (; !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
587                             const VkImageSubresource &subres = pos->subresource;
588 
589                             if (!layout_check.Check(subres, check_layout, pos->current_layout, pos->initial_layout)) {
590                                 subres_skip |= LogError(
591                                     device, kVUID_Core_DrawState_InvalidRenderpass,
592                                     "You cannot start a render pass using attachment %u where the render pass initial layout is %s "
593                                     "and the %s layout of the attachment is %s. The layouts must match, or the render "
594                                     "pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED",
595                                     i, string_VkImageLayout(check_layout), layout_check.message,
596                                     string_VkImageLayout(layout_check.layout));
597                             }
598                         }
599                     }
600                 }
601             }
602 
603             skip |= subres_skip;
604 
605             ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_initial_layout, *view_state, framebuffer,
606                                                                  render_pass, i, "initial layout");
607 
608             ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, final_layout, *view_state, framebuffer, render_pass, i,
609                                                                  "final layout");
610         }
611 
612         for (uint32_t j = 0; j < render_pass_info->subpassCount; ++j) {
613             auto &subpass = render_pass_info->pSubpasses[j];
614             for (uint32_t k = 0; k < render_pass_info->pSubpasses[j].inputAttachmentCount; ++k) {
615                 auto &attachment_ref = subpass.pInputAttachments[k];
616                 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
617                     auto image_view = attachments[attachment_ref.attachment];
618                     auto view_state = Get<IMAGE_VIEW_STATE>(image_view);
619 
620                     if (view_state) {
621                         ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, *view_state,
622                                                                              framebuffer, render_pass, attachment_ref.attachment,
623                                                                              "input attachment layout");
624                     }
625                 }
626             }
627 
628             for (uint32_t k = 0; k < render_pass_info->pSubpasses[j].colorAttachmentCount; ++k) {
629                 auto &attachment_ref = subpass.pColorAttachments[k];
630                 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
631                     auto image_view = attachments[attachment_ref.attachment];
632                     auto view_state = Get<IMAGE_VIEW_STATE>(image_view);
633 
634                     if (view_state) {
635                         ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, *view_state,
636                                                                              framebuffer, render_pass, attachment_ref.attachment,
637                                                                              "color attachment layout");
638                         if (subpass.pResolveAttachments) {
639                             ValidateRenderPassLayoutAgainstFramebufferImageUsage(
640                                 rp_version, attachment_ref.layout, *view_state, framebuffer, render_pass, attachment_ref.attachment,
641                                 "resolve attachment layout");
642                         }
643                     }
644                 }
645             }
646 
647             if (render_pass_info->pSubpasses[j].pDepthStencilAttachment) {
648                 auto &attachment_ref = *subpass.pDepthStencilAttachment;
649                 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
650                     auto image_view = attachments[attachment_ref.attachment];
651                     auto view_state = Get<IMAGE_VIEW_STATE>(image_view);
652 
653                     if (view_state) {
654                         ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, *view_state,
655                                                                              framebuffer, render_pass, attachment_ref.attachment,
656                                                                              "input attachment layout");
657                     }
658                 }
659             }
660         }
661     }
662     return skip;
663 }
664 
TransitionAttachmentRefLayout(CMD_BUFFER_STATE * pCB,FRAMEBUFFER_STATE * pFramebuffer,const safe_VkAttachmentReference2 & ref)665 void CoreChecks::TransitionAttachmentRefLayout(CMD_BUFFER_STATE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
666                                                const safe_VkAttachmentReference2 &ref) {
667     if (ref.attachment != VK_ATTACHMENT_UNUSED) {
668         IMAGE_VIEW_STATE *image_view = pCB->GetActiveAttachmentImageViewState(ref.attachment);
669         if (image_view) {
670             VkImageLayout stencil_layout = kInvalidLayout;
671             const auto *attachment_reference_stencil_layout = LvlFindInChain<VkAttachmentReferenceStencilLayout>(ref.pNext);
672             if (attachment_reference_stencil_layout) {
673                 stencil_layout = attachment_reference_stencil_layout->stencilLayout;
674             }
675 
676             pCB->SetImageViewLayout(*image_view, ref.layout, stencil_layout);
677         }
678     }
679 }
680 
TransitionSubpassLayouts(CMD_BUFFER_STATE * pCB,const RENDER_PASS_STATE * render_pass_state,const int subpass_index,FRAMEBUFFER_STATE * framebuffer_state)681 void CoreChecks::TransitionSubpassLayouts(CMD_BUFFER_STATE *pCB, const RENDER_PASS_STATE *render_pass_state,
682                                           const int subpass_index, FRAMEBUFFER_STATE *framebuffer_state) {
683     assert(render_pass_state);
684 
685     if (framebuffer_state) {
686         auto const &subpass = render_pass_state->createInfo.pSubpasses[subpass_index];
687         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
688             TransitionAttachmentRefLayout(pCB, framebuffer_state, subpass.pInputAttachments[j]);
689         }
690         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
691             TransitionAttachmentRefLayout(pCB, framebuffer_state, subpass.pColorAttachments[j]);
692         }
693         if (subpass.pDepthStencilAttachment) {
694             TransitionAttachmentRefLayout(pCB, framebuffer_state, *subpass.pDepthStencilAttachment);
695         }
696     }
697 }
698 
699 // Transition the layout state for renderpass attachments based on the BeginRenderPass() call. This includes:
700 // 1. Transition into initialLayout state
701 // 2. Transition from initialLayout to layout used in subpass 0
TransitionBeginRenderPassLayouts(CMD_BUFFER_STATE * cb_state,const RENDER_PASS_STATE * render_pass_state,FRAMEBUFFER_STATE * framebuffer_state)702 void CoreChecks::TransitionBeginRenderPassLayouts(CMD_BUFFER_STATE *cb_state, const RENDER_PASS_STATE *render_pass_state,
703                                                   FRAMEBUFFER_STATE *framebuffer_state) {
704     // First record expected initialLayout as a potential initial layout usage.
705     auto const rpci = render_pass_state->createInfo.ptr();
706     for (uint32_t i = 0; i < rpci->attachmentCount; ++i) {
707         auto *view_state = cb_state->GetActiveAttachmentImageViewState(i);
708         if (view_state) {
709             IMAGE_STATE *image_state = view_state->image_state.get();
710             const auto initial_layout = rpci->pAttachments[i].initialLayout;
711             const auto *attachment_description_stencil_layout =
712                 LvlFindInChain<VkAttachmentDescriptionStencilLayout>(rpci->pAttachments[i].pNext);
713             if (attachment_description_stencil_layout) {
714                 const auto stencil_initial_layout = attachment_description_stencil_layout->stencilInitialLayout;
715                 VkImageSubresourceRange sub_range = view_state->normalized_subresource_range;
716                 sub_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
717                 cb_state->SetImageInitialLayout(*image_state, sub_range, initial_layout);
718                 sub_range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
719                 cb_state->SetImageInitialLayout(*image_state, sub_range, stencil_initial_layout);
720             } else {
721                 cb_state->SetImageInitialLayout(*image_state, view_state->normalized_subresource_range, initial_layout);
722             }
723         }
724     }
725     // Now transition for first subpass (index 0)
726     TransitionSubpassLayouts(cb_state, render_pass_state, 0, framebuffer_state);
727 }
728 
VerifyAspectsPresent(VkImageAspectFlags aspect_mask,VkFormat format)729 bool VerifyAspectsPresent(VkImageAspectFlags aspect_mask, VkFormat format) {
730     if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
731         if (!(FormatIsColor(format) || FormatIsMultiplane(format))) return false;
732     }
733     if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
734         if (!FormatHasDepth(format)) return false;
735     }
736     if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
737         if (!FormatHasStencil(format)) return false;
738     }
739     if (0 != (aspect_mask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT))) {
740         if (FormatPlaneCount(format) == 1) return false;
741     }
742     return true;
743 }
744 
745 // There is a table in the Vulkan spec to list all formats that implicitly require YCbCr conversion,
746 // but some features/extensions can explicitly turn that restriction off
747 // The implicit check is done in format utils, while feature checks are done here in CoreChecks
FormatRequiresYcbcrConversionExplicitly(const VkFormat format) const748 bool CoreChecks::FormatRequiresYcbcrConversionExplicitly(const VkFormat format) const {
749     if (format == VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 &&
750         enabled_features.rgba10x6_formats_features.formatRgba10x6WithoutYCbCrSampler) {
751         return false;
752     }
753     return FormatRequiresYcbcrConversion(format);
754 }
755 
756 // Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags.
ValidateBarrierLayoutToImageUsage(const Location & loc,VkImage image,VkImageLayout layout,VkImageUsageFlags usage_flags) const757 bool CoreChecks::ValidateBarrierLayoutToImageUsage(const Location &loc, VkImage image, VkImageLayout layout,
758                                                    VkImageUsageFlags usage_flags) const {
759     bool skip = false;
760     bool is_error = false;
761     switch (layout) {
762         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
763             is_error = ((usage_flags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0);
764             break;
765         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
766             is_error = ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0);
767             break;
768         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
769             is_error = ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0);
770             break;
771         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
772             is_error = ((usage_flags & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0);
773             break;
774         case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
775             is_error = ((usage_flags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0);
776             break;
777         case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
778             is_error = ((usage_flags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0);
779             break;
780         case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV:
781             is_error = ((usage_flags & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) == 0);
782             break;
783         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
784             is_error = ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0);
785             break;
786         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
787             is_error = ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0);
788             break;
789         default:
790             // Other VkImageLayout values do not have VUs defined in this context.
791             break;
792     }
793 
794     if (is_error) {
795         const auto &vuid = sync_vuid_maps::GetBadImageLayoutVUID(loc, layout);
796 
797         skip |=
798             LogError(image, vuid, "%s Image barrier Layout=%s is not compatible with %s usage flags 0x%" PRIx32 ".",
799                      loc.Message().c_str(), string_VkImageLayout(layout), report_data->FormatHandle(image).c_str(), usage_flags);
800     }
801     return skip;
802 }
803 
804 // Verify image barriers are compatible with the images they reference.
805 template <typename ImageBarrier>
ValidateBarriersToImages(const Location & outer_loc,const CMD_BUFFER_STATE * cb_state,uint32_t imageMemoryBarrierCount,const ImageBarrier * pImageMemoryBarriers) const806 bool CoreChecks::ValidateBarriersToImages(const Location &outer_loc, const CMD_BUFFER_STATE *cb_state,
807                                           uint32_t imageMemoryBarrierCount, const ImageBarrier *pImageMemoryBarriers) const {
808     bool skip = false;
809     using sync_vuid_maps::GetImageBarrierVUID;
810     using sync_vuid_maps::ImageError;
811 
812     // Scoreboard for duplicate layout transition barriers within the list
813     // Pointers retained in the scoreboard only have the lifetime of *this* call (i.e. within the scope of the API call)
814     const CommandBufferImageLayoutMap &current_map = cb_state->GetImageSubresourceLayoutMap();
815     CommandBufferImageLayoutMap layout_updates;
816 
817     for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
818         auto loc = outer_loc.dot(Field::pImageMemoryBarriers, i);
819         const auto &img_barrier = pImageMemoryBarriers[i];
820 
821         auto image_state = Get<IMAGE_STATE>(img_barrier.image);
822         if (image_state) {
823             VkImageUsageFlags usage_flags = image_state->createInfo.usage;
824             skip |=
825                 ValidateBarrierLayoutToImageUsage(loc.dot(Field::oldLayout), img_barrier.image, img_barrier.oldLayout, usage_flags);
826             skip |=
827                 ValidateBarrierLayoutToImageUsage(loc.dot(Field::newLayout), img_barrier.image, img_barrier.newLayout, usage_flags);
828 
829             // Make sure layout is able to be transitioned, currently only presented shared presentable images are locked
830             if (image_state->layout_locked) {
831                 // TODO: Add unique id for error when available
832                 skip |= LogError(
833                     img_barrier.image, 0,
834                     "%s Attempting to transition shared presentable %s"
835                     " from layout %s to layout %s, but image has already been presented and cannot have its layout transitioned.",
836                     loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
837                     string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(img_barrier.newLayout));
838             }
839 
840             const VkImageCreateInfo &image_create_info = image_state->createInfo;
841             const VkFormat image_format = image_create_info.format;
842             const VkImageAspectFlags aspect_mask = img_barrier.subresourceRange.aspectMask;
843             // For a Depth/Stencil image both aspects MUST be set
844             auto image_loc = loc.dot(Field::image);
845             if (FormatIsDepthAndStencil(image_format)) {
846                 if (enabled_features.core12.separateDepthStencilLayouts) {
847                     if (!(aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
848                         auto vuid = GetImageBarrierVUID(loc, ImageError::kNotDepthOrStencilAspect);
849                         skip |= LogError(img_barrier.image, vuid,
850                                          "%s references %s of format %s that must have either the depth or stencil "
851                                          "aspects set, but its aspectMask is 0x%" PRIx32 ".",
852                                          image_loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
853                                          string_VkFormat(image_format), aspect_mask);
854                     }
855                 } else {
856                     auto const ds_mask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
857                     if ((aspect_mask & ds_mask) != (ds_mask)) {
858                         auto error = IsExtEnabled(device_extensions.vk_khr_separate_depth_stencil_layouts)
859                                          ? ImageError::kNotSeparateDepthAndStencilAspect
860                                          : ImageError::kNotDepthAndStencilAspect;
861                         auto vuid = GetImageBarrierVUID(image_loc, error);
862                         skip |= LogError(img_barrier.image, vuid,
863                                          "%s references %s of format %s that must have the depth and stencil "
864                                          "aspects set, but its aspectMask is 0x%" PRIx32 ".",
865                                          image_loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
866                                          string_VkFormat(image_format), aspect_mask);
867                     }
868                 }
869             }
870 
871             if (img_barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
872                 // TODO: Set memory invalid which is in mem_tracker currently
873             } else if (!QueueFamilyIsExternal(img_barrier.srcQueueFamilyIndex)) {
874                 auto &write_subresource_map = layout_updates[image_state.get()];
875                 bool new_write = false;
876                 if (!write_subresource_map) {
877                     write_subresource_map.emplace(*image_state);
878                     new_write = true;
879                 }
880                 const auto &current_subresource_map = current_map.find(image_state.get());
881                 const auto &read_subresource_map = (new_write && current_subresource_map != current_map.end())
882                                                        ? (*current_subresource_map).second
883                                                        : write_subresource_map;
884 
885                 bool subres_skip = false;
886                 // Validate aspects in isolation.
887                 // This is required when handling separate depth-stencil layouts.
888                 for (uint32_t aspect_index = 0; aspect_index < 32; aspect_index++) {
889                     VkImageAspectFlags test_aspect = 1u << aspect_index;
890                     if ((img_barrier.subresourceRange.aspectMask & test_aspect) == 0) {
891                         continue;
892                     }
893 
894                     LayoutUseCheckAndMessage layout_check(&read_subresource_map, test_aspect);
895                     auto normalized_isr = image_state->NormalizeSubresourceRange(img_barrier.subresourceRange);
896                     normalized_isr.aspectMask = test_aspect;
897                     // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to the next "constant value" range
898                     for (auto pos = read_subresource_map->Find(normalized_isr); !(pos.AtEnd()) && !subres_skip;
899                          pos.IncrementInterval()) {
900                         const auto &value = *pos;
901                         auto old_layout = NormalizeSynchronization2Layout(test_aspect, img_barrier.oldLayout);
902                         if (!layout_check.Check(value.subresource, old_layout, value.current_layout, value.initial_layout)) {
903                             const auto &vuid = GetImageBarrierVUID(loc, ImageError::kConflictingLayout);
904                             subres_skip =
905                                 LogError(cb_state->commandBuffer(), vuid,
906                                          "%s %s cannot transition the layout of aspect=%d level=%d layer=%d from %s when the "
907                                          "%s layout is %s.",
908                                          loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
909                                          value.subresource.aspectMask, value.subresource.mipLevel, value.subresource.arrayLayer,
910                                          string_VkImageLayout(img_barrier.oldLayout), layout_check.message,
911                                          string_VkImageLayout(layout_check.layout));
912                         }
913                     }
914                     write_subresource_map->SetSubresourceRangeLayout(*cb_state, normalized_isr, img_barrier.newLayout);
915                 }
916                 skip |= subres_skip;
917             }
918 
919             // checks color format and (single-plane or non-disjoint)
920             // if ycbcr extension is not supported then single-plane and non-disjoint are always both true
921             if ((FormatIsColor(image_format) == true) &&
922                 ((FormatIsMultiplane(image_format) == false) || (image_state->disjoint == false))) {
923                 if (aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT) {
924                     auto error = IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion) ? ImageError::kNotColorAspect
925                                                                                                  : ImageError::kNotColorAspectYcbcr;
926                     const auto &vuid = GetImageBarrierVUID(loc, error);
927                     skip |= LogError(img_barrier.image, vuid,
928                                      "%s references %s of format %s that must be only VK_IMAGE_ASPECT_COLOR_BIT, "
929                                      "but its aspectMask is 0x%" PRIx32 ".",
930                                      image_loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
931                                      string_VkFormat(image_format), aspect_mask);
932                 }
933             }
934 
935             VkImageAspectFlags valid_disjoint_mask =
936                 VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT | VK_IMAGE_ASPECT_COLOR_BIT;
937             if ((FormatIsMultiplane(image_format) == true) && (image_state->disjoint == true) &&
938                 ((aspect_mask & valid_disjoint_mask) == 0)) {
939                 const auto &vuid = GetImageBarrierVUID(image_loc, ImageError::kBadMultiplanarAspect);
940                 skip |= LogError(img_barrier.image, vuid,
941                                  "%s references %s of format %s has aspectMask (0x%" PRIx32
942                                  ") but needs to include either an VK_IMAGE_ASPECT_PLANE_*_BIT or VK_IMAGE_ASPECT_COLOR_BIT.",
943                                  image_loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
944                                  string_VkFormat(image_format), aspect_mask);
945             }
946 
947             if ((FormatPlaneCount(image_format) == 2) && ((aspect_mask & VK_IMAGE_ASPECT_PLANE_2_BIT) != 0)) {
948                 const auto &vuid = GetImageBarrierVUID(image_loc, ImageError::kBadPlaneCount);
949                 skip |= LogError(img_barrier.image, vuid,
950                                  "%s references %s of format %s has only two planes but included "
951                                  "VK_IMAGE_ASPECT_PLANE_2_BIT in its aspectMask (0x%" PRIx32 ").",
952                                  image_loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
953                                  string_VkFormat(image_format), aspect_mask);
954             }
955         }
956     }
957     return skip;
958 }
959 
960 template <typename Barrier, typename TransferBarrier>
ValidateQFOTransferBarrierUniqueness(const Location & loc,const CMD_BUFFER_STATE * cb_state,const Barrier & barrier,const QFOTransferBarrierSets<TransferBarrier> & barrier_sets) const961 bool CoreChecks::ValidateQFOTransferBarrierUniqueness(const Location &loc, const CMD_BUFFER_STATE *cb_state, const Barrier &barrier,
962                                                       const QFOTransferBarrierSets<TransferBarrier> &barrier_sets) const {
963     bool skip = false;
964     const char *handle_name = TransferBarrier::HandleName();
965     const char *transfer_type = nullptr;
966     if (!IsTransferOp(barrier)) {
967         return skip;
968     }
969     const TransferBarrier *barrier_record = nullptr;
970     if (cb_state->IsReleaseOp(barrier) && !QueueFamilyIsExternal(barrier.dstQueueFamilyIndex)) {
971         const auto found = barrier_sets.release.find(barrier);
972         if (found != barrier_sets.release.cend()) {
973             barrier_record = &(*found);
974             transfer_type = "releasing";
975         }
976     } else if (cb_state->IsAcquireOp(barrier) && !QueueFamilyIsExternal(barrier.srcQueueFamilyIndex)) {
977         const auto found = barrier_sets.acquire.find(barrier);
978         if (found != barrier_sets.acquire.cend()) {
979             barrier_record = &(*found);
980             transfer_type = "acquiring";
981         }
982     }
983     if (barrier_record != nullptr) {
984         skip |=
985             LogWarning(cb_state->commandBuffer(), TransferBarrier::ErrMsgDuplicateQFOInCB(),
986                        "%s %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32 " to dstQueueFamilyIndex %" PRIu32
987                        " duplicates existing barrier recorded in this command buffer.",
988                        loc.Message().c_str(), transfer_type, handle_name, report_data->FormatHandle(barrier_record->handle).c_str(),
989                        barrier_record->srcQueueFamilyIndex, barrier_record->dstQueueFamilyIndex);
990     }
991     return skip;
992 }
993 
BarrierTypedHandle(const VkImageMemoryBarrier & barrier)994 VulkanTypedHandle BarrierTypedHandle(const VkImageMemoryBarrier &barrier) {
995     return VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage);
996 }
997 
BarrierTypedHandle(const VkImageMemoryBarrier2KHR & barrier)998 VulkanTypedHandle BarrierTypedHandle(const VkImageMemoryBarrier2KHR &barrier) {
999     return VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage);
1000 }
1001 
BarrierHandleState(const ValidationStateTracker & device_state,const VkImageMemoryBarrier & barrier)1002 std::shared_ptr<const IMAGE_STATE> BarrierHandleState(const ValidationStateTracker &device_state,
1003                                                       const VkImageMemoryBarrier &barrier) {
1004     return device_state.Get<IMAGE_STATE>(barrier.image);
1005 }
1006 
BarrierHandleState(const ValidationStateTracker & device_state,const VkImageMemoryBarrier2KHR & barrier)1007 std::shared_ptr<const IMAGE_STATE> BarrierHandleState(const ValidationStateTracker &device_state,
1008                                                       const VkImageMemoryBarrier2KHR &barrier) {
1009     return device_state.Get<IMAGE_STATE>(barrier.image);
1010 }
1011 
BarrierTypedHandle(const VkBufferMemoryBarrier & barrier)1012 VulkanTypedHandle BarrierTypedHandle(const VkBufferMemoryBarrier &barrier) {
1013     return VulkanTypedHandle(barrier.buffer, kVulkanObjectTypeBuffer);
1014 }
1015 
BarrierTypedHandle(const VkBufferMemoryBarrier2KHR & barrier)1016 VulkanTypedHandle BarrierTypedHandle(const VkBufferMemoryBarrier2KHR &barrier) {
1017     return VulkanTypedHandle(barrier.buffer, kVulkanObjectTypeBuffer);
1018 }
1019 
BarrierHandleState(const ValidationStateTracker & device_state,const VkBufferMemoryBarrier & barrier)1020 const std::shared_ptr<const BUFFER_STATE> BarrierHandleState(const ValidationStateTracker &device_state,
1021                                                              const VkBufferMemoryBarrier &barrier) {
1022     return device_state.Get<BUFFER_STATE>(barrier.buffer);
1023 }
1024 
BarrierHandleState(const ValidationStateTracker & device_state,const VkBufferMemoryBarrier2KHR & barrier)1025 std::shared_ptr<const BUFFER_STATE> BarrierHandleState(const ValidationStateTracker &device_state,
1026                                                        const VkBufferMemoryBarrier2KHR &barrier) {
1027     return device_state.Get<BUFFER_STATE>(barrier.buffer);
1028 }
1029 
1030 template <typename Barrier, typename TransferBarrier>
RecordBarrierValidationInfo(const Location & loc,CMD_BUFFER_STATE * cb_state,const Barrier & barrier,QFOTransferBarrierSets<TransferBarrier> & barrier_sets)1031 void CoreChecks::RecordBarrierValidationInfo(const Location &loc, CMD_BUFFER_STATE *cb_state, const Barrier &barrier,
1032                                              QFOTransferBarrierSets<TransferBarrier> &barrier_sets) {
1033     if (IsTransferOp(barrier)) {
1034         if (cb_state->IsReleaseOp(barrier) && !QueueFamilyIsExternal(barrier.dstQueueFamilyIndex)) {
1035             barrier_sets.release.emplace(barrier);
1036         } else if (cb_state->IsAcquireOp(barrier) && !QueueFamilyIsExternal(barrier.srcQueueFamilyIndex)) {
1037             barrier_sets.acquire.emplace(barrier);
1038         }
1039     }
1040 
1041     // 7.7.4: If the values of srcQueueFamilyIndex and dstQueueFamilyIndex are equal, no ownership transfer is performed, and the
1042     // barrier operates as if they were both set to VK_QUEUE_FAMILY_IGNORED.
1043     const uint32_t src_queue_family = barrier.srcQueueFamilyIndex;
1044     const uint32_t dst_queue_family = barrier.dstQueueFamilyIndex;
1045     const bool is_ownership_transfer = src_queue_family != dst_queue_family;
1046 
1047     if (is_ownership_transfer) {
1048         // Only enqueue submit time check if it is needed. If more submit time checks are added, change the criteria
1049         // TODO create a better named list, or rename the submit time lists to something that matches the broader usage...
1050         auto handle_state = BarrierHandleState(*this, barrier);
1051         bool mode_concurrent = handle_state ? handle_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT : false;
1052         if (!mode_concurrent) {
1053             const auto typed_handle = BarrierTypedHandle(barrier);
1054             core_error::LocationCapture loc_capture(loc);
1055             cb_state->queue_submit_functions.emplace_back(
1056                 [loc_capture, typed_handle, src_queue_family, dst_queue_family](
1057                     const ValidationStateTracker &device_data, const QUEUE_STATE &queue_state, const CMD_BUFFER_STATE &cb_state) {
1058                     return ValidateConcurrentBarrierAtSubmit(loc_capture.Get(), device_data, queue_state, cb_state, typed_handle,
1059                                                              src_queue_family, dst_queue_family);
1060                 });
1061         }
1062     }
1063 }
1064 
1065 // Verify image barrier image state and that the image is consistent with FB image
1066 template <typename ImgBarrier>
ValidateImageBarrierAttachment(const Location & loc,CMD_BUFFER_STATE const * cb_state,const FRAMEBUFFER_STATE * framebuffer,uint32_t active_subpass,const safe_VkSubpassDescription2 & sub_desc,const VkRenderPass rp_handle,const ImgBarrier & img_barrier,const CMD_BUFFER_STATE * primary_cb_state) const1067 bool CoreChecks::ValidateImageBarrierAttachment(const Location &loc, CMD_BUFFER_STATE const *cb_state,
1068                                                 const FRAMEBUFFER_STATE *framebuffer, uint32_t active_subpass,
1069                                                 const safe_VkSubpassDescription2 &sub_desc, const VkRenderPass rp_handle,
1070                                                 const ImgBarrier &img_barrier, const CMD_BUFFER_STATE *primary_cb_state) const {
1071     using sync_vuid_maps::GetImageBarrierVUID;
1072     using sync_vuid_maps::ImageError;
1073 
1074     bool skip = false;
1075     const auto *fb_state = framebuffer;
1076     assert(fb_state);
1077     const auto img_bar_image = img_barrier.image;
1078     bool image_match = false;
1079     bool sub_image_found = false;  // Do we find a corresponding subpass description
1080     VkImageLayout sub_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
1081     uint32_t attach_index = 0;
1082     // Verify that a framebuffer image matches barrier image
1083     const auto attachment_count = fb_state->createInfo.attachmentCount;
1084     for (uint32_t attachment = 0; attachment < attachment_count; ++attachment) {
1085         auto view_state = primary_cb_state ? primary_cb_state->GetActiveAttachmentImageViewState(attachment) : cb_state->GetActiveAttachmentImageViewState(attachment);
1086         if (view_state && (img_bar_image == view_state->create_info.image)) {
1087             image_match = true;
1088             attach_index = attachment;
1089             break;
1090         }
1091     }
1092     if (image_match) {  // Make sure subpass is referring to matching attachment
1093         if (sub_desc.pDepthStencilAttachment && sub_desc.pDepthStencilAttachment->attachment == attach_index) {
1094             sub_image_layout = sub_desc.pDepthStencilAttachment->layout;
1095             sub_image_found = true;
1096         }
1097         if (!sub_image_found && IsExtEnabled(device_extensions.vk_khr_depth_stencil_resolve)) {
1098             const auto *resolve = LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(sub_desc.pNext);
1099             if (resolve && resolve->pDepthStencilResolveAttachment &&
1100                 resolve->pDepthStencilResolveAttachment->attachment == attach_index) {
1101                 sub_image_layout = resolve->pDepthStencilResolveAttachment->layout;
1102                 sub_image_found = true;
1103             }
1104         }
1105         if (!sub_image_found) {
1106             for (uint32_t j = 0; j < sub_desc.colorAttachmentCount; ++j) {
1107                 if (sub_desc.pColorAttachments && sub_desc.pColorAttachments[j].attachment == attach_index) {
1108                     sub_image_layout = sub_desc.pColorAttachments[j].layout;
1109                     sub_image_found = true;
1110                     break;
1111                 }
1112                 if (!sub_image_found && sub_desc.pResolveAttachments &&
1113                     sub_desc.pResolveAttachments[j].attachment == attach_index) {
1114                     sub_image_layout = sub_desc.pResolveAttachments[j].layout;
1115                     sub_image_found = true;
1116                     break;
1117                 }
1118             }
1119         }
1120         if (!sub_image_found) {
1121             auto img_loc = loc.dot(Field::image);
1122             const auto &vuid = GetImageBarrierVUID(img_loc, ImageError::kRenderPassMismatch);
1123             skip |=
1124                 LogError(rp_handle, vuid,
1125                          "%s Barrier for %s is not referenced by the VkSubpassDescription for active subpass (%d) of current %s.",
1126                          img_loc.Message().c_str(), report_data->FormatHandle(img_bar_image).c_str(), active_subpass,
1127                          report_data->FormatHandle(rp_handle).c_str());
1128         }
1129     } else {  // !image_match
1130         auto img_loc = loc.dot(Field::image);
1131         const auto &vuid = GetImageBarrierVUID(img_loc, ImageError::kRenderPassMismatch);
1132         skip |= LogError(fb_state->framebuffer(), vuid, "%s Barrier for %s does not match an image from the current %s.",
1133                          img_loc.Message().c_str(), report_data->FormatHandle(img_bar_image).c_str(),
1134                          report_data->FormatHandle(fb_state->framebuffer()).c_str());
1135     }
1136     if (img_barrier.oldLayout != img_barrier.newLayout) {
1137         auto layout_loc = loc.dot(Field::oldLayout);
1138         const auto &vuid = GetImageBarrierVUID(layout_loc, ImageError::kRenderPassLayoutChange);
1139         skip |= LogError(cb_state->commandBuffer(), vuid,
1140                          "%s As the Image Barrier for %s is being executed within a render pass instance, oldLayout must "
1141                          "equal newLayout yet they are %s and %s.",
1142                          layout_loc.Message().c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
1143                          string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(img_barrier.newLayout));
1144     } else {
1145         if (sub_image_found && sub_image_layout != img_barrier.oldLayout) {
1146             LogObjectList objlist(rp_handle);
1147             objlist.add(img_bar_image);
1148             auto layout_loc = loc.dot(Field::oldLayout);
1149             const auto &vuid = GetImageBarrierVUID(layout_loc, ImageError::kRenderPassLayoutChange);
1150             skip |= LogError(objlist, vuid,
1151                              "%s Barrier for %s is referenced by the VkSubpassDescription for active "
1152                              "subpass (%d) of current %s as having layout %s, but image barrier has layout %s.",
1153                              layout_loc.Message().c_str(), report_data->FormatHandle(img_bar_image).c_str(), active_subpass,
1154                              report_data->FormatHandle(rp_handle).c_str(), string_VkImageLayout(sub_image_layout),
1155                              string_VkImageLayout(img_barrier.oldLayout));
1156         }
1157     }
1158     return skip;
1159 }
1160 // explictly instantiate so these can be used in core_validation.cpp
1161 template bool CoreChecks::ValidateImageBarrierAttachment(const Location &loc, CMD_BUFFER_STATE const *cb_state,
1162                                                          const FRAMEBUFFER_STATE *framebuffer, uint32_t active_subpass,
1163                                                          const safe_VkSubpassDescription2 &sub_desc, const VkRenderPass rp_handle,
1164                                                          const VkImageMemoryBarrier &img_barrier,
1165                                                          const CMD_BUFFER_STATE *primary_cb_state) const;
1166 template bool CoreChecks::ValidateImageBarrierAttachment(const Location &loc, CMD_BUFFER_STATE const *cb_state,
1167                                                          const FRAMEBUFFER_STATE *framebuffer, uint32_t active_subpass,
1168                                                          const safe_VkSubpassDescription2 &sub_desc, const VkRenderPass rp_handle,
1169                                                          const VkImageMemoryBarrier2KHR &img_barrier,
1170                                                          const CMD_BUFFER_STATE *primary_cb_state) const;
1171 
1172 template <typename ImgBarrier>
EnqueueSubmitTimeValidateImageBarrierAttachment(const Location & loc,CMD_BUFFER_STATE * cb_state,const ImgBarrier & barrier)1173 void CoreChecks::EnqueueSubmitTimeValidateImageBarrierAttachment(const Location &loc, CMD_BUFFER_STATE *cb_state,
1174                                                                  const ImgBarrier &barrier) {
1175     // Secondary CBs can have null framebuffer so queue up validation in that case 'til FB is known
1176     if ((cb_state->activeRenderPass) && (VK_NULL_HANDLE == cb_state->activeFramebuffer) &&
1177         (VK_COMMAND_BUFFER_LEVEL_SECONDARY == cb_state->createInfo.level)) {
1178         const auto active_subpass = cb_state->activeSubpass;
1179         const auto rp_state = cb_state->activeRenderPass;
1180         const auto &sub_desc = rp_state->createInfo.pSubpasses[active_subpass];
1181         // Secondary CB case w/o FB specified delay validation
1182         auto *this_ptr = this;  // Required for older compilers with c++20 compatibility
1183         core_error::LocationCapture loc_capture(loc);
1184         const auto render_pass = rp_state->renderPass();
1185         cb_state->cmd_execute_commands_functions.emplace_back(
1186             [this_ptr, loc_capture, active_subpass, sub_desc, render_pass, barrier](
1187                 const CMD_BUFFER_STATE &secondary_cb, const CMD_BUFFER_STATE *primary_cb, const FRAMEBUFFER_STATE *fb) {
1188                 return this_ptr->ValidateImageBarrierAttachment(loc_capture.Get(), &secondary_cb, fb, active_subpass, sub_desc,
1189                                                                 render_pass, barrier, primary_cb);
1190             });
1191     }
1192 }
1193 
RecordBarriers(Func func_name,CMD_BUFFER_STATE * cb_state,uint32_t bufferBarrierCount,const VkBufferMemoryBarrier * pBufferMemBarriers,uint32_t imageMemBarrierCount,const VkImageMemoryBarrier * pImageMemBarriers)1194 void CoreChecks::RecordBarriers(Func func_name, CMD_BUFFER_STATE *cb_state, uint32_t bufferBarrierCount,
1195                                 const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
1196                                 const VkImageMemoryBarrier *pImageMemBarriers) {
1197     for (uint32_t i = 0; i < bufferBarrierCount; i++) {
1198         Location loc(func_name, Struct::VkBufferMemoryBarrier, Field::pBufferMemoryBarriers, i);
1199         RecordBarrierValidationInfo(loc, cb_state, pBufferMemBarriers[i], cb_state->qfo_transfer_buffer_barriers);
1200     }
1201     for (uint32_t i = 0; i < imageMemBarrierCount; i++) {
1202         Location loc(func_name, Struct::VkImageMemoryBarrier, Field::pImageMemoryBarriers, i);
1203         const auto &img_barrier = pImageMemBarriers[i];
1204         RecordBarrierValidationInfo(loc, cb_state, img_barrier, cb_state->qfo_transfer_image_barriers);
1205         EnqueueSubmitTimeValidateImageBarrierAttachment(loc, cb_state, img_barrier);
1206     }
1207 }
1208 
RecordBarriers(Func func_name,CMD_BUFFER_STATE * cb_state,const VkDependencyInfoKHR & dep_info)1209 void CoreChecks::RecordBarriers(Func func_name, CMD_BUFFER_STATE *cb_state, const VkDependencyInfoKHR &dep_info) {
1210     for (uint32_t i = 0; i < dep_info.bufferMemoryBarrierCount; i++) {
1211         Location loc(func_name, Struct::VkBufferMemoryBarrier2KHR, Field::pBufferMemoryBarriers, i);
1212         RecordBarrierValidationInfo(loc, cb_state, dep_info.pBufferMemoryBarriers[i], cb_state->qfo_transfer_buffer_barriers);
1213     }
1214     for (uint32_t i = 0; i < dep_info.imageMemoryBarrierCount; i++) {
1215         Location loc(func_name, Struct::VkImageMemoryBarrier2KHR, Field::pImageMemoryBarriers, i);
1216         const auto &img_barrier = dep_info.pImageMemoryBarriers[i];
1217         RecordBarrierValidationInfo(loc, cb_state, img_barrier, cb_state->qfo_transfer_image_barriers);
1218         EnqueueSubmitTimeValidateImageBarrierAttachment(loc, cb_state, img_barrier);
1219     }
1220 }
1221 
1222 template <typename TransferBarrier, typename Scoreboard>
ValidateAndUpdateQFOScoreboard(const debug_report_data * report_data,const CMD_BUFFER_STATE * cb_state,const char * operation,const TransferBarrier & barrier,Scoreboard * scoreboard) const1223 bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const CMD_BUFFER_STATE *cb_state,
1224                                                 const char *operation, const TransferBarrier &barrier,
1225                                                 Scoreboard *scoreboard) const {
1226     // Record to the scoreboard or report that we have a duplication
1227     bool skip = false;
1228     auto inserted = scoreboard->emplace(barrier, cb_state);
1229     if (!inserted.second && inserted.first->second != cb_state) {
1230         // This is a duplication (but don't report duplicates from the same CB, as we do that at record time
1231         LogObjectList objlist(cb_state->commandBuffer());
1232         objlist.add(barrier.handle);
1233         objlist.add(inserted.first->second->commandBuffer());
1234         skip = LogWarning(objlist, TransferBarrier::ErrMsgDuplicateQFOInSubmit(),
1235                           "%s: %s %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1236                           " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier submitted in this batch from %s.",
1237                           "vkQueueSubmit()", TransferBarrier::BarrierName(), operation, TransferBarrier::HandleName(),
1238                           report_data->FormatHandle(barrier.handle).c_str(), barrier.srcQueueFamilyIndex,
1239                           barrier.dstQueueFamilyIndex, report_data->FormatHandle(inserted.first->second->commandBuffer()).c_str());
1240     }
1241     return skip;
1242 }
1243 
1244 template <typename TransferBarrier>
ValidateQueuedQFOTransferBarriers(const CMD_BUFFER_STATE * cb_state,QFOTransferCBScoreboards<TransferBarrier> * scoreboards,const GlobalQFOTransferBarrierMap<TransferBarrier> & global_release_barriers) const1245 bool CoreChecks::ValidateQueuedQFOTransferBarriers(
1246     const CMD_BUFFER_STATE *cb_state, QFOTransferCBScoreboards<TransferBarrier> *scoreboards,
1247     const GlobalQFOTransferBarrierMap<TransferBarrier> &global_release_barriers) const {
1248     bool skip = false;
1249     const auto &cb_barriers = cb_state->GetQFOBarrierSets(TransferBarrier());
1250     const char *barrier_name = TransferBarrier::BarrierName();
1251     const char *handle_name = TransferBarrier::HandleName();
1252     // No release should have an extant duplicate (WARNING)
1253     for (const auto &release : cb_barriers.release) {
1254         // Check the global pending release barriers
1255         const auto set_it = global_release_barriers.find(release.handle);
1256         if (set_it != global_release_barriers.cend()) {
1257             const QFOTransferBarrierSet<TransferBarrier> &set_for_handle = set_it->second;
1258             const auto found = set_for_handle.find(release);
1259             if (found != set_for_handle.cend()) {
1260                 skip |= LogWarning(cb_state->commandBuffer(), TransferBarrier::ErrMsgDuplicateQFOSubmitted(),
1261                                    "%s: %s releasing queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1262                                    " to dstQueueFamilyIndex %" PRIu32
1263                                    " duplicates existing barrier queued for execution, without intervening acquire operation.",
1264                                    "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(found->handle).c_str(),
1265                                    found->srcQueueFamilyIndex, found->dstQueueFamilyIndex);
1266             }
1267         }
1268         skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "releasing", release, &scoreboards->release);
1269     }
1270     // Each acquire must have a matching release (ERROR)
1271     for (const auto &acquire : cb_barriers.acquire) {
1272         const auto set_it = global_release_barriers.find(acquire.handle);
1273         bool matching_release_found = false;
1274         if (set_it != global_release_barriers.cend()) {
1275             const QFOTransferBarrierSet<TransferBarrier> &set_for_handle = set_it->second;
1276             matching_release_found = set_for_handle.find(acquire) != set_for_handle.cend();
1277         }
1278         if (!matching_release_found) {
1279             skip |= LogError(cb_state->commandBuffer(), TransferBarrier::ErrMsgMissingQFOReleaseInSubmit(),
1280                              "%s: in submitted command buffer %s acquiring ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
1281                              " to dstQueueFamilyIndex %" PRIu32 " has no matching release barrier queued for execution.",
1282                              "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(acquire.handle).c_str(),
1283                              acquire.srcQueueFamilyIndex, acquire.dstQueueFamilyIndex);
1284         }
1285         skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "acquiring", acquire, &scoreboards->acquire);
1286     }
1287     return skip;
1288 }
1289 
ValidateQueuedQFOTransfers(const CMD_BUFFER_STATE * cb_state,QFOTransferCBScoreboards<QFOImageTransferBarrier> * qfo_image_scoreboards,QFOTransferCBScoreboards<QFOBufferTransferBarrier> * qfo_buffer_scoreboards) const1290 bool CoreChecks::ValidateQueuedQFOTransfers(const CMD_BUFFER_STATE *cb_state,
1291                                             QFOTransferCBScoreboards<QFOImageTransferBarrier> *qfo_image_scoreboards,
1292                                             QFOTransferCBScoreboards<QFOBufferTransferBarrier> *qfo_buffer_scoreboards) const {
1293     bool skip = false;
1294     skip |=
1295         ValidateQueuedQFOTransferBarriers<QFOImageTransferBarrier>(cb_state, qfo_image_scoreboards, qfo_release_image_barrier_map);
1296     skip |= ValidateQueuedQFOTransferBarriers<QFOBufferTransferBarrier>(cb_state, qfo_buffer_scoreboards,
1297                                                                         qfo_release_buffer_barrier_map);
1298     return skip;
1299 }
1300 
1301 template <typename TransferBarrier>
RecordQueuedQFOTransferBarriers(QFOTransferBarrierSets<TransferBarrier> & cb_barriers,GlobalQFOTransferBarrierMap<TransferBarrier> & global_release_barriers)1302 void RecordQueuedQFOTransferBarriers(QFOTransferBarrierSets<TransferBarrier> &cb_barriers,
1303                                      GlobalQFOTransferBarrierMap<TransferBarrier> &global_release_barriers) {
1304     // Add release barriers from this submit to the global map
1305     for (const auto &release : cb_barriers.release) {
1306         // the global barrier list is mapped by resource handle to allow cleanup on resource destruction
1307         // NOTE: We're using [] because creation of a Set is a needed side effect for new handles
1308         global_release_barriers[release.handle].insert(release);
1309     }
1310 
1311     // Erase acquired barriers from this submit from the global map -- essentially marking releases as consumed
1312     for (const auto &acquire : cb_barriers.acquire) {
1313         // NOTE: We're not using [] because we don't want to create entries for missing releases
1314         auto set_it = global_release_barriers.find(acquire.handle);
1315         if (set_it != global_release_barriers.end()) {
1316             QFOTransferBarrierSet<TransferBarrier> &set_for_handle = set_it->second;
1317             set_for_handle.erase(acquire);
1318             if (set_for_handle.size() == 0) {  // Clean up empty sets
1319                 global_release_barriers.erase(set_it);
1320             }
1321         }
1322     }
1323 }
1324 
RecordQueuedQFOTransfers(CMD_BUFFER_STATE * cb_state)1325 void CoreChecks::RecordQueuedQFOTransfers(CMD_BUFFER_STATE *cb_state) {
1326     RecordQueuedQFOTransferBarriers<QFOImageTransferBarrier>(cb_state->qfo_transfer_image_barriers, qfo_release_image_barrier_map);
1327     RecordQueuedQFOTransferBarriers<QFOBufferTransferBarrier>(cb_state->qfo_transfer_buffer_barriers,
1328                                                               qfo_release_buffer_barrier_map);
1329 }
1330 
1331 template <typename ImgBarrier>
TransitionImageLayouts(CMD_BUFFER_STATE * cb_state,uint32_t barrier_count,const ImgBarrier * barriers)1332 void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t barrier_count, const ImgBarrier *barriers) {
1333     // For ownership transfers, the barrier is specified twice; as a release
1334     // operation on the yielding queue family, and as an acquire operation
1335     // on the acquiring queue family. This barrier may also include a layout
1336     // transition, which occurs 'between' the two operations. For validation
1337     // purposes it doesn't seem important which side performs the layout
1338     // transition, but it must not be performed twice. We'll arbitrarily
1339     // choose to perform it as part of the acquire operation.
1340     //
1341     // However, we still need to record initial layout for the "initial layout" validation
1342     for (uint32_t i = 0; i < barrier_count; i++) {
1343         const auto &mem_barrier = barriers[i];
1344         const bool is_release_op = cb_state->IsReleaseOp(mem_barrier);
1345         auto image_state = Get<IMAGE_STATE>(mem_barrier.image);
1346         if (image_state) {
1347             RecordTransitionImageLayout(cb_state, image_state.get(), mem_barrier, is_release_op);
1348         }
1349     }
1350 }
1351 // explictly instantiate this template so it can be used in core_validation.cpp
1352 template void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t barrier_count,
1353                                                  const VkImageMemoryBarrier *barrier);
1354 template void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t barrier_count,
1355                                                  const VkImageMemoryBarrier2KHR *barrier);
1356 
1357 VkImageLayout NormalizeSynchronization2Layout(const VkImageAspectFlags aspect_mask, VkImageLayout layout);
1358 
1359 template <typename ImgBarrier>
RecordTransitionImageLayout(CMD_BUFFER_STATE * cb_state,const IMAGE_STATE * image_state,const ImgBarrier & mem_barrier,bool is_release_op)1360 void CoreChecks::RecordTransitionImageLayout(CMD_BUFFER_STATE *cb_state, const IMAGE_STATE *image_state,
1361                                              const ImgBarrier &mem_barrier, bool is_release_op) {
1362     if (enabled_features.synchronization2_features.synchronization2) {
1363         if (mem_barrier.oldLayout == mem_barrier.newLayout) {
1364             return;
1365         }
1366     }
1367     auto normalized_isr = image_state->NormalizeSubresourceRange(mem_barrier.subresourceRange);
1368 
1369     VkImageLayout initial_layout = NormalizeSynchronization2Layout(mem_barrier.subresourceRange.aspectMask, mem_barrier.oldLayout);
1370     VkImageLayout new_layout = NormalizeSynchronization2Layout(mem_barrier.subresourceRange.aspectMask, mem_barrier.newLayout);
1371 
1372     // Layout transitions in external instance are not tracked, so don't validate initial layout.
1373     if (QueueFamilyIsExternal(mem_barrier.srcQueueFamilyIndex)) {
1374         initial_layout = VK_IMAGE_LAYOUT_UNDEFINED;
1375     }
1376 
1377     if (is_release_op) {
1378         cb_state->SetImageInitialLayout(*image_state, normalized_isr, initial_layout);
1379     } else {
1380         cb_state->SetImageLayout(*image_state, normalized_isr, new_layout, initial_layout);
1381     }
1382 }
1383 
VerifyImageLayout(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * image_state,const VkImageSubresourceRange & range,VkImageAspectFlags aspect_mask,VkImageLayout explicit_layout,VkImageLayout optimal_layout,const char * caller,const char * layout_invalid_msg_code,const char * layout_mismatch_msg_code,bool * error) const1384 bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
1385                                    const VkImageSubresourceRange &range, VkImageAspectFlags aspect_mask,
1386                                    VkImageLayout explicit_layout, VkImageLayout optimal_layout, const char *caller,
1387                                    const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code, bool *error) const {
1388     if (disabled[image_layout_validation]) return false;
1389     assert(cb_node);
1390     assert(image_state);
1391     bool skip = false;
1392 
1393     const auto *subresource_map = cb_node->GetImageSubresourceLayoutMap(*image_state);
1394     if (subresource_map) {
1395         bool subres_skip = false;
1396         LayoutUseCheckAndMessage layout_check(subresource_map, aspect_mask);
1397         // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to
1398         // the next "constant value" range
1399         for (auto pos = subresource_map->Find(range); !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
1400             if (!layout_check.Check(pos->subresource, explicit_layout, pos->current_layout, pos->initial_layout)) {
1401                 *error = true;
1402                 subres_skip |=
1403                     LogError(cb_node->commandBuffer(), layout_mismatch_msg_code,
1404                              "%s: Cannot use %s (layer=%u mip=%u) with specific layout %s that doesn't match the "
1405                              "%s layout %s.",
1406                              caller, report_data->FormatHandle(image_state->Handle()).c_str(), pos->subresource.arrayLayer,
1407                              pos->subresource.mipLevel, string_VkImageLayout(explicit_layout), layout_check.message,
1408                              string_VkImageLayout(layout_check.layout));
1409             }
1410         }
1411         skip |= subres_skip;
1412     }
1413 
1414     // If optimal_layout is not UNDEFINED, check that layout matches optimal for this case
1415     if ((VK_IMAGE_LAYOUT_UNDEFINED != optimal_layout) && (explicit_layout != optimal_layout)) {
1416         if (VK_IMAGE_LAYOUT_GENERAL == explicit_layout) {
1417             if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
1418                 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
1419                 skip |= LogPerformanceWarning(cb_node->commandBuffer(), kVUID_Core_DrawState_InvalidImageLayout,
1420                                               "%s: For optimal performance %s layout should be %s instead of GENERAL.", caller,
1421                                               report_data->FormatHandle(image_state->Handle()).c_str(),
1422                                               string_VkImageLayout(optimal_layout));
1423             }
1424         } else if (IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)) {
1425             if (image_state->shared_presentable) {
1426                 if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != explicit_layout) {
1427                     skip |=
1428                         LogError(device, layout_invalid_msg_code,
1429                                  "%s: Layout for shared presentable image is %s but must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.",
1430                                  caller, string_VkImageLayout(optimal_layout));
1431                 }
1432             }
1433         } else {
1434             *error = true;
1435             skip |= LogError(cb_node->commandBuffer(), layout_invalid_msg_code,
1436                              "%s: Layout for %s is %s but can only be %s or VK_IMAGE_LAYOUT_GENERAL.", caller,
1437                              report_data->FormatHandle(image_state->Handle()).c_str(), string_VkImageLayout(explicit_layout),
1438                              string_VkImageLayout(optimal_layout));
1439         }
1440     }
1441     return skip;
1442 }
VerifyImageLayout(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * image_state,const VkImageSubresourceLayers & subLayers,VkImageLayout explicit_layout,VkImageLayout optimal_layout,const char * caller,const char * layout_invalid_msg_code,const char * layout_mismatch_msg_code,bool * error) const1443 bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
1444                                    const VkImageSubresourceLayers &subLayers, VkImageLayout explicit_layout,
1445                                    VkImageLayout optimal_layout, const char *caller, const char *layout_invalid_msg_code,
1446                                    const char *layout_mismatch_msg_code, bool *error) const {
1447     return VerifyImageLayout(cb_node, image_state, RangeFromLayers(subLayers), explicit_layout, optimal_layout, caller,
1448                              layout_invalid_msg_code, layout_mismatch_msg_code, error);
1449 }
1450 
TransitionFinalSubpassLayouts(CMD_BUFFER_STATE * pCB,const VkRenderPassBeginInfo * pRenderPassBegin,FRAMEBUFFER_STATE * framebuffer_state)1451 void CoreChecks::TransitionFinalSubpassLayouts(CMD_BUFFER_STATE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
1452                                                FRAMEBUFFER_STATE *framebuffer_state) {
1453     auto render_pass = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
1454     if (!render_pass) return;
1455 
1456     const VkRenderPassCreateInfo2 *render_pass_info = render_pass->createInfo.ptr();
1457     if (framebuffer_state) {
1458         for (uint32_t i = 0; i < render_pass_info->attachmentCount; ++i) {
1459             auto *view_state = pCB->GetActiveAttachmentImageViewState(i);
1460             if (view_state) {
1461                 VkImageLayout stencil_layout = kInvalidLayout;
1462                 const auto *attachment_description_stencil_layout =
1463                     LvlFindInChain<VkAttachmentDescriptionStencilLayout>(render_pass_info->pAttachments[i].pNext);
1464                 if (attachment_description_stencil_layout) {
1465                     stencil_layout = attachment_description_stencil_layout->stencilFinalLayout;
1466                 }
1467                 pCB->SetImageViewLayout(*view_state, render_pass_info->pAttachments[i].finalLayout, stencil_layout);
1468             }
1469         }
1470     }
1471 }
1472 
1473 #ifdef VK_USE_PLATFORM_ANDROID_KHR
1474 // Android-specific validation that uses types defined only with VK_USE_PLATFORM_ANDROID_KHR
1475 // This could also move into a seperate core_validation_android.cpp file... ?
1476 
1477 //
1478 // AHB-specific validation within non-AHB APIs
1479 //
ValidateCreateImageANDROID(const debug_report_data * report_data,const VkImageCreateInfo * create_info) const1480 bool CoreChecks::ValidateCreateImageANDROID(const debug_report_data *report_data, const VkImageCreateInfo *create_info) const {
1481     bool skip = false;
1482 
1483     const VkExternalFormatANDROID *ext_fmt_android = LvlFindInChain<VkExternalFormatANDROID>(create_info->pNext);
1484     if (ext_fmt_android) {
1485         if (0 != ext_fmt_android->externalFormat) {
1486             if (VK_FORMAT_UNDEFINED != create_info->format) {
1487                 skip |=
1488                     LogError(device, "VUID-VkImageCreateInfo-pNext-01974",
1489                              "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with non-zero "
1490                              "externalFormat, but the VkImageCreateInfo's format is not VK_FORMAT_UNDEFINED.");
1491             }
1492 
1493             if (0 != (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT & create_info->flags)) {
1494                 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02396",
1495                                  "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1496                                  "non-zero externalFormat, but flags include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
1497             }
1498 
1499             if (0 != (~VK_IMAGE_USAGE_SAMPLED_BIT & create_info->usage)) {
1500                 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02397",
1501                                  "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1502                                  "non-zero externalFormat, but usage includes bits (0x%" PRIx32 ") other than VK_IMAGE_USAGE_SAMPLED_BIT.",
1503                                  create_info->usage);
1504             }
1505 
1506             if (VK_IMAGE_TILING_OPTIMAL != create_info->tiling) {
1507                 skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02398",
1508                                  "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1509                                  "non-zero externalFormat, but layout is not VK_IMAGE_TILING_OPTIMAL.");
1510             }
1511         }
1512 
1513         if ((0 != ext_fmt_android->externalFormat) &&
1514             (ahb_ext_formats_map.find(ext_fmt_android->externalFormat) == ahb_ext_formats_map.end())) {
1515             skip |= LogError(device, "VUID-VkExternalFormatANDROID-externalFormat-01894",
1516                              "vkCreateImage(): Chained VkExternalFormatANDROID struct contains a non-zero externalFormat (%" PRIu64
1517                              ") which has "
1518                              "not been previously retrieved by vkGetAndroidHardwareBufferPropertiesANDROID().",
1519                              ext_fmt_android->externalFormat);
1520         }
1521     }
1522 
1523     if ((nullptr == ext_fmt_android) || (0 == ext_fmt_android->externalFormat)) {
1524         if (VK_FORMAT_UNDEFINED == create_info->format) {
1525             skip |=
1526                 LogError(device, "VUID-VkImageCreateInfo-pNext-01975",
1527                          "vkCreateImage(): VkImageCreateInfo struct's format is VK_FORMAT_UNDEFINED, but either does not have a "
1528                          "chained VkExternalFormatANDROID struct or the struct exists but has an externalFormat of 0.");
1529         }
1530     }
1531 
1532     const VkExternalMemoryImageCreateInfo *emici = LvlFindInChain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
1533     if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
1534         if (create_info->imageType != VK_IMAGE_TYPE_2D) {
1535             skip |=
1536                 LogError(device, "VUID-VkImageCreateInfo-pNext-02393",
1537                          "vkCreateImage(): VkImageCreateInfo struct with imageType %s has chained VkExternalMemoryImageCreateInfo "
1538                          "struct with handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
1539                          string_VkImageType(create_info->imageType));
1540         }
1541 
1542         if ((create_info->mipLevels != 1) && (create_info->mipLevels != FullMipChainLevels(create_info->extent))) {
1543             skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-02394",
1544                              "vkCreateImage(): VkImageCreateInfo struct with chained VkExternalMemoryImageCreateInfo struct of "
1545                              "handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID "
1546                              "specifies mipLevels = %" PRId32 " (full chain mipLevels are %" PRId32 ").",
1547                              create_info->mipLevels, FullMipChainLevels(create_info->extent));
1548         }
1549     }
1550 
1551     return skip;
1552 }
1553 
ValidateCreateImageViewANDROID(const VkImageViewCreateInfo * create_info) const1554 bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) const {
1555     bool skip = false;
1556     const auto image_state = Get<IMAGE_STATE>(create_info->image);
1557 
1558     if (image_state->HasAHBFormat()) {
1559         if (VK_FORMAT_UNDEFINED != create_info->format) {
1560             skip |= LogError(create_info->image, "VUID-VkImageViewCreateInfo-image-02399",
1561                              "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
1562                              "format member is %s and must be VK_FORMAT_UNDEFINED.",
1563                              string_VkFormat(create_info->format));
1564         }
1565 
1566         // Chain must include a compatible ycbcr conversion
1567         bool conv_found = false;
1568         uint64_t external_format = 0;
1569         const VkSamplerYcbcrConversionInfo *ycbcr_conv_info = LvlFindInChain<VkSamplerYcbcrConversionInfo>(create_info->pNext);
1570         if (ycbcr_conv_info != nullptr) {
1571             auto ycbcr_state = Get<SAMPLER_YCBCR_CONVERSION_STATE>(ycbcr_conv_info->conversion);
1572             if (ycbcr_state) {
1573                 conv_found = true;
1574                 external_format = ycbcr_state->external_format;
1575             }
1576         }
1577         if ((!conv_found) || (external_format != image_state->ahb_format)) {
1578             skip |= LogError(create_info->image, "VUID-VkImageViewCreateInfo-image-02400",
1579                              "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1580                              "an externalFormat (%" PRIu64
1581                              ") but needs a chained VkSamplerYcbcrConversionInfo struct with a VkSamplerYcbcrConversion created "
1582                              "with the same external format.",
1583                              image_state->ahb_format);
1584         }
1585 
1586         // Errors in create_info swizzles
1587         if (IsIdentitySwizzle(create_info->components) == false) {
1588             skip |= LogError(
1589                 create_info->image, "VUID-VkImageViewCreateInfo-image-02401",
1590                 "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
1591                 "includes one or more non-identity component swizzles, r swizzle = %s, g swizzle = %s, b swizzle = %s, a swizzle "
1592                 "= %s.",
1593                 string_VkComponentSwizzle(create_info->components.r), string_VkComponentSwizzle(create_info->components.g),
1594                 string_VkComponentSwizzle(create_info->components.b), string_VkComponentSwizzle(create_info->components.a));
1595         }
1596     }
1597 
1598     return skip;
1599 }
1600 
ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const1601 bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const {
1602     bool skip = false;
1603 
1604     const auto image_state = Get<IMAGE_STATE>(image);
1605     if (image_state != nullptr) {
1606         if (image_state->IsExternalAHB() && (0 == image_state->GetBoundMemory().size())) {
1607             skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-image-01895",
1608                              "vkGetImageSubresourceLayout(): Attempt to query layout from an image created with "
1609                              "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType which has not yet been "
1610                              "bound to memory.");
1611         }
1612     }
1613     return skip;
1614 }
1615 
1616 #else
1617 
ValidateCreateImageANDROID(const debug_report_data * report_data,const VkImageCreateInfo * create_info) const1618 bool CoreChecks::ValidateCreateImageANDROID(const debug_report_data *report_data, const VkImageCreateInfo *create_info) const {
1619     return false;
1620 }
1621 
ValidateCreateImageViewANDROID(const VkImageViewCreateInfo * create_info) const1622 bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) const { return false; }
1623 
ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const1624 bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const { return false; }
1625 
1626 #endif  // VK_USE_PLATFORM_ANDROID_KHR
1627 
ValidateImageFormatFeatures(const VkImageCreateInfo * pCreateInfo) const1628 bool CoreChecks::ValidateImageFormatFeatures(const VkImageCreateInfo *pCreateInfo) const {
1629     bool skip = false;
1630 
1631     // validates based on imageCreateFormatFeatures from vkspec.html#resources-image-creation-limits
1632     VkFormatFeatureFlags tiling_features = 0;
1633     const VkImageTiling image_tiling = pCreateInfo->tiling;
1634     const VkFormat image_format = pCreateInfo->format;
1635 
1636     if (image_format == VK_FORMAT_UNDEFINED) {
1637         // VU 01975 states format can't be undefined unless an android externalFormat
1638 #ifdef VK_USE_PLATFORM_ANDROID_KHR
1639         const VkExternalFormatANDROID *ext_fmt_android = LvlFindInChain<VkExternalFormatANDROID>(pCreateInfo->pNext);
1640         if ((image_tiling == VK_IMAGE_TILING_OPTIMAL) && (ext_fmt_android != nullptr) && (0 != ext_fmt_android->externalFormat)) {
1641             auto it = ahb_ext_formats_map.find(ext_fmt_android->externalFormat);
1642             if (it != ahb_ext_formats_map.end()) {
1643                 tiling_features = it->second;
1644             }
1645         }
1646 #endif
1647     } else if (image_tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
1648         layer_data::unordered_set<uint64_t> drm_format_modifiers;
1649         const VkImageDrmFormatModifierExplicitCreateInfoEXT *drm_explicit =
1650             LvlFindInChain<VkImageDrmFormatModifierExplicitCreateInfoEXT>(pCreateInfo->pNext);
1651         const VkImageDrmFormatModifierListCreateInfoEXT *drm_implicit =
1652             LvlFindInChain<VkImageDrmFormatModifierListCreateInfoEXT>(pCreateInfo->pNext);
1653 
1654         if (drm_explicit != nullptr) {
1655             drm_format_modifiers.insert(drm_explicit->drmFormatModifier);
1656         } else {
1657             // VUID 02261 makes sure its only explict or implict in parameter checking
1658             assert(drm_implicit != nullptr);
1659             for (uint32_t i = 0; i < drm_implicit->drmFormatModifierCount; i++) {
1660                 drm_format_modifiers.insert(drm_implicit->pDrmFormatModifiers[i]);
1661             }
1662         }
1663 
1664         auto fmt_drm_props = LvlInitStruct<VkDrmFormatModifierPropertiesListEXT>();
1665         auto fmt_props_2 = LvlInitStruct<VkFormatProperties2>(&fmt_drm_props);
1666         DispatchGetPhysicalDeviceFormatProperties2(physical_device, image_format, &fmt_props_2);
1667         std::vector<VkDrmFormatModifierPropertiesEXT> drm_properties;
1668         drm_properties.resize(fmt_drm_props.drmFormatModifierCount);
1669         fmt_drm_props.pDrmFormatModifierProperties = drm_properties.data();
1670         DispatchGetPhysicalDeviceFormatProperties2(physical_device, image_format, &fmt_props_2);
1671 
1672         for (uint32_t i = 0; i < fmt_drm_props.drmFormatModifierCount; i++) {
1673             if (drm_format_modifiers.find(fmt_drm_props.pDrmFormatModifierProperties[i].drmFormatModifier) !=
1674                 drm_format_modifiers.end()) {
1675                 tiling_features |= fmt_drm_props.pDrmFormatModifierProperties[i].drmFormatModifierTilingFeatures;
1676             }
1677         }
1678     } else {
1679         VkFormatProperties format_properties = GetPDFormatProperties(image_format);
1680         tiling_features = (image_tiling == VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
1681                                                                    : format_properties.optimalTilingFeatures;
1682     }
1683 
1684     // Lack of disjoint format feature support while using the flag
1685     if (FormatIsMultiplane(image_format) && ((pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0) &&
1686         ((tiling_features & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0)) {
1687         skip |= LogError(device, "VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260",
1688                          "vkCreateImage(): can't use VK_IMAGE_CREATE_DISJOINT_BIT because %s doesn't support "
1689                          "VK_FORMAT_FEATURE_DISJOINT_BIT based on imageCreateFormatFeatures.",
1690                          string_VkFormat(pCreateInfo->format));
1691     }
1692 
1693     return skip;
1694 }
1695 
PreCallValidateCreateImage(VkDevice device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage) const1696 bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
1697                                             const VkAllocationCallbacks *pAllocator, VkImage *pImage) const {
1698     bool skip = false;
1699 
1700     if (IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
1701         skip |= ValidateCreateImageANDROID(report_data, pCreateInfo);
1702     } else {  // These checks are omitted or replaced when Android HW Buffer extension is active
1703         if (pCreateInfo->format == VK_FORMAT_UNDEFINED) {
1704             return LogError(device, "VUID-VkImageCreateInfo-format-00943",
1705                             "vkCreateImage(): VkFormat for image must not be VK_FORMAT_UNDEFINED.");
1706         }
1707     }
1708 
1709     if (pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
1710         if (VK_IMAGE_TYPE_2D != pCreateInfo->imageType) {
1711             skip |= LogError(device, "VUID-VkImageCreateInfo-flags-00949",
1712                              "vkCreateImage(): Image type must be VK_IMAGE_TYPE_2D when VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT "
1713                              "flag bit is set");
1714         }
1715     }
1716 
1717     const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
1718     VkImageUsageFlags attach_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
1719                                      VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1720     if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.width > device_limits->maxFramebufferWidth)) {
1721         skip |= LogError(device, "VUID-VkImageCreateInfo-usage-00964",
1722                          "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image width (%u) exceeds "
1723                          "device maxFramebufferWidth (%u).",
1724                          pCreateInfo->extent.width, device_limits->maxFramebufferWidth);
1725     }
1726 
1727     if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.height > device_limits->maxFramebufferHeight)) {
1728         skip |= LogError(device, "VUID-VkImageCreateInfo-usage-00965",
1729                          "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image height (%u) exceeds "
1730                          "device maxFramebufferHeight (%u).",
1731                          pCreateInfo->extent.height, device_limits->maxFramebufferHeight);
1732     }
1733 
1734     VkImageCreateFlags sparseFlags =
1735         VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT;
1736     if ((pCreateInfo->flags & sparseFlags) && (pCreateInfo->usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) {
1737         skip |= LogError(
1738             device, "VUID-VkImageCreateInfo-None-01925",
1739             "vkCreateImage(): images using sparse memory cannot have VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT set");
1740     }
1741 
1742     if (IsExtEnabled(device_extensions.vk_ext_fragment_density_map) ||
1743         IsExtEnabled(device_extensions.vk_ext_fragment_density_map2)) {
1744         uint32_t ceiling_width = static_cast<uint32_t>(ceil(
1745             static_cast<float>(device_limits->maxFramebufferWidth) /
1746             std::max(static_cast<float>(phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width), 1.0f)));
1747         if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.width > ceiling_width)) {
1748             skip |=
1749                 LogError(device, "VUID-VkImageCreateInfo-usage-02559",
1750                          "vkCreateImage(): Image usage flags include a fragment density map bit and image width (%u) exceeds the "
1751                          "ceiling of device "
1752                          "maxFramebufferWidth (%u) / minFragmentDensityTexelSize.width (%u). The ceiling value: %u",
1753                          pCreateInfo->extent.width, device_limits->maxFramebufferWidth,
1754                          phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width, ceiling_width);
1755         }
1756 
1757         uint32_t ceiling_height = static_cast<uint32_t>(ceil(
1758             static_cast<float>(device_limits->maxFramebufferHeight) /
1759             std::max(static_cast<float>(phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height), 1.0f)));
1760         if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.height > ceiling_height)) {
1761             skip |=
1762                 LogError(device, "VUID-VkImageCreateInfo-usage-02560",
1763                          "vkCreateImage(): Image usage flags include a fragment density map bit and image height (%u) exceeds the "
1764                          "ceiling of device "
1765                          "maxFramebufferHeight (%u) / minFragmentDensityTexelSize.height (%u). The ceiling value: %u",
1766                          pCreateInfo->extent.height, device_limits->maxFramebufferHeight,
1767                          phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height, ceiling_height);
1768         }
1769     }
1770 
1771     VkImageFormatProperties format_limits = {};
1772     VkResult result = VK_SUCCESS;
1773     if (pCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
1774         result = DispatchGetPhysicalDeviceImageFormatProperties(physical_device, pCreateInfo->format, pCreateInfo->imageType,
1775                                                                 pCreateInfo->tiling, pCreateInfo->usage, pCreateInfo->flags,
1776                                                                 &format_limits);
1777     } else {
1778         auto modifier_list = LvlFindInChain<VkImageDrmFormatModifierListCreateInfoEXT>(pCreateInfo->pNext);
1779         auto explicit_modifier = LvlFindInChain<VkImageDrmFormatModifierExplicitCreateInfoEXT>(pCreateInfo->pNext);
1780         if (modifier_list) {
1781             for (uint32_t i = 0; i < modifier_list->drmFormatModifierCount; i++) {
1782                 auto drm_format_modifier = LvlInitStruct<VkPhysicalDeviceImageDrmFormatModifierInfoEXT>();
1783                 drm_format_modifier.drmFormatModifier = modifier_list->pDrmFormatModifiers[i];
1784                 auto image_format_info = LvlInitStruct<VkPhysicalDeviceImageFormatInfo2>(&drm_format_modifier);
1785                 image_format_info.type = pCreateInfo->imageType;
1786                 image_format_info.format = pCreateInfo->format;
1787                 image_format_info.tiling = pCreateInfo->tiling;
1788                 image_format_info.usage = pCreateInfo->usage;
1789                 image_format_info.flags = pCreateInfo->flags;
1790                 auto image_format_properties = LvlInitStruct<VkImageFormatProperties2>();
1791 
1792                 result =
1793                     DispatchGetPhysicalDeviceImageFormatProperties2(physical_device, &image_format_info, &image_format_properties);
1794                 format_limits = image_format_properties.imageFormatProperties;
1795 
1796                 /* The application gives a list of modifier and the driver
1797                  * selects one. If one is wrong, stop there.
1798                  */
1799                 if (result != VK_SUCCESS) break;
1800             }
1801         } else if (explicit_modifier) {
1802             auto drm_format_modifier = LvlInitStruct<VkPhysicalDeviceImageDrmFormatModifierInfoEXT>();
1803             drm_format_modifier.drmFormatModifier = explicit_modifier->drmFormatModifier;
1804             auto image_format_info = LvlInitStruct<VkPhysicalDeviceImageFormatInfo2>(&drm_format_modifier);
1805             image_format_info.type = pCreateInfo->imageType;
1806             image_format_info.format = pCreateInfo->format;
1807             image_format_info.tiling = pCreateInfo->tiling;
1808             image_format_info.usage = pCreateInfo->usage;
1809             image_format_info.flags = pCreateInfo->flags;
1810             auto image_format_properties = LvlInitStruct<VkImageFormatProperties2>();
1811 
1812             result = DispatchGetPhysicalDeviceImageFormatProperties2(physical_device, &image_format_info, &image_format_properties);
1813             format_limits = image_format_properties.imageFormatProperties;
1814         }
1815     }
1816 
1817     // 1. vkGetPhysicalDeviceImageFormatProperties[2] only success code is VK_SUCCESS
1818     // 2. If call returns an error, then "imageCreateImageFormatPropertiesList" is defined to be the empty list
1819     // 3. All values in 02251 are undefined if "imageCreateImageFormatPropertiesList" is empty.
1820     if (result != VK_SUCCESS) {
1821         // External memory will always have a "imageCreateImageFormatPropertiesList" so skip
1822 #ifdef VK_USE_PLATFORM_ANDROID_KHR
1823         if (!LvlFindInChain<VkExternalFormatANDROID>(pCreateInfo->pNext)) {
1824 #endif  // VK_USE_PLATFORM_ANDROID_KHR
1825             skip |= LogError(device, "VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251",
1826                              "vkCreateImage(): Format %s is not supported for this combination of parameters and "
1827                              "VkGetPhysicalDeviceImageFormatProperties returned back %s.",
1828                              string_VkFormat(pCreateInfo->format), string_VkResult(result));
1829 #ifdef VK_USE_PLATFORM_ANDROID_KHR
1830         }
1831 #endif  // VK_USE_PLATFORM_ANDROID_KHR
1832     } else {
1833         if (pCreateInfo->mipLevels > format_limits.maxMipLevels) {
1834             const char *format_string = string_VkFormat(pCreateInfo->format);
1835             skip |= LogError(device, "VUID-VkImageCreateInfo-mipLevels-02255",
1836                              "vkCreateImage(): Image mip levels=%d exceed image format maxMipLevels=%d for format %s.",
1837                              pCreateInfo->mipLevels, format_limits.maxMipLevels, format_string);
1838         }
1839 
1840         uint64_t texel_count = static_cast<uint64_t>(pCreateInfo->extent.width) *
1841                                static_cast<uint64_t>(pCreateInfo->extent.height) *
1842                                static_cast<uint64_t>(pCreateInfo->extent.depth) * static_cast<uint64_t>(pCreateInfo->arrayLayers) *
1843                                static_cast<uint64_t>(pCreateInfo->samples);
1844 
1845         // Depth/Stencil formats size can't be accurately calculated
1846         if (!FormatIsDepthAndStencil(pCreateInfo->format)) {
1847             uint64_t total_size =
1848                 static_cast<uint64_t>(std::ceil(FormatTexelSize(pCreateInfo->format) * static_cast<double>(texel_count)));
1849 
1850             // Round up to imageGranularity boundary
1851             VkDeviceSize image_granularity = phys_dev_props.limits.bufferImageGranularity;
1852             uint64_t ig_mask = image_granularity - 1;
1853             total_size = (total_size + ig_mask) & ~ig_mask;
1854 
1855             if (total_size > format_limits.maxResourceSize) {
1856                 skip |= LogWarning(device, kVUID_Core_Image_InvalidFormatLimitsViolation,
1857                                    "vkCreateImage(): resource size exceeds allowable maximum Image resource size = 0x%" PRIxLEAST64
1858                                    ", maximum resource size = 0x%" PRIxLEAST64 " ",
1859                                    total_size, format_limits.maxResourceSize);
1860             }
1861         }
1862 
1863         if (pCreateInfo->arrayLayers > format_limits.maxArrayLayers) {
1864             skip |= LogError(device, "VUID-VkImageCreateInfo-arrayLayers-02256",
1865                              "vkCreateImage(): arrayLayers=%d exceeds allowable maximum supported by format of %d.",
1866                              pCreateInfo->arrayLayers, format_limits.maxArrayLayers);
1867         }
1868 
1869         if ((pCreateInfo->samples & format_limits.sampleCounts) == 0) {
1870             skip |= LogError(device, "VUID-VkImageCreateInfo-samples-02258",
1871                              "vkCreateImage(): samples %s is not supported by format 0x%.8X.",
1872                              string_VkSampleCountFlagBits(pCreateInfo->samples), format_limits.sampleCounts);
1873         }
1874 
1875         if (pCreateInfo->extent.width > format_limits.maxExtent.width) {
1876             skip |= LogError(device, "VUID-VkImageCreateInfo-extent-02252",
1877                              "vkCreateImage(): extent.width %u exceeds allowable maximum image extent width %u.",
1878                              pCreateInfo->extent.width, format_limits.maxExtent.width);
1879         }
1880 
1881         if (pCreateInfo->extent.height > format_limits.maxExtent.height) {
1882             skip |= LogError(device, "VUID-VkImageCreateInfo-extent-02253",
1883                              "vkCreateImage(): extent.height %u exceeds allowable maximum image extent height %u.",
1884                              pCreateInfo->extent.height, format_limits.maxExtent.height);
1885         }
1886 
1887         if (pCreateInfo->extent.depth > format_limits.maxExtent.depth) {
1888             skip |= LogError(device, "VUID-VkImageCreateInfo-extent-02254",
1889                              "vkCreateImage(): extent.depth %u exceeds allowable maximum image extent depth %u.",
1890                              pCreateInfo->extent.depth, format_limits.maxExtent.depth);
1891         }
1892     }
1893 
1894     // Tests for "Formats requiring sampler YCBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views"
1895     if (FormatRequiresYcbcrConversionExplicitly(pCreateInfo->format)) {
1896         if (!enabled_features.ycbcr_image_array_features.ycbcrImageArrays && pCreateInfo->arrayLayers != 1) {
1897             const char *error_vuid = IsExtEnabled(device_extensions.vk_ext_ycbcr_image_arrays)
1898                                          ? "VUID-VkImageCreateInfo-format-06414"
1899                                          : "VUID-VkImageCreateInfo-format-06413";
1900             skip |= LogError(device, error_vuid,
1901                              "vkCreateImage(): arrayLayers = %d, but when the ycbcrImagesArrays feature is not enabled and using a "
1902                              "YCbCr Conversion format, arrayLayers must be 1",
1903                              pCreateInfo->arrayLayers);
1904         }
1905 
1906         if (pCreateInfo->mipLevels != 1) {
1907             skip |= LogError(device, "VUID-VkImageCreateInfo-format-06410",
1908                              "vkCreateImage(): mipLevels = %d, but when using a YCbCr Conversion format, mipLevels must be 1",
1909                              pCreateInfo->arrayLayers);
1910         }
1911 
1912         if (pCreateInfo->samples != VK_SAMPLE_COUNT_1_BIT) {
1913             skip |= LogError(
1914                 device, "VUID-VkImageCreateInfo-format-06411",
1915                 "vkCreateImage(): samples = %s, but when using a YCbCr Conversion format, samples must be VK_SAMPLE_COUNT_1_BIT",
1916                 string_VkSampleCountFlagBits(pCreateInfo->samples));
1917         }
1918 
1919         if (pCreateInfo->imageType != VK_IMAGE_TYPE_2D) {
1920             skip |= LogError(
1921                 device, "VUID-VkImageCreateInfo-format-06412",
1922                 "vkCreateImage(): imageType = %s, but when using a YCbCr Conversion format, imageType must be VK_IMAGE_TYPE_2D ",
1923                 string_VkImageType(pCreateInfo->imageType));
1924         }
1925     }
1926 
1927     if (IsExtEnabled(device_extensions.vk_khr_maintenance2)) {
1928         if (pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) {
1929             if (!FormatIsCompressed(pCreateInfo->format)) {
1930                 skip |= LogError(device, "VUID-VkImageCreateInfo-flags-01572",
1931                                  "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, "
1932                                  "format must be a compressed image format, but is %s",
1933                                  string_VkFormat(pCreateInfo->format));
1934             }
1935             if (!(pCreateInfo->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) {
1936                 skip |= LogError(device, "VUID-VkImageCreateInfo-flags-01573",
1937                                  "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, "
1938                                  "flags must also contain VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
1939             }
1940         }
1941     }
1942 
1943     if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
1944         const char *vuid = IsExtEnabled(device_extensions.vk_khr_get_physical_device_properties2)
1945                                ? "VUID-VkImageCreateInfo-sharingMode-01420"
1946                                : "VUID-VkImageCreateInfo-sharingMode-01392";
1947         skip |= ValidatePhysicalDeviceQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
1948                                                     "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", vuid);
1949     }
1950 
1951     if (!FormatIsMultiplane(pCreateInfo->format) && !(pCreateInfo->flags & VK_IMAGE_CREATE_ALIAS_BIT) &&
1952         (pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT)) {
1953         skip |=
1954             LogError(device, "VUID-VkImageCreateInfo-format-01577",
1955                      "vkCreateImage(): format is %s and flags are %s. The flags should not include VK_IMAGE_CREATE_DISJOINT_BIT.",
1956                      string_VkFormat(pCreateInfo->format), string_VkImageCreateFlags(pCreateInfo->flags).c_str());
1957     }
1958 
1959     const auto swapchain_create_info = LvlFindInChain<VkImageSwapchainCreateInfoKHR>(pCreateInfo->pNext);
1960     if (swapchain_create_info != nullptr) {
1961         if (swapchain_create_info->swapchain != VK_NULL_HANDLE) {
1962             const auto swapchain_state = Get<SWAPCHAIN_NODE>(swapchain_create_info->swapchain);
1963             const VkSwapchainCreateFlagsKHR swapchain_flags = swapchain_state->createInfo.flags;
1964 
1965             // Validate rest of Swapchain Image create check that require swapchain state
1966             const char *vuid = "VUID-VkImageSwapchainCreateInfoKHR-swapchain-00995";
1967             if (((swapchain_flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR) != 0) &&
1968                 ((pCreateInfo->flags & VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT) == 0)) {
1969                 skip |= LogError(
1970                     device, vuid,
1971                     "vkCreateImage(): Swapchain was created with VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR flag so "
1972                     "all swapchain images must have the VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT flag set.");
1973             }
1974             if (((swapchain_flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) != 0) &&
1975                 ((pCreateInfo->flags & VK_IMAGE_CREATE_PROTECTED_BIT) == 0)) {
1976                 skip |= LogError(device, vuid,
1977                                  "vkCreateImage(): Swapchain was created with VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR flag so all "
1978                                  "swapchain images must have the VK_IMAGE_CREATE_PROTECTED_BIT flag set.");
1979             }
1980             const VkImageCreateFlags mutable_flags = (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT);
1981             if (((swapchain_flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) != 0) &&
1982                 ((pCreateInfo->flags & mutable_flags) != mutable_flags)) {
1983                 skip |= LogError(device, vuid,
1984                                  "vkCreateImage(): Swapchain was created with VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR flag so "
1985                                  "all swapchain images must have the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT and "
1986                                  "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT flags both set.");
1987             }
1988         }
1989     }
1990 
1991     if ((pCreateInfo->flags & VK_IMAGE_CREATE_PROTECTED_BIT) != 0) {
1992         if (enabled_features.core11.protectedMemory == VK_FALSE) {
1993             skip |= LogError(device, "VUID-VkImageCreateInfo-flags-01890",
1994                              "vkCreateImage(): the protectedMemory device feature is disabled: Images cannot be created with the "
1995                              "VK_IMAGE_CREATE_PROTECTED_BIT set.");
1996         }
1997         const VkImageCreateFlags invalid_flags =
1998             VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT;
1999         if ((pCreateInfo->flags & invalid_flags) != 0) {
2000             skip |= LogError(device, "VUID-VkImageCreateInfo-None-01891",
2001                              "vkCreateImage(): VK_IMAGE_CREATE_PROTECTED_BIT is set so no sparse create flags can be used at same "
2002                              "time (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | "
2003                              "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT).");
2004         }
2005     }
2006 
2007     skip |= ValidateImageFormatFeatures(pCreateInfo);
2008 
2009     // Check compatibility with VK_KHR_portability_subset
2010     if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
2011         if (VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT & pCreateInfo->flags &&
2012             VK_FALSE == enabled_features.portability_subset_features.imageView2DOn3DImage) {
2013             skip |= LogError(device, "VUID-VkImageCreateInfo-imageView2DOn3DImage-04459",
2014                              "vkCreateImage (portability error): VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT is not supported.");
2015         }
2016         if ((VK_SAMPLE_COUNT_1_BIT != pCreateInfo->samples) && (1 != pCreateInfo->arrayLayers) &&
2017             (VK_FALSE == enabled_features.portability_subset_features.multisampleArrayImage)) {
2018             skip |=
2019                 LogError(device, "VUID-VkImageCreateInfo-multisampleArrayImage-04460",
2020                          "vkCreateImage (portability error): Cannot create an image with samples/texel > 1 && arrayLayers != 1");
2021         }
2022     }
2023 
2024     const auto external_memory_create_info_nv = LvlFindInChain<VkExternalMemoryImageCreateInfoNV>(pCreateInfo->pNext);
2025     const auto external_memory_create_info = LvlFindInChain<VkExternalMemoryImageCreateInfo>(pCreateInfo->pNext);
2026     if (external_memory_create_info_nv != nullptr && external_memory_create_info != nullptr) {
2027         skip |= LogError(device, "VUID-VkImageCreateInfo-pNext-00988",
2028                          "vkCreateImage(): VkImageCreateInfo struct has both VkExternalMemoryImageCreateInfoNV and "
2029                          "VkExternalMemoryImageCreateInfo chained structs.");
2030     }
2031     if (external_memory_create_info) {
2032         if (external_memory_create_info->handleTypes != 0 && pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
2033             skip |= LogError(
2034                 device, "VUID-VkImageCreateInfo-pNext-01443",
2035                 "vkCreateImage: VkImageCreateInfo pNext chain includes VkExternalMemoryImageCreateInfo with handleTypes %" PRIu32
2036                 " but pCreateInfo->initialLayout is %s.",
2037                 external_memory_create_info->handleTypes, string_VkImageLayout(pCreateInfo->initialLayout));
2038         }
2039     } else if (external_memory_create_info_nv) {
2040         if (external_memory_create_info_nv->handleTypes != 0 && pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
2041             skip |= LogError(
2042                 device, "VUID-VkImageCreateInfo-pNext-01443",
2043                 "vkCreateImage: VkImageCreateInfo pNext chain includes VkExternalMemoryImageCreateInfoNV with handleTypes %" PRIu32
2044                 " but pCreateInfo->initialLayout is %s.",
2045                 external_memory_create_info_nv->handleTypes, string_VkImageLayout(pCreateInfo->initialLayout));
2046         }
2047     }
2048 
2049     if (device_group_create_info.physicalDeviceCount == 1) {
2050         if (pCreateInfo->flags & VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT) {
2051             skip |= LogError(device, "VUID-VkImageCreateInfo-physicalDeviceCount-01421",
2052                              "vkCreateImage: Device was created with VkDeviceGroupDeviceCreateInfo::physicalDeviceCount 1, but "
2053                              "flags contain VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT bit.");
2054         }
2055     }
2056 
2057     return skip;
2058 }
2059 
PostCallRecordCreateImage(VkDevice device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage,VkResult result)2060 void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
2061                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) {
2062     if (VK_SUCCESS != result) return;
2063 
2064     StateTracker::PostCallRecordCreateImage(device, pCreateInfo, pAllocator, pImage, result);
2065     auto image_state = Get<IMAGE_STATE>(*pImage);
2066     AddInitialLayoutintoImageLayoutMap(*image_state, imageLayoutMap);
2067 }
2068 
PreCallValidateDestroyImage(VkDevice device,VkImage image,const VkAllocationCallbacks * pAllocator) const2069 bool CoreChecks::PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) const {
2070     const auto image_state = Get<IMAGE_STATE>(image);
2071     bool skip = false;
2072     if (image_state) {
2073         if (image_state->IsSwapchainImage()) {
2074             skip |= LogError(device, "VUID-vkDestroyImage-image-04882",
2075                              "vkDestroyImage(): %s is a presentable image and it is controlled by the implementation and is "
2076                              "destroyed with vkDestroySwapchainKHR.",
2077                              report_data->FormatHandle(image_state->image()).c_str());
2078         }
2079         skip |= ValidateObjectNotInUse(image_state.get(), "vkDestroyImage", "VUID-vkDestroyImage-image-01000");
2080     }
2081     return skip;
2082 }
2083 
PreCallRecordDestroyImage(VkDevice device,VkImage image,const VkAllocationCallbacks * pAllocator)2084 void CoreChecks::PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
2085     // Clean up validation specific data
2086     auto image_state = Get<IMAGE_STATE>(image);
2087     qfo_release_image_barrier_map.erase(image);
2088 
2089     imageLayoutMap.erase(image_state.get());
2090 
2091     // Clean up generic image state
2092     StateTracker::PreCallRecordDestroyImage(device, image, pAllocator);
2093 }
2094 
ValidateImageAttributes(const IMAGE_STATE * image_state,const VkImageSubresourceRange & range,const char * param_name) const2095 bool CoreChecks::ValidateImageAttributes(const IMAGE_STATE *image_state, const VkImageSubresourceRange &range,
2096                                          const char *param_name) const {
2097     bool skip = false;
2098     const VkImage image = image_state->image();
2099     const VkFormat format = image_state->createInfo.format;
2100 
2101     if (range.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
2102         skip |= LogError(image, "VUID-vkCmdClearColorImage-aspectMask-02498",
2103                          "vkCmdClearColorImage(): %s.aspectMasks must only be set to VK_IMAGE_ASPECT_COLOR_BIT.", param_name);
2104     }
2105 
2106     if (FormatIsDepthOrStencil(format)) {
2107         skip |= LogError(image, "VUID-vkCmdClearColorImage-image-00007",
2108                          "vkCmdClearColorImage(): %s called with image %s which has a depth/stencil format (%s).", param_name,
2109                          report_data->FormatHandle(image).c_str(), string_VkFormat(format));
2110     } else if (FormatIsCompressed(format)) {
2111         skip |= LogError(image, "VUID-vkCmdClearColorImage-image-00007",
2112                          "vkCmdClearColorImage(): %s called with image %s which has a compressed format (%s).", param_name,
2113                          report_data->FormatHandle(image).c_str(), string_VkFormat(format));
2114     }
2115 
2116     if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
2117         skip |=
2118             LogError(image, "VUID-vkCmdClearColorImage-image-00002",
2119                      "vkCmdClearColorImage() %s called with image %s which was created without VK_IMAGE_USAGE_TRANSFER_DST_BIT.",
2120                      param_name, report_data->FormatHandle(image).c_str());
2121     }
2122     return skip;
2123 }
2124 
VerifyClearImageLayout(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * image_state,const VkImageSubresourceRange & range,VkImageLayout dest_image_layout,const char * func_name) const2125 bool CoreChecks::VerifyClearImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
2126                                         const VkImageSubresourceRange &range, VkImageLayout dest_image_layout,
2127                                         const char *func_name) const {
2128     bool skip = false;
2129     if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
2130         if ((dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) && (dest_image_layout != VK_IMAGE_LAYOUT_GENERAL)) {
2131             skip |= LogError(image_state->image(), "VUID-vkCmdClearDepthStencilImage-imageLayout-00012",
2132                              "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL.", func_name,
2133                              string_VkImageLayout(dest_image_layout));
2134         }
2135 
2136     } else {
2137         assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
2138         if (!IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)) {
2139             if ((dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) && (dest_image_layout != VK_IMAGE_LAYOUT_GENERAL)) {
2140                 skip |= LogError(image_state->image(), "VUID-vkCmdClearColorImage-imageLayout-00005",
2141                                  "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL.", func_name,
2142                                  string_VkImageLayout(dest_image_layout));
2143             }
2144         } else {
2145             if ((dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) && (dest_image_layout != VK_IMAGE_LAYOUT_GENERAL) &&
2146                 (dest_image_layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR)) {
2147                 skip |= LogError(
2148                     image_state->image(), "VUID-vkCmdClearColorImage-imageLayout-01394",
2149                     "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL, SHARED_PRESENT_KHR, or GENERAL.",
2150                     func_name, string_VkImageLayout(dest_image_layout));
2151             }
2152         }
2153     }
2154 
2155     // Cast to const to prevent creation at validate time.
2156     const auto *subresource_map = cb_node->GetImageSubresourceLayoutMap(*image_state);
2157     if (subresource_map) {
2158         bool subres_skip = false;
2159         LayoutUseCheckAndMessage layout_check(subresource_map);
2160         auto normalized_isr = image_state->NormalizeSubresourceRange(range);
2161         // IncrementInterval skips over all the subresources that have the same state as we just checked, incrementing to
2162         // the next "constant value" range
2163         for (auto pos = subresource_map->Find(normalized_isr); !(pos.AtEnd()) && !subres_skip; pos.IncrementInterval()) {
2164             if (!layout_check.Check(pos->subresource, dest_image_layout, pos->current_layout, pos->initial_layout)) {
2165                 const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
2166                 if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
2167                     error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
2168                 } else {
2169                     assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
2170                 }
2171                 subres_skip |= LogError(cb_node->commandBuffer(), error_code,
2172                                         "%s: Cannot clear an image whose layout is %s and doesn't match the %s layout %s.",
2173                                         func_name, string_VkImageLayout(dest_image_layout), layout_check.message,
2174                                         string_VkImageLayout(layout_check.layout));
2175             }
2176         }
2177         skip |= subres_skip;
2178     }
2179 
2180     return skip;
2181 }
2182 
PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearColorValue * pColor,uint32_t rangeCount,const VkImageSubresourceRange * pRanges) const2183 bool CoreChecks::PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2184                                                    const VkClearColorValue *pColor, uint32_t rangeCount,
2185                                                    const VkImageSubresourceRange *pRanges) const {
2186     bool skip = false;
2187     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
2188     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
2189     const auto image_state = Get<IMAGE_STATE>(image);
2190     if (cb_node && image_state) {
2191         skip |= ValidateMemoryIsBoundToImage(image_state.get(), "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-image-00003");
2192         skip |= ValidateCmd(cb_node.get(), CMD_CLEARCOLORIMAGE);
2193         if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
2194             skip |= ValidateImageFormatFeatureFlags(image_state.get(), VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdClearColorImage",
2195                                                     "VUID-vkCmdClearColorImage-image-01993");
2196         }
2197         skip |= ValidateProtectedImage(cb_node.get(), image_state.get(), "vkCmdClearColorImage()",
2198                                        "VUID-vkCmdClearColorImage-commandBuffer-01805");
2199         skip |= ValidateUnprotectedImage(cb_node.get(), image_state.get(), "vkCmdClearColorImage()",
2200                                          "VUID-vkCmdClearColorImage-commandBuffer-01806");
2201         for (uint32_t i = 0; i < rangeCount; ++i) {
2202             std::string param_name = "pRanges[" + std::to_string(i) + "]";
2203             skip |= ValidateCmdClearColorSubresourceRange(image_state.get(), pRanges[i], param_name.c_str());
2204             skip |= ValidateImageAttributes(image_state.get(), pRanges[i], param_name.c_str());
2205             skip |= VerifyClearImageLayout(cb_node.get(), image_state.get(), pRanges[i], imageLayout, "vkCmdClearColorImage()");
2206         }
2207         // Tests for "Formats requiring sampler Y’CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views"
2208         if (FormatRequiresYcbcrConversionExplicitly(image_state->createInfo.format)) {
2209             skip |= LogError(device, "VUID-vkCmdClearColorImage-image-01545",
2210                              "vkCmdClearColorImage(): format (%s) must not be one of the formats requiring sampler YCBCR "
2211                              "conversion for VK_IMAGE_ASPECT_COLOR_BIT image views",
2212                              string_VkFormat(image_state->createInfo.format));
2213         }
2214     }
2215     return skip;
2216 }
2217 
PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearColorValue * pColor,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)2218 void CoreChecks::PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2219                                                  const VkClearColorValue *pColor, uint32_t rangeCount,
2220                                                  const VkImageSubresourceRange *pRanges) {
2221     StateTracker::PreCallRecordCmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
2222 
2223     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
2224     auto image_state = Get<IMAGE_STATE>(image);
2225     if (cb_node && image_state) {
2226         for (uint32_t i = 0; i < rangeCount; ++i) {
2227             cb_node->SetImageInitialLayout(image, pRanges[i], imageLayout);
2228         }
2229     }
2230 }
2231 
ValidateClearDepthStencilValue(VkCommandBuffer commandBuffer,VkClearDepthStencilValue clearValue,const char * apiName) const2232 bool CoreChecks::ValidateClearDepthStencilValue(VkCommandBuffer commandBuffer, VkClearDepthStencilValue clearValue,
2233                                                 const char *apiName) const {
2234     bool skip = false;
2235 
2236     // The extension was not created with a feature bit whichs prevents displaying the 2 variations of the VUIDs
2237     if (!IsExtEnabled(device_extensions.vk_ext_depth_range_unrestricted)) {
2238         if (!(clearValue.depth >= 0.0) || !(clearValue.depth <= 1.0)) {
2239             // Also VUID-VkClearDepthStencilValue-depth-00022
2240             skip |= LogError(commandBuffer, "VUID-VkClearDepthStencilValue-depth-02506",
2241                              "%s: VK_EXT_depth_range_unrestricted extension is not enabled and VkClearDepthStencilValue::depth "
2242                              "(=%f) is not within the [0.0, 1.0] range.",
2243                              apiName, clearValue.depth);
2244         }
2245     }
2246 
2247     return skip;
2248 }
2249 
PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearDepthStencilValue * pDepthStencil,uint32_t rangeCount,const VkImageSubresourceRange * pRanges) const2250 bool CoreChecks::PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2251                                                           const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
2252                                                           const VkImageSubresourceRange *pRanges) const {
2253     bool skip = false;
2254 
2255     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
2256     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
2257     const auto image_state = Get<IMAGE_STATE>(image);
2258     if (cb_node && image_state) {
2259         const VkFormat image_format = image_state->createInfo.format;
2260         skip |= ValidateMemoryIsBoundToImage(image_state.get(), "vkCmdClearDepthStencilImage()",
2261                                              "VUID-vkCmdClearDepthStencilImage-image-00010");
2262         skip |= ValidateCmd(cb_node.get(), CMD_CLEARDEPTHSTENCILIMAGE);
2263         if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
2264             skip |= ValidateImageFormatFeatureFlags(image_state.get(), VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
2265                                                     "vkCmdClearDepthStencilImage", "VUID-vkCmdClearDepthStencilImage-image-01994");
2266         }
2267         skip |= ValidateClearDepthStencilValue(commandBuffer, *pDepthStencil, "vkCmdClearDepthStencilImage()");
2268         skip |= ValidateProtectedImage(cb_node.get(), image_state.get(), "vkCmdClearDepthStencilImage()",
2269                                        "VUID-vkCmdClearDepthStencilImage-commandBuffer-01807");
2270         skip |= ValidateUnprotectedImage(cb_node.get(), image_state.get(), "vkCmdClearDepthStencilImage()",
2271                                          "VUID-vkCmdClearDepthStencilImage-commandBuffer-01808");
2272 
2273         bool any_include_aspect_depth_bit = false;
2274         bool any_include_aspect_stencil_bit = false;
2275 
2276         for (uint32_t i = 0; i < rangeCount; ++i) {
2277             std::string param_name = "pRanges[" + std::to_string(i) + "]";
2278             skip |= ValidateCmdClearDepthSubresourceRange(image_state.get(), pRanges[i], param_name.c_str());
2279             skip |=
2280                 VerifyClearImageLayout(cb_node.get(), image_state.get(), pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
2281             // Image aspect must be depth or stencil or both
2282             VkImageAspectFlags valid_aspects = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
2283             if (((pRanges[i].aspectMask & valid_aspects) == 0) || ((pRanges[i].aspectMask & ~valid_aspects) != 0)) {
2284                 skip |= LogError(commandBuffer, "VUID-vkCmdClearDepthStencilImage-aspectMask-02824",
2285                                  "vkCmdClearDepthStencilImage(): pRanges[%u].aspectMask can only be VK_IMAGE_ASPECT_DEPTH_BIT "
2286                                  "and/or VK_IMAGE_ASPECT_STENCIL_BIT.",
2287                                  i);
2288             }
2289             if ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
2290                 any_include_aspect_depth_bit = true;
2291                 if (FormatHasDepth(image_format) == false) {
2292                     skip |= LogError(commandBuffer, "VUID-vkCmdClearDepthStencilImage-image-02826",
2293                                      "vkCmdClearDepthStencilImage(): pRanges[%u].aspectMask has a VK_IMAGE_ASPECT_DEPTH_BIT but %s "
2294                                      "doesn't have a depth component.",
2295                                      i, string_VkFormat(image_format));
2296                 }
2297             }
2298             if ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
2299                 any_include_aspect_stencil_bit = true;
2300                 if (FormatHasStencil(image_format) == false) {
2301                     skip |= LogError(commandBuffer, "VUID-vkCmdClearDepthStencilImage-image-02825",
2302                                      "vkCmdClearDepthStencilImage(): pRanges[%u].aspectMask has a VK_IMAGE_ASPECT_STENCIL_BIT but "
2303                                      "%s doesn't have a stencil component.",
2304                                      i, string_VkFormat(image_format));
2305                 }
2306             }
2307         }
2308         if (any_include_aspect_stencil_bit) {
2309             const auto image_stencil_struct = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_state->createInfo.pNext);
2310             if (image_stencil_struct != nullptr) {
2311                 if ((image_stencil_struct->stencilUsage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
2312                     skip |=
2313                         LogError(device, "VUID-vkCmdClearDepthStencilImage-pRanges-02658",
2314                                  "vkCmdClearDepthStencilImage(): an element of pRanges.aspect includes VK_IMAGE_ASPECT_STENCIL_BIT "
2315                                  "and image was created with separate stencil usage, VK_IMAGE_USAGE_TRANSFER_DST_BIT must be "
2316                                  "included in VkImageStencilUsageCreateInfo::stencilUsage used to create image");
2317                 }
2318             } else {
2319                 if ((image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
2320                     skip |= LogError(
2321                         device, "VUID-vkCmdClearDepthStencilImage-pRanges-02659",
2322                         "vkCmdClearDepthStencilImage(): an element of pRanges.aspect includes VK_IMAGE_ASPECT_STENCIL_BIT and "
2323                         "image was not created with separate stencil usage, VK_IMAGE_USAGE_TRANSFER_DST_BIT must be included "
2324                         "in VkImageCreateInfo::usage used to create image");
2325                 }
2326             }
2327         }
2328         if (any_include_aspect_depth_bit && (image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
2329             skip |= LogError(device, "VUID-vkCmdClearDepthStencilImage-pRanges-02660",
2330                              "vkCmdClearDepthStencilImage(): an element of pRanges.aspect includes VK_IMAGE_ASPECT_DEPTH_BIT, "
2331                              "VK_IMAGE_USAGE_TRANSFER_DST_BIT must be included in VkImageCreateInfo::usage used to create image");
2332         }
2333         if (image_state && !FormatIsDepthOrStencil(image_format)) {
2334             skip |= LogError(image, "VUID-vkCmdClearDepthStencilImage-image-00014",
2335                              "vkCmdClearDepthStencilImage(): called with image %s which doesn't have a depth/stencil format (%s).",
2336                              report_data->FormatHandle(image).c_str(), string_VkFormat(image_format));
2337         }
2338         if (VK_IMAGE_USAGE_TRANSFER_DST_BIT != (VK_IMAGE_USAGE_TRANSFER_DST_BIT & image_state->createInfo.usage)) {
2339             skip |= LogError(image, "VUID-vkCmdClearDepthStencilImage-image-00009",
2340                              "vkCmdClearDepthStencilImage(): called with image %s which was not created with the "
2341                              "VK_IMAGE_USAGE_TRANSFER_DST_BIT set.",
2342                              report_data->FormatHandle(image).c_str());
2343         }
2344     }
2345     return skip;
2346 }
2347 
PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearDepthStencilValue * pDepthStencil,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)2348 void CoreChecks::PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
2349                                                         const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
2350                                                         const VkImageSubresourceRange *pRanges) {
2351     StateTracker::PreCallRecordCmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
2352     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
2353     auto image_state = Get<IMAGE_STATE>(image);
2354     if (cb_node && image_state) {
2355         for (uint32_t i = 0; i < rangeCount; ++i) {
2356             cb_node->SetImageInitialLayout(image, pRanges[i], imageLayout);
2357         }
2358     }
2359 }
2360 
2361 // Returns true if [x, xoffset] and [y, yoffset] overlap
RangesIntersect(int32_t start,uint32_t start_offset,int32_t end,uint32_t end_offset)2362 static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) {
2363     bool result = false;
2364     uint32_t intersection_min = std::max(static_cast<uint32_t>(start), static_cast<uint32_t>(end));
2365     uint32_t intersection_max = std::min(static_cast<uint32_t>(start) + start_offset, static_cast<uint32_t>(end) + end_offset);
2366 
2367     if (intersection_max > intersection_min) {
2368         result = true;
2369     }
2370     return result;
2371 }
2372 
2373 // Returns true if source area of first vkImageCopy/vkImageCopy2KHR region intersects dest area of second region
2374 // It is assumed that these are copy regions within a single image (otherwise no possibility of collision)
2375 template <typename RegionType>
RegionIntersects(const RegionType * rgn0,const RegionType * rgn1,VkImageType type,bool is_multiplane)2376 static bool RegionIntersects(const RegionType *rgn0, const RegionType *rgn1, VkImageType type, bool is_multiplane) {
2377     bool result = false;
2378 
2379     // Separate planes within a multiplane image cannot intersect
2380     if (is_multiplane && (rgn0->srcSubresource.aspectMask != rgn1->dstSubresource.aspectMask)) {
2381         return result;
2382     }
2383 
2384     if ((rgn0->srcSubresource.mipLevel == rgn1->dstSubresource.mipLevel) &&
2385         (RangesIntersect(rgn0->srcSubresource.baseArrayLayer, rgn0->srcSubresource.layerCount, rgn1->dstSubresource.baseArrayLayer,
2386                          rgn1->dstSubresource.layerCount))) {
2387         result = true;
2388         switch (type) {
2389             case VK_IMAGE_TYPE_3D:
2390                 result &= RangesIntersect(rgn0->srcOffset.z, rgn0->extent.depth, rgn1->dstOffset.z, rgn1->extent.depth);
2391                 // fall through
2392             case VK_IMAGE_TYPE_2D:
2393                 result &= RangesIntersect(rgn0->srcOffset.y, rgn0->extent.height, rgn1->dstOffset.y, rgn1->extent.height);
2394                 // fall through
2395             case VK_IMAGE_TYPE_1D:
2396                 result &= RangesIntersect(rgn0->srcOffset.x, rgn0->extent.width, rgn1->dstOffset.x, rgn1->extent.width);
2397                 break;
2398             default:
2399                 // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
2400                 assert(false);
2401         }
2402     }
2403     return result;
2404 }
2405 
2406 // Returns non-zero if offset and extent exceed image extents
2407 static const uint32_t kXBit = 1;
2408 static const uint32_t kYBit = 2;
2409 static const uint32_t kZBit = 4;
ExceedsBounds(const VkOffset3D * offset,const VkExtent3D * extent,const VkExtent3D * image_extent)2410 static uint32_t ExceedsBounds(const VkOffset3D *offset, const VkExtent3D *extent, const VkExtent3D *image_extent) {
2411     uint32_t result = 0;
2412     // Extents/depths cannot be negative but checks left in for clarity
2413     if ((offset->z + extent->depth > image_extent->depth) || (offset->z < 0) ||
2414         ((offset->z + static_cast<int32_t>(extent->depth)) < 0)) {
2415         result |= kZBit;
2416     }
2417     if ((offset->y + extent->height > image_extent->height) || (offset->y < 0) ||
2418         ((offset->y + static_cast<int32_t>(extent->height)) < 0)) {
2419         result |= kYBit;
2420     }
2421     if ((offset->x + extent->width > image_extent->width) || (offset->x < 0) ||
2422         ((offset->x + static_cast<int32_t>(extent->width)) < 0)) {
2423         result |= kXBit;
2424     }
2425     return result;
2426 }
2427 
2428 // Test if two VkExtent3D structs are equivalent
IsExtentEqual(const VkExtent3D * extent,const VkExtent3D * other_extent)2429 static inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
2430     bool result = true;
2431     if ((extent->width != other_extent->width) || (extent->height != other_extent->height) ||
2432         (extent->depth != other_extent->depth)) {
2433         result = false;
2434     }
2435     return result;
2436 }
2437 
2438 // Test if the extent argument has all dimensions set to 0.
IsExtentAllZeroes(const VkExtent3D * extent)2439 static inline bool IsExtentAllZeroes(const VkExtent3D *extent) {
2440     return ((extent->width == 0) && (extent->height == 0) && (extent->depth == 0));
2441 }
2442 
2443 // Returns the image transfer granularity for a specific image scaled by compressed block size if necessary.
GetScaledItg(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img) const2444 VkExtent3D CoreChecks::GetScaledItg(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img) const {
2445     // Default to (0, 0, 0) granularity in case we can't find the real granularity for the physical device.
2446     VkExtent3D granularity = {0, 0, 0};
2447     const auto pool = cb_node->command_pool;
2448     if (pool) {
2449         granularity = physical_device_state->queue_family_properties[pool->queueFamilyIndex].minImageTransferGranularity;
2450         if (FormatIsBlockedImage(img->createInfo.format)) {
2451             auto block_size = FormatTexelBlockExtent(img->createInfo.format);
2452             granularity.width *= block_size.width;
2453             granularity.height *= block_size.height;
2454         }
2455     }
2456     return granularity;
2457 }
2458 
2459 // Test elements of a VkExtent3D structure against alignment constraints contained in another VkExtent3D structure
IsExtentAligned(const VkExtent3D * extent,const VkExtent3D * granularity)2460 static inline bool IsExtentAligned(const VkExtent3D *extent, const VkExtent3D *granularity) {
2461     bool valid = true;
2462     if ((SafeModulo(extent->depth, granularity->depth) != 0) || (SafeModulo(extent->width, granularity->width) != 0) ||
2463         (SafeModulo(extent->height, granularity->height) != 0)) {
2464         valid = false;
2465     }
2466     return valid;
2467 }
2468 
2469 // Check elements of a VkOffset3D structure against a queue family's Image Transfer Granularity values
CheckItgOffset(const CMD_BUFFER_STATE * cb_node,const VkOffset3D * offset,const VkExtent3D * granularity,const uint32_t i,const char * function,const char * member,const char * vuid) const2470 bool CoreChecks::CheckItgOffset(const CMD_BUFFER_STATE *cb_node, const VkOffset3D *offset, const VkExtent3D *granularity,
2471                                 const uint32_t i, const char *function, const char *member, const char *vuid) const {
2472     bool skip = false;
2473     VkExtent3D offset_extent = {};
2474     offset_extent.width = static_cast<uint32_t>(abs(offset->x));
2475     offset_extent.height = static_cast<uint32_t>(abs(offset->y));
2476     offset_extent.depth = static_cast<uint32_t>(abs(offset->z));
2477     if (IsExtentAllZeroes(granularity)) {
2478         // If the queue family image transfer granularity is (0, 0, 0), then the offset must always be (0, 0, 0)
2479         if (IsExtentAllZeroes(&offset_extent) == false) {
2480             skip |= LogError(cb_node->commandBuffer(), vuid,
2481                              "%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 "
2482                              "image transfer granularity is (w=0, h=0, d=0).",
2483                              function, i, member, offset->x, offset->y, offset->z);
2484         }
2485     } else {
2486         // If the queue family image transfer granularity is not (0, 0, 0), then the offset dimensions must always be even
2487         // integer multiples of the image transfer granularity.
2488         if (IsExtentAligned(&offset_extent, granularity) == false) {
2489             skip |= LogError(cb_node->commandBuffer(), vuid,
2490                              "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) dimensions must be even integer multiples of this command "
2491                              "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d).",
2492                              function, i, member, offset->x, offset->y, offset->z, granularity->width, granularity->height,
2493                              granularity->depth);
2494         }
2495     }
2496     return skip;
2497 }
2498 
2499 // Check elements of a VkExtent3D structure against a queue family's Image Transfer Granularity values
CheckItgExtent(const CMD_BUFFER_STATE * cb_node,const VkExtent3D * extent,const VkOffset3D * offset,const VkExtent3D * granularity,const VkExtent3D * subresource_extent,const VkImageType image_type,const uint32_t i,const char * function,const char * member,const char * vuid) const2500 bool CoreChecks::CheckItgExtent(const CMD_BUFFER_STATE *cb_node, const VkExtent3D *extent, const VkOffset3D *offset,
2501                                 const VkExtent3D *granularity, const VkExtent3D *subresource_extent, const VkImageType image_type,
2502                                 const uint32_t i, const char *function, const char *member, const char *vuid) const {
2503     bool skip = false;
2504     if (IsExtentAllZeroes(granularity)) {
2505         // If the queue family image transfer granularity is (0, 0, 0), then the extent must always match the image
2506         // subresource extent.
2507         if (IsExtentEqual(extent, subresource_extent) == false) {
2508             skip |= LogError(cb_node->commandBuffer(), vuid,
2509                              "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d) "
2510                              "when the command buffer's queue family image transfer granularity is (w=0, h=0, d=0).",
2511                              function, i, member, extent->width, extent->height, extent->depth, subresource_extent->width,
2512                              subresource_extent->height, subresource_extent->depth);
2513         }
2514     } else {
2515         // If the queue family image transfer granularity is not (0, 0, 0), then the extent dimensions must always be even
2516         // integer multiples of the image transfer granularity or the offset + extent dimensions must always match the image
2517         // subresource extent dimensions.
2518         VkExtent3D offset_extent_sum = {};
2519         offset_extent_sum.width = static_cast<uint32_t>(abs(offset->x)) + extent->width;
2520         offset_extent_sum.height = static_cast<uint32_t>(abs(offset->y)) + extent->height;
2521         offset_extent_sum.depth = static_cast<uint32_t>(abs(offset->z)) + extent->depth;
2522         bool x_ok = true;
2523         bool y_ok = true;
2524         bool z_ok = true;
2525         switch (image_type) {
2526             case VK_IMAGE_TYPE_3D:
2527                 z_ok = ((0 == SafeModulo(extent->depth, granularity->depth)) ||
2528                         (subresource_extent->depth == offset_extent_sum.depth));
2529                 // fall through
2530             case VK_IMAGE_TYPE_2D:
2531                 y_ok = ((0 == SafeModulo(extent->height, granularity->height)) ||
2532                         (subresource_extent->height == offset_extent_sum.height));
2533                 // fall through
2534             case VK_IMAGE_TYPE_1D:
2535                 x_ok = ((0 == SafeModulo(extent->width, granularity->width)) ||
2536                         (subresource_extent->width == offset_extent_sum.width));
2537                 break;
2538             default:
2539                 // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
2540                 assert(false);
2541         }
2542         if (!(x_ok && y_ok && z_ok)) {
2543             skip |=
2544                 LogError(cb_node->commandBuffer(), vuid,
2545                          "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) dimensions must be even integer multiples of this command "
2546                          "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d) or offset (x=%d, y=%d, z=%d) + "
2547                          "extent (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d).",
2548                          function, i, member, extent->width, extent->height, extent->depth, granularity->width, granularity->height,
2549                          granularity->depth, offset->x, offset->y, offset->z, extent->width, extent->height, extent->depth,
2550                          subresource_extent->width, subresource_extent->height, subresource_extent->depth);
2551         }
2552     }
2553     return skip;
2554 }
2555 
ValidateImageMipLevel(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img,uint32_t mip_level,const uint32_t i,const char * function,const char * member,const char * vuid) const2556 bool CoreChecks::ValidateImageMipLevel(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, uint32_t mip_level,
2557                                        const uint32_t i, const char *function, const char *member, const char *vuid) const {
2558     bool skip = false;
2559     if (mip_level >= img->createInfo.mipLevels) {
2560         skip |= LogError(cb_node->commandBuffer(), vuid, "In %s, pRegions[%u].%s.mipLevel is %u, but provided %s has %u mip levels.",
2561                          function, i, member, mip_level, report_data->FormatHandle(img->image()).c_str(), img->createInfo.mipLevels);
2562     }
2563     return skip;
2564 }
2565 
ValidateImageArrayLayerRange(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img,const uint32_t base_layer,const uint32_t layer_count,const uint32_t i,const char * function,const char * member,const char * vuid) const2566 bool CoreChecks::ValidateImageArrayLayerRange(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, const uint32_t base_layer,
2567                                               const uint32_t layer_count, const uint32_t i, const char *function,
2568                                               const char *member, const char *vuid) const {
2569     bool skip = false;
2570     if (base_layer >= img->createInfo.arrayLayers || layer_count > img->createInfo.arrayLayers ||
2571         (base_layer + layer_count) > img->createInfo.arrayLayers) {
2572         skip |= LogError(cb_node->commandBuffer(), vuid,
2573                          "In %s, pRegions[%u].%s.baseArrayLayer is %u and .layerCount is "
2574                          "%u, but provided %s has %u array layers.",
2575                          function, i, member, base_layer, layer_count, report_data->FormatHandle(img->image()).c_str(),
2576                          img->createInfo.arrayLayers);
2577     }
2578     return skip;
2579 }
2580 
2581 // Check valid usage Image Transfer Granularity requirements for elements of a VkBufferImageCopy/VkBufferImageCopy2KHR structure
2582 template <typename BufferImageCopyRegionType>
ValidateCopyBufferImageTransferGranularityRequirements(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img,const BufferImageCopyRegionType * region,const uint32_t i,const char * function,const char * vuid) const2583 bool CoreChecks::ValidateCopyBufferImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img,
2584                                                                         const BufferImageCopyRegionType *region, const uint32_t i,
2585                                                                         const char *function, const char *vuid) const {
2586     bool skip = false;
2587     VkExtent3D granularity = GetScaledItg(cb_node, img);
2588     skip |= CheckItgOffset(cb_node, &region->imageOffset, &granularity, i, function, "imageOffset", vuid);
2589     VkExtent3D subresource_extent = img->GetSubresourceExtent(region->imageSubresource);
2590     skip |= CheckItgExtent(cb_node, &region->imageExtent, &region->imageOffset, &granularity, &subresource_extent,
2591                            img->createInfo.imageType, i, function, "imageExtent", vuid);
2592     return skip;
2593 }
2594 
2595 // Check valid usage Image Transfer Granularity requirements for elements of a VkImageCopy/VkImageCopy2KHR structure
2596 template <typename RegionType>
ValidateCopyImageTransferGranularityRequirements(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * src_img,const IMAGE_STATE * dst_img,const RegionType * region,const uint32_t i,const char * function,CopyCommandVersion version) const2597 bool CoreChecks::ValidateCopyImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *src_img,
2598                                                                   const IMAGE_STATE *dst_img, const RegionType *region,
2599                                                                   const uint32_t i, const char *function,
2600                                                                   CopyCommandVersion version) const {
2601     bool skip = false;
2602     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
2603     const char *vuid;
2604 
2605     // Source image checks
2606     VkExtent3D granularity = GetScaledItg(cb_node, src_img);
2607     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-01783" : "VUID-vkCmdCopyImage-srcOffset-01783";
2608     skip |= CheckItgOffset(cb_node, &region->srcOffset, &granularity, i, function, "srcOffset", vuid);
2609     VkExtent3D subresource_extent = src_img->GetSubresourceExtent(region->srcSubresource);
2610     const VkExtent3D extent = region->extent;
2611     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-01783" : "VUID-vkCmdCopyImage-srcOffset-01783";
2612     skip |= CheckItgExtent(cb_node, &extent, &region->srcOffset, &granularity, &subresource_extent, src_img->createInfo.imageType,
2613                            i, function, "extent", vuid);
2614 
2615     // Destination image checks
2616     granularity = GetScaledItg(cb_node, dst_img);
2617     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-01784" : "VUID-vkCmdCopyImage-dstOffset-01784";
2618     skip |= CheckItgOffset(cb_node, &region->dstOffset, &granularity, i, function, "dstOffset", vuid);
2619     // Adjust dest extent, if necessary
2620     const VkExtent3D dest_effective_extent =
2621         GetAdjustedDestImageExtent(src_img->createInfo.format, dst_img->createInfo.format, extent);
2622     subresource_extent = dst_img->GetSubresourceExtent(region->dstSubresource);
2623     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-01784" : "VUID-vkCmdCopyImage-dstOffset-01784";
2624     skip |= CheckItgExtent(cb_node, &dest_effective_extent, &region->dstOffset, &granularity, &subresource_extent,
2625                            dst_img->createInfo.imageType, i, function, "extent", vuid);
2626     return skip;
2627 }
2628 
2629 // Validate contents of a VkImageCopy or VkImageCopy2KHR struct
2630 template <typename ImageCopyRegionType>
ValidateImageCopyData(const uint32_t regionCount,const ImageCopyRegionType * ic_regions,const IMAGE_STATE * src_state,const IMAGE_STATE * dst_state,CopyCommandVersion version) const2631 bool CoreChecks::ValidateImageCopyData(const uint32_t regionCount, const ImageCopyRegionType *ic_regions,
2632                                        const IMAGE_STATE *src_state, const IMAGE_STATE *dst_state,
2633                                        CopyCommandVersion version) const {
2634     bool skip = false;
2635     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
2636     const char *func_name = is_2khr ? "vkCmdCopyImage2KHR()" : "vkCmdCopyImage()";
2637     const char *vuid;
2638 
2639     for (uint32_t i = 0; i < regionCount; i++) {
2640         const ImageCopyRegionType region = ic_regions[i];
2641 
2642         // For comp<->uncomp copies, the copy extent for the dest image must be adjusted
2643         const VkExtent3D src_copy_extent = region.extent;
2644         const VkExtent3D dst_copy_extent =
2645             GetAdjustedDestImageExtent(src_state->createInfo.format, dst_state->createInfo.format, region.extent);
2646 
2647         bool slice_override = false;
2648         uint32_t depth_slices = 0;
2649 
2650         // Special case for copying between a 1D/2D array and a 3D image
2651         // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
2652         if ((VK_IMAGE_TYPE_3D == src_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != dst_state->createInfo.imageType)) {
2653             depth_slices = region.dstSubresource.layerCount;  // Slice count from 2D subresource
2654             slice_override = (depth_slices != 1);
2655         } else if ((VK_IMAGE_TYPE_3D == dst_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != src_state->createInfo.imageType)) {
2656             depth_slices = region.srcSubresource.layerCount;  // Slice count from 2D subresource
2657             slice_override = (depth_slices != 1);
2658         }
2659 
2660         // Do all checks on source image
2661         if (src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
2662             if ((0 != region.srcOffset.y) || (1 != src_copy_extent.height)) {
2663                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00146" : "VUID-vkCmdCopyImage-srcImage-00146";
2664                 skip |= LogError(src_state->image(), vuid,
2665                                  "%s: pRegion[%d] srcOffset.y is %d and extent.height is %d. For 1D images these must "
2666                                  "be 0 and 1, respectively.",
2667                                  func_name, i, region.srcOffset.y, src_copy_extent.height);
2668             }
2669         }
2670 
2671         if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.srcOffset.z) || (1 != src_copy_extent.depth))) {
2672             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01785" : "VUID-vkCmdCopyImage-srcImage-01785";
2673             skip |= LogError(src_state->image(), vuid,
2674                              "%s: pRegion[%d] srcOffset.z is %d and extent.depth is %d. For 1D images "
2675                              "these must be 0 and 1, respectively.",
2676                              func_name, i, region.srcOffset.z, src_copy_extent.depth);
2677         }
2678 
2679         if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.srcOffset.z)) {
2680             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01787" : "VUID-vkCmdCopyImage-srcImage-01787";
2681             skip |= LogError(src_state->image(), vuid, "%s: pRegion[%d] srcOffset.z is %d. For 2D images the z-offset must be 0.",
2682                              func_name, i, region.srcOffset.z);
2683         }
2684 
2685         // Source checks that apply only to "blocked images"
2686         if (FormatIsBlockedImage(src_state->createInfo.format)) {
2687             const VkExtent3D block_size = FormatTexelBlockExtent(src_state->createInfo.format);
2688             //  image offsets must be multiples of block dimensions
2689             if ((SafeModulo(region.srcOffset.x, block_size.width) != 0) ||
2690                 (SafeModulo(region.srcOffset.y, block_size.height) != 0) ||
2691                 (SafeModulo(region.srcOffset.z, block_size.depth) != 0)) {
2692                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01727" : "VUID-vkCmdCopyImage-srcImage-01727";
2693                 skip |= LogError(src_state->image(), vuid,
2694                                  "%s: pRegion[%d] srcOffset (%d, %d) must be multiples of the blocked image's "
2695                                  "texel width & height (%d, %d).",
2696                                  func_name, i, region.srcOffset.x, region.srcOffset.y, block_size.width, block_size.height);
2697             }
2698 
2699             const VkExtent3D mip_extent = src_state->GetSubresourceExtent(region.srcSubresource);
2700             if ((SafeModulo(src_copy_extent.width, block_size.width) != 0) &&
2701                 (src_copy_extent.width + region.srcOffset.x != mip_extent.width)) {
2702                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01728" : "VUID-vkCmdCopyImage-srcImage-01728";
2703                 skip |= LogError(src_state->image(), vuid,
2704                                  "%s: pRegion[%d] extent width (%d) must be a multiple of the blocked texture block "
2705                                  "width (%d), or when added to srcOffset.x (%d) must equal the image subresource width (%d).",
2706                                  func_name, i, src_copy_extent.width, block_size.width, region.srcOffset.x, mip_extent.width);
2707             }
2708 
2709             // Extent height must be a multiple of block height, or extent+offset height must equal subresource height
2710             if ((SafeModulo(src_copy_extent.height, block_size.height) != 0) &&
2711                 (src_copy_extent.height + region.srcOffset.y != mip_extent.height)) {
2712                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01729" : "VUID-vkCmdCopyImage-srcImage-01729";
2713                 skip |= LogError(src_state->image(), vuid,
2714                                  "%s: pRegion[%d] extent height (%d) must be a multiple of the compressed texture block "
2715                                  "height (%d), or when added to srcOffset.y (%d) must equal the image subresource height (%d).",
2716                                  func_name, i, src_copy_extent.height, block_size.height, region.srcOffset.y, mip_extent.height);
2717             }
2718 
2719             // Extent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
2720             uint32_t copy_depth = (slice_override ? depth_slices : src_copy_extent.depth);
2721             if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.srcOffset.z != mip_extent.depth)) {
2722                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01730" : "VUID-vkCmdCopyImage-srcImage-01730";
2723                 skip |= LogError(src_state->image(), vuid,
2724                                  "%s: pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
2725                                  "depth (%d), or when added to srcOffset.z (%d) must equal the image subresource depth (%d).",
2726                                  func_name, i, src_copy_extent.depth, block_size.depth, region.srcOffset.z, mip_extent.depth);
2727             }
2728         }  // Compressed
2729 
2730         // Do all checks on dest image
2731         if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
2732             if ((0 != region.dstOffset.y) || (1 != dst_copy_extent.height)) {
2733                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-00152" : "VUID-vkCmdCopyImage-dstImage-00152";
2734                 skip |= LogError(dst_state->image(), vuid,
2735                                  "%s: pRegion[%d] dstOffset.y is %d and dst_copy_extent.height is %d. For 1D images "
2736                                  "these must be 0 and 1, respectively.",
2737                                  func_name, i, region.dstOffset.y, dst_copy_extent.height);
2738             }
2739         }
2740 
2741         if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.dstOffset.z) || (1 != dst_copy_extent.depth))) {
2742             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01786" : "VUID-vkCmdCopyImage-dstImage-01786";
2743             skip |= LogError(dst_state->image(), vuid,
2744                              "%s: pRegion[%d] dstOffset.z is %d and extent.depth is %d. For 1D images these must be 0 "
2745                              "and 1, respectively.",
2746                              func_name, i, region.dstOffset.z, dst_copy_extent.depth);
2747         }
2748 
2749         if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.dstOffset.z)) {
2750             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01788" : "VUID-vkCmdCopyImage-dstImage-01788";
2751             skip |= LogError(dst_state->image(), vuid, "%s: pRegion[%d] dstOffset.z is %d. For 2D images the z-offset must be 0.",
2752                              func_name, i, region.dstOffset.z);
2753         }
2754 
2755         // Handle difference between Maintenance 1
2756         if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
2757             if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2758                 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
2759                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-04443" : "VUID-vkCmdCopyImage-srcImage-04443";
2760                     skip |= LogError(src_state->image(), vuid,
2761                                      "%s: pRegion[%d] srcSubresource.baseArrayLayer is %d and srcSubresource.layerCount "
2762                                      "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2763                                      func_name, i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
2764                 }
2765             }
2766             if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2767                 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
2768                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-04444" : "VUID-vkCmdCopyImage-dstImage-04444";
2769                     skip |= LogError(dst_state->image(), vuid,
2770                                      "%s: pRegion[%d] dstSubresource.baseArrayLayer is %d and dstSubresource.layerCount "
2771                                      "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2772                                      func_name, i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
2773                 }
2774             }
2775         } else {  // Pre maint 1
2776             if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D || dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2777                 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
2778                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00139" : "VUID-vkCmdCopyImage-srcImage-00139";
2779                     skip |= LogError(src_state->image(), vuid,
2780                                      "%s: pRegion[%d] srcSubresource.baseArrayLayer is %d and "
2781                                      "srcSubresource.layerCount is %d. For copies with either source or dest of type "
2782                                      "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
2783                                      func_name, i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
2784                 }
2785                 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
2786                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00139" : "VUID-vkCmdCopyImage-srcImage-00139";
2787                     skip |= LogError(dst_state->image(), vuid,
2788                                      "%s: pRegion[%d] dstSubresource.baseArrayLayer is %d and "
2789                                      "dstSubresource.layerCount is %d. For copies with either source or dest of type "
2790                                      "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
2791                                      func_name, i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
2792                 }
2793             }
2794         }
2795 
2796         // Dest checks that apply only to "blocked images"
2797         if (FormatIsBlockedImage(dst_state->createInfo.format)) {
2798             const VkExtent3D block_size = FormatTexelBlockExtent(dst_state->createInfo.format);
2799 
2800             //  image offsets must be multiples of block dimensions
2801             if ((SafeModulo(region.dstOffset.x, block_size.width) != 0) ||
2802                 (SafeModulo(region.dstOffset.y, block_size.height) != 0) ||
2803                 (SafeModulo(region.dstOffset.z, block_size.depth) != 0)) {
2804                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01731" : "VUID-vkCmdCopyImage-dstImage-01731";
2805                 skip |= LogError(dst_state->image(), vuid,
2806                                  "%s: pRegion[%d] dstOffset (%d, %d) must be multiples of the blocked image's "
2807                                  "texel width & height (%d, %d).",
2808                                  func_name, i, region.dstOffset.x, region.dstOffset.y, block_size.width, block_size.height);
2809             }
2810 
2811             const VkExtent3D mip_extent = dst_state->GetSubresourceExtent(region.dstSubresource);
2812             if ((SafeModulo(dst_copy_extent.width, block_size.width) != 0) &&
2813                 (dst_copy_extent.width + region.dstOffset.x != mip_extent.width)) {
2814                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01732" : "VUID-vkCmdCopyImage-dstImage-01732";
2815                 skip |= LogError(dst_state->image(), vuid,
2816                                  "%s: pRegion[%d] dst_copy_extent width (%d) must be a multiple of the blocked texture "
2817                                  "block width (%d), or when added to dstOffset.x (%d) must equal the image subresource width (%d).",
2818                                  func_name, i, dst_copy_extent.width, block_size.width, region.dstOffset.x, mip_extent.width);
2819             }
2820 
2821             // Extent height must be a multiple of block height, or dst_copy_extent+offset height must equal subresource height
2822             if ((SafeModulo(dst_copy_extent.height, block_size.height) != 0) &&
2823                 (dst_copy_extent.height + region.dstOffset.y != mip_extent.height)) {
2824                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01733" : "VUID-vkCmdCopyImage-dstImage-01733";
2825                 skip |= LogError(dst_state->image(), vuid,
2826                                  "%s: pRegion[%d] dst_copy_extent height (%d) must be a multiple of the compressed "
2827                                  "texture block height (%d), or when added to dstOffset.y (%d) must equal the image subresource "
2828                                  "height (%d).",
2829                                  func_name, i, dst_copy_extent.height, block_size.height, region.dstOffset.y, mip_extent.height);
2830             }
2831 
2832             // Extent depth must be a multiple of block depth, or dst_copy_extent+offset depth must equal subresource depth
2833             uint32_t copy_depth = (slice_override ? depth_slices : dst_copy_extent.depth);
2834             if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.dstOffset.z != mip_extent.depth)) {
2835                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01734" : "VUID-vkCmdCopyImage-dstImage-01734";
2836                 skip |= LogError(dst_state->image(), vuid,
2837                                  "%s: pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
2838                                  "block depth (%d), or when added to dstOffset.z (%d) must equal the image subresource depth (%d).",
2839                                  func_name, i, dst_copy_extent.depth, block_size.depth, region.dstOffset.z, mip_extent.depth);
2840             }
2841         }  // Compressed
2842     }
2843     return skip;
2844 }
2845 
2846 template <typename RegionType>
ValidateCmdCopyImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const RegionType * pRegions,CopyCommandVersion version) const2847 bool CoreChecks::ValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
2848                                       VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
2849                                       const RegionType *pRegions, CopyCommandVersion version) const {
2850     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
2851     const auto src_image_state = Get<IMAGE_STATE>(srcImage);
2852     const auto dst_image_state = Get<IMAGE_STATE>(dstImage);
2853     const VkFormat src_format = src_image_state->createInfo.format;
2854     const VkFormat dst_format = dst_image_state->createInfo.format;
2855     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
2856     bool skip = false;
2857 
2858     const CMD_TYPE cmd_type = is_2khr ? CMD_COPYIMAGE2KHR : CMD_COPYIMAGE;
2859     const char *func_name = CommandTypeString(cmd_type);
2860     const char *vuid;
2861 
2862     skip = ValidateImageCopyData(regionCount, pRegions, src_image_state.get(), dst_image_state.get(), version);
2863 
2864     VkCommandBuffer command_buffer = cb_node->commandBuffer();
2865 
2866     for (uint32_t i = 0; i < regionCount; i++) {
2867         const RegionType region = pRegions[i];
2868 
2869         // For comp/uncomp copies, the copy extent for the dest image must be adjusted
2870         VkExtent3D src_copy_extent = region.extent;
2871         VkExtent3D dst_copy_extent = GetAdjustedDestImageExtent(src_format, dst_format, region.extent);
2872 
2873         bool slice_override = false;
2874         uint32_t depth_slices = 0;
2875 
2876         // Special case for copying between a 1D/2D array and a 3D image
2877         // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
2878         if ((VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType) &&
2879             (VK_IMAGE_TYPE_3D != dst_image_state->createInfo.imageType)) {
2880             depth_slices = region.dstSubresource.layerCount;  // Slice count from 2D subresource
2881             slice_override = (depth_slices != 1);
2882         } else if ((VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType) &&
2883                    (VK_IMAGE_TYPE_3D != src_image_state->createInfo.imageType)) {
2884             depth_slices = region.srcSubresource.layerCount;  // Slice count from 2D subresource
2885             slice_override = (depth_slices != 1);
2886         }
2887 
2888         skip |= ValidateImageSubresourceLayers(cb_node.get(), &region.srcSubresource, func_name, "srcSubresource", i);
2889         skip |= ValidateImageSubresourceLayers(cb_node.get(), &region.dstSubresource, func_name, "dstSubresource", i);
2890         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcSubresource-01696" : "VUID-vkCmdCopyImage-srcSubresource-01696";
2891         skip |= ValidateImageMipLevel(cb_node.get(), src_image_state.get(), region.srcSubresource.mipLevel, i, func_name,
2892                                       "srcSubresource", vuid);
2893         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstSubresource-01697" : "VUID-vkCmdCopyImage-dstSubresource-01697";
2894         skip |= ValidateImageMipLevel(cb_node.get(), dst_image_state.get(), region.dstSubresource.mipLevel, i, func_name,
2895                                       "dstSubresource", vuid);
2896         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcSubresource-01698" : "VUID-vkCmdCopyImage-srcSubresource-01698";
2897         skip |= ValidateImageArrayLayerRange(cb_node.get(), src_image_state.get(), region.srcSubresource.baseArrayLayer,
2898                                              region.srcSubresource.layerCount, i, func_name, "srcSubresource", vuid);
2899         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstSubresource-01699" : "VUID-vkCmdCopyImage-dstSubresource-01699";
2900         skip |= ValidateImageArrayLayerRange(cb_node.get(), dst_image_state.get(), region.dstSubresource.baseArrayLayer,
2901                                              region.dstSubresource.layerCount, i, func_name, "dstSubresource", vuid);
2902 
2903         if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
2904             // No chance of mismatch if we're overriding depth slice count
2905             if (!slice_override) {
2906                 // The number of depth slices in srcSubresource and dstSubresource must match
2907                 // Depth comes from layerCount for 1D,2D resources, from extent.depth for 3D
2908                 uint32_t src_slices =
2909                     (VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType ? src_copy_extent.depth
2910                                                                                : region.srcSubresource.layerCount);
2911                 uint32_t dst_slices =
2912                     (VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType ? dst_copy_extent.depth
2913                                                                                : region.dstSubresource.layerCount);
2914                 if (src_slices != dst_slices) {
2915                     vuid = is_2khr ? "VUID-VkImageCopy2KHR-extent-00140" : "VUID-VkImageCopy-extent-00140";
2916                     skip |= LogError(command_buffer, vuid,
2917                                      "%s: number of depth slices in source (%u) and destination (%u) subresources for pRegions[%u] "
2918                                      "do not match.",
2919                                      func_name, src_slices, dst_slices, i);
2920                 }
2921             }
2922         } else {
2923             // For each region the layerCount member of srcSubresource and dstSubresource must match
2924             if (region.srcSubresource.layerCount != region.dstSubresource.layerCount) {
2925                 vuid = is_2khr ? "VUID-VkImageCopy2KHR-layerCount-00138" : "VUID-VkImageCopy-layerCount-00138";
2926                 skip |=
2927                     LogError(command_buffer, vuid,
2928                              "%s: number of layers in source (%u) and destination (%u) subresources for pRegions[%u] do not match",
2929                              func_name, region.srcSubresource.layerCount, region.dstSubresource.layerCount, i);
2930             }
2931         }
2932 
2933         // Do multiplane-specific checks, if extension enabled
2934         if (IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)) {
2935             if ((!FormatIsMultiplane(src_format)) && (!FormatIsMultiplane(dst_format))) {
2936                 // If neither image is multi-plane the aspectMask member of src and dst must match
2937                 if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
2938                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01551" : "VUID-vkCmdCopyImage-srcImage-01551";
2939                     skip |= LogError(command_buffer, vuid,
2940                                      "%s: Copy between non-multiplane images with differing aspectMasks in pRegions[%u] with "
2941                                      "source (0x%x) destination (0x%x).",
2942                                      func_name, i, region.srcSubresource.aspectMask, region.dstSubresource.aspectMask);
2943                 }
2944             } else {
2945                 // Source image multiplane checks
2946                 uint32_t planes = FormatPlaneCount(src_format);
2947                 VkImageAspectFlags aspect = region.srcSubresource.aspectMask;
2948                 if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT)) {
2949                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01552" : "VUID-vkCmdCopyImage-srcImage-01552";
2950                     skip |= LogError(command_buffer, vuid,
2951                                      "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) is invalid for 2-plane format.", func_name,
2952                                      i, aspect);
2953                 }
2954                 if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT) &&
2955                     (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT)) {
2956                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01553" : "VUID-vkCmdCopyImage-srcImage-01553";
2957                     skip |= LogError(command_buffer, vuid,
2958                                      "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) is invalid for 3-plane format.", func_name,
2959                                      i, aspect);
2960                 }
2961                 // Single-plane to multi-plane
2962                 if ((!FormatIsMultiplane(src_format)) && (FormatIsMultiplane(dst_format)) &&
2963                     (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
2964                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01557" : "VUID-vkCmdCopyImage-dstImage-01557";
2965                     skip |= LogError(command_buffer, vuid,
2966                                      "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) is not VK_IMAGE_ASPECT_COLOR_BIT.",
2967                                      func_name, i, aspect);
2968                 }
2969 
2970                 // Dest image multiplane checks
2971                 planes = FormatPlaneCount(dst_format);
2972                 aspect = region.dstSubresource.aspectMask;
2973                 if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT)) {
2974                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01554" : "VUID-vkCmdCopyImage-dstImage-01554";
2975                     skip |= LogError(command_buffer, vuid,
2976                                      "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) is invalid for 2-plane format.", func_name,
2977                                      i, aspect);
2978                 }
2979                 if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT) &&
2980                     (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT)) {
2981                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01555" : "VUID-vkCmdCopyImage-dstImage-01555";
2982                     skip |= LogError(command_buffer, vuid,
2983                                      "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) is invalid for 3-plane format.", func_name,
2984                                      i, aspect);
2985                 }
2986                 // Multi-plane to single-plane
2987                 if ((FormatIsMultiplane(src_format)) && (!FormatIsMultiplane(dst_format)) &&
2988                     (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
2989                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01556" : "VUID-vkCmdCopyImage-srcImage-01556";
2990                     skip |= LogError(command_buffer, vuid,
2991                                      "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) is not VK_IMAGE_ASPECT_COLOR_BIT.",
2992                                      func_name, i, aspect);
2993                 }
2994             }
2995         } else {
2996             // !vk_khr_sampler_ycbcr_conversion
2997             // not multi-plane, the aspectMask member of srcSubresource and dstSubresource must match
2998             if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
2999                 vuid = is_2khr ? "VUID-VkImageCopy2KHR-aspectMask-00137" : "VUID-VkImageCopy-aspectMask-00137";
3000                 skip |= LogError(
3001                     command_buffer, vuid,
3002                     "%s: Copy between images with differing aspectMasks in pRegions[%u] with source (0x%x) destination (0x%x).",
3003                     func_name, i, region.srcSubresource.aspectMask, region.dstSubresource.aspectMask);
3004             }
3005         }
3006 
3007         // For each region, the aspectMask member of srcSubresource must be present in the source image
3008         if (!VerifyAspectsPresent(region.srcSubresource.aspectMask, src_format)) {
3009             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-aspectMask-00142" : "VUID-vkCmdCopyImage-aspectMask-00142";
3010             skip |=
3011                 LogError(command_buffer, vuid,
3012                          "%s: pRegions[%u].srcSubresource.aspectMask (0x%x) cannot specify aspects not present in source image.",
3013                          func_name, i, region.srcSubresource.aspectMask);
3014         }
3015 
3016         // For each region, the aspectMask member of dstSubresource must be present in the destination image
3017         if (!VerifyAspectsPresent(region.dstSubresource.aspectMask, dst_format)) {
3018             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-aspectMask-00143" : "VUID-vkCmdCopyImage-aspectMask-00143";
3019             skip |= LogError(
3020                 command_buffer, vuid,
3021                 "%s: pRegions[%u].dstSubresource.aspectMask (0x%x) cannot specify aspects not present in destination image.",
3022                 func_name, i, region.dstSubresource.aspectMask);
3023         }
3024 
3025         // Each dimension offset + extent limits must fall with image subresource extent
3026         VkExtent3D subresource_extent = src_image_state->GetSubresourceExtent(region.srcSubresource);
3027         if (slice_override) src_copy_extent.depth = depth_slices;
3028         uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &src_copy_extent, &subresource_extent);
3029         if (extent_check & kXBit) {
3030             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-00144" : "VUID-vkCmdCopyImage-srcOffset-00144";
3031             skip |= LogError(command_buffer, vuid,
3032                              "%s: Source image pRegion[%u] x-dimension offset [%1d] + extent [%1d] exceeds subResource "
3033                              "width [%1d].",
3034                              func_name, i, region.srcOffset.x, src_copy_extent.width, subresource_extent.width);
3035         }
3036 
3037         if (extent_check & kYBit) {
3038             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-00145" : "VUID-vkCmdCopyImage-srcOffset-00145";
3039             skip |= LogError(command_buffer, vuid,
3040                              "%s: Source image pRegion[%u] y-dimension offset [%1d] + extent [%1d] exceeds subResource "
3041                              "height [%1d].",
3042                              func_name, i, region.srcOffset.y, src_copy_extent.height, subresource_extent.height);
3043         }
3044         if (extent_check & kZBit) {
3045             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcOffset-00147" : "VUID-vkCmdCopyImage-srcOffset-00147";
3046             skip |= LogError(command_buffer, vuid,
3047                              "%s: Source image pRegion[%u] z-dimension offset [%1d] + extent [%1d] exceeds subResource "
3048                              "depth [%1d].",
3049                              func_name, i, region.srcOffset.z, src_copy_extent.depth, subresource_extent.depth);
3050         }
3051 
3052         // Adjust dest extent if necessary
3053         subresource_extent = dst_image_state->GetSubresourceExtent(region.dstSubresource);
3054         if (slice_override) dst_copy_extent.depth = depth_slices;
3055 
3056         extent_check = ExceedsBounds(&(region.dstOffset), &dst_copy_extent, &subresource_extent);
3057         if (extent_check & kXBit) {
3058             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-00150" : "VUID-vkCmdCopyImage-dstOffset-00150";
3059             skip |= LogError(command_buffer, vuid,
3060                              "%s: Dest image pRegion[%u] x-dimension offset [%1d] + extent [%1d] exceeds subResource "
3061                              "width [%1d].",
3062                              func_name, i, region.dstOffset.x, dst_copy_extent.width, subresource_extent.width);
3063         }
3064         if (extent_check & kYBit) {
3065             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-00151" : "VUID-vkCmdCopyImage-dstOffset-00151";
3066             skip |= LogError(command_buffer, vuid,
3067                              "%s): Dest image pRegion[%u] y-dimension offset [%1d] + extent [%1d] exceeds subResource "
3068                              "height [%1d].",
3069                              func_name, i, region.dstOffset.y, dst_copy_extent.height, subresource_extent.height);
3070         }
3071         if (extent_check & kZBit) {
3072             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstOffset-00153" : "VUID-vkCmdCopyImage-dstOffset-00153";
3073             skip |= LogError(command_buffer, vuid,
3074                              "%s: Dest image pRegion[%u] z-dimension offset [%1d] + extent [%1d] exceeds subResource "
3075                              "depth [%1d].",
3076                              func_name, i, region.dstOffset.z, dst_copy_extent.depth, subresource_extent.depth);
3077         }
3078 
3079         // The union of all source regions, and the union of all destination regions, specified by the elements of regions,
3080         // must not overlap in memory
3081         if (src_image_state->image() == dst_image_state->image()) {
3082             for (uint32_t j = 0; j < regionCount; j++) {
3083                 if (RegionIntersects(&region, &pRegions[j], src_image_state->createInfo.imageType,
3084                                      FormatIsMultiplane(src_format))) {
3085                     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-pRegions-00124" : "VUID-vkCmdCopyImage-pRegions-00124";
3086                     skip |= LogError(command_buffer, vuid, "%s: pRegion[%u] src overlaps with pRegions[%u].", func_name, i, j);
3087                 }
3088             }
3089         }
3090 
3091         // Check depth for 2D as post Maintaince 1 requires both while prior only required one to be 2D
3092         if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
3093             if (((VK_IMAGE_TYPE_2D == src_image_state->createInfo.imageType) &&
3094                  (VK_IMAGE_TYPE_2D == dst_image_state->createInfo.imageType)) &&
3095                 (src_copy_extent.depth != 1)) {
3096                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01790" : "VUID-vkCmdCopyImage-srcImage-01790";
3097                 skip |= LogError(command_buffer, vuid,
3098                                  "%s: pRegion[%u] both srcImage and dstImage are 2D and extent.depth is %u and has to be 1",
3099                                  func_name, i, src_copy_extent.depth);
3100             }
3101         } else {
3102             if (((VK_IMAGE_TYPE_2D == src_image_state->createInfo.imageType) ||
3103                  (VK_IMAGE_TYPE_2D == dst_image_state->createInfo.imageType)) &&
3104                 (src_copy_extent.depth != 1)) {
3105                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01789" : "VUID-vkCmdCopyImage-srcImage-01789";
3106                 skip |= LogError(command_buffer, vuid,
3107                                  "%s: pRegion[%u] either srcImage or dstImage is 2D and extent.depth is %u and has to be 1",
3108                                  func_name, i, src_copy_extent.depth);
3109             }
3110         }
3111 
3112         // Check if 2D with 3D and depth not equal to 2D layerCount
3113         if ((VK_IMAGE_TYPE_2D == src_image_state->createInfo.imageType) &&
3114             (VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType) &&
3115             (src_copy_extent.depth != region.srcSubresource.layerCount)) {
3116             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01791" : "VUID-vkCmdCopyImage-srcImage-01791";
3117             skip |= LogError(command_buffer, vuid,
3118                              "%s: pRegion[%u] srcImage is 2D, dstImage is 3D and extent.depth is %u and has to be "
3119                              "srcSubresource.layerCount (%u)",
3120                              func_name, i, src_copy_extent.depth, region.srcSubresource.layerCount);
3121         } else if ((VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType) &&
3122                    (VK_IMAGE_TYPE_2D == dst_image_state->createInfo.imageType) &&
3123                    (src_copy_extent.depth != region.dstSubresource.layerCount)) {
3124             vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01792" : "VUID-vkCmdCopyImage-dstImage-01792";
3125             skip |= LogError(command_buffer, vuid,
3126                              "%s: pRegion[%u] srcImage is 3D, dstImage is 2D and extent.depth is %u and has to be "
3127                              "dstSubresource.layerCount (%u)",
3128                              func_name, i, src_copy_extent.depth, region.dstSubresource.layerCount);
3129         }
3130 
3131         // Check for multi-plane format compatiblity
3132         if (FormatIsMultiplane(src_format) || FormatIsMultiplane(dst_format)) {
3133             const VkFormat src_plane_format = FormatIsMultiplane(src_format)
3134                                                   ? FindMultiplaneCompatibleFormat(src_format, region.srcSubresource.aspectMask)
3135                                                   : src_format;
3136             const VkFormat dst_plane_format = FormatIsMultiplane(dst_format)
3137                                                   ? FindMultiplaneCompatibleFormat(dst_format, region.dstSubresource.aspectMask)
3138                                                   : dst_format;
3139             const size_t src_format_size = FormatElementSize(src_plane_format);
3140             const size_t dst_format_size = FormatElementSize(dst_plane_format);
3141 
3142             // If size is still zero, then format is invalid and will be caught in another VU
3143             if ((src_format_size != dst_format_size) && (src_format_size != 0) && (dst_format_size != 0)) {
3144                 vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-None-01549" : "VUID-vkCmdCopyImage-None-01549";
3145                 skip |= LogError(command_buffer, vuid,
3146                                  "%s: pRegions[%u] called with non-compatible image formats. "
3147                                  "The src format %s with aspectMask %s is not compatible with dst format %s aspectMask %s.",
3148                                  func_name, i, string_VkFormat(src_format),
3149                                  string_VkImageAspectFlags(region.srcSubresource.aspectMask).c_str(), string_VkFormat(dst_format),
3150                                  string_VkImageAspectFlags(region.dstSubresource.aspectMask).c_str());
3151             }
3152         }
3153     }
3154 
3155     // The formats of non-multiplane src_image and dst_image must be compatible. Formats are considered compatible if their texel
3156     // size in bytes is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT
3157     // because because both texels are 4 bytes in size.
3158     if (!FormatIsMultiplane(src_format) && !FormatIsMultiplane(dst_format)) {
3159         const char *compatible_vuid =
3160             IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)
3161                 ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01548" : "VUID-vkCmdCopyImage-srcImage-01548")
3162                 : (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00135" : "VUID-vkCmdCopyImage-srcImage-00135");
3163         // Depth/stencil formats must match exactly.
3164         if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
3165             if (src_format != dst_format) {
3166                 skip |= LogError(command_buffer, compatible_vuid,
3167                                  "%s: Depth/stencil formats must match exactly for src (%s) and dst (%s).", func_name,
3168                                  string_VkFormat(src_format), string_VkFormat(dst_format));
3169             }
3170         } else {
3171             if (FormatElementSize(src_format) != FormatElementSize(dst_format)) {
3172                 skip |= LogError(command_buffer, compatible_vuid,
3173                                  "%s: Unmatched image format sizes. "
3174                                  "The src format %s has size of %" PRIu32 " and dst format %s has size of %" PRIu32 ".",
3175                                  func_name, string_VkFormat(src_format), FormatElementSize(src_format), string_VkFormat(dst_format),
3176                                  FormatElementSize(dst_format));
3177             }
3178         }
3179     }
3180 
3181     // Source and dest image sample counts must match
3182     if (src_image_state->createInfo.samples != dst_image_state->createInfo.samples) {
3183         std::stringstream ss;
3184         ss << func_name << " called on image pair with non-identical sample counts.";
3185         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00136" : "VUID-vkCmdCopyImage-srcImage-00136";
3186         skip |=
3187             LogError(command_buffer, vuid, "%s: The src image sample count (%s) dose not match the dst image sample count (%s).",
3188                      func_name, string_VkSampleCountFlagBits(src_image_state->createInfo.samples),
3189                      string_VkSampleCountFlagBits(dst_image_state->createInfo.samples));
3190     }
3191 
3192     vuid = IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)
3193                ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01546" : "VUID-vkCmdCopyImage-srcImage-01546")
3194                : (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00127" : "VUID-vkCmdCopyImage-srcImage-00127");
3195     skip |= ValidateMemoryIsBoundToImage(src_image_state.get(), func_name, vuid);
3196     vuid = IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)
3197                ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01547" : "VUID-vkCmdCopyImage-dstImage-01547")
3198                : (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-00132" : "VUID-vkCmdCopyImage-dstImage-00132");
3199     skip |= ValidateMemoryIsBoundToImage(dst_image_state.get(), func_name, vuid);
3200     // Validate that SRC & DST images have correct usage flags set
3201     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-00126" : "VUID-vkCmdCopyImage-srcImage-00126";
3202     skip |= ValidateImageUsageFlags(src_image_state.get(), VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
3203                                     "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
3204     vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-00131" : "VUID-vkCmdCopyImage-dstImage-00131";
3205     skip |= ValidateImageUsageFlags(dst_image_state.get(), VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
3206                                     "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
3207     vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-01825" : "VUID-vkCmdCopyImage-commandBuffer-01825";
3208     skip |= ValidateProtectedImage(cb_node.get(), src_image_state.get(), func_name, vuid);
3209     vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-01826" : "VUID-vkCmdCopyImage-commandBuffer-01826";
3210     skip |= ValidateProtectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
3211     vuid = is_2khr ? "VUID-vkCmdCopyImage2KHR-commandBuffer-01827" : "VUID-vkCmdCopyImage-commandBuffer-01827";
3212     skip |= ValidateUnprotectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
3213 
3214     // Validation for VK_EXT_fragment_density_map
3215     if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
3216         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-02542" : "VUID-vkCmdCopyImage-dstImage-02542";
3217         skip |=
3218             LogError(command_buffer, vuid,
3219                      "%s: srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT", func_name);
3220     }
3221     if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
3222         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-02542" : "VUID-vkCmdCopyImage-dstImage-02542";
3223         skip |=
3224             LogError(command_buffer, vuid,
3225                      "%s: dstImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT", func_name);
3226     }
3227 
3228     if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
3229         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImage-01995" : "VUID-vkCmdCopyImage-srcImage-01995";
3230         skip |= ValidateImageFormatFeatureFlags(src_image_state.get(), VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, func_name, vuid);
3231         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImage-01996" : "VUID-vkCmdCopyImage-dstImage-01996";
3232         skip |= ValidateImageFormatFeatureFlags(dst_image_state.get(), VK_FORMAT_FEATURE_TRANSFER_DST_BIT, func_name, vuid);
3233     }
3234     skip |= ValidateCmd(cb_node.get(), cmd_type);
3235     bool hit_error = false;
3236 
3237     const char *invalid_src_layout_vuid =
3238         (src_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
3239             ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImageLayout-01917" : "VUID-vkCmdCopyImage-srcImageLayout-01917")
3240             : (is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImageLayout-00129" : "VUID-vkCmdCopyImage-srcImageLayout-00129");
3241     const char *invalid_dst_layout_vuid =
3242         (dst_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
3243             ? (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImageLayout-01395" : "VUID-vkCmdCopyImage-dstImageLayout-01395")
3244             : (is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImageLayout-00134" : "VUID-vkCmdCopyImage-dstImageLayout-00134");
3245 
3246     for (uint32_t i = 0; i < regionCount; ++i) {
3247         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-srcImageLayout-00128" : "VUID-vkCmdCopyImage-srcImageLayout-00128";
3248         skip |= VerifyImageLayout(cb_node.get(), src_image_state.get(), pRegions[i].srcSubresource, srcImageLayout,
3249                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, invalid_src_layout_vuid, vuid, &hit_error);
3250         vuid = is_2khr ? "VUID-VkCopyImageInfo2KHR-dstImageLayout-00133" : "VUID-vkCmdCopyImage-dstImageLayout-00133";
3251         skip |= VerifyImageLayout(cb_node.get(), dst_image_state.get(), pRegions[i].dstSubresource, dstImageLayout,
3252                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, invalid_dst_layout_vuid, vuid, &hit_error);
3253         skip |= ValidateCopyImageTransferGranularityRequirements(cb_node.get(), src_image_state.get(), dst_image_state.get(),
3254                                                                  &pRegions[i], i, func_name, version);
3255     }
3256 
3257     return skip;
3258 }
3259 
PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageCopy * pRegions) const3260 bool CoreChecks::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3261                                              VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3262                                              const VkImageCopy *pRegions) const {
3263     return ValidateCmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions,
3264                                 COPY_COMMAND_VERSION_1);
3265 }
3266 
PreCallValidateCmdCopyImage2KHR(VkCommandBuffer commandBuffer,const VkCopyImageInfo2KHR * pCopyImageInfo) const3267 bool CoreChecks::PreCallValidateCmdCopyImage2KHR(VkCommandBuffer commandBuffer, const VkCopyImageInfo2KHR *pCopyImageInfo) const {
3268     return ValidateCmdCopyImage(commandBuffer, pCopyImageInfo->srcImage, pCopyImageInfo->srcImageLayout, pCopyImageInfo->dstImage,
3269                                 pCopyImageInfo->dstImageLayout, pCopyImageInfo->regionCount, pCopyImageInfo->pRegions,
3270                                 COPY_COMMAND_VERSION_2);
3271 }
3272 
PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageCopy * pRegions)3273 void CoreChecks::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3274                                            VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3275                                            const VkImageCopy *pRegions) {
3276     StateTracker::PreCallRecordCmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
3277                                             pRegions);
3278     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
3279     auto src_image_state = Get<IMAGE_STATE>(srcImage);
3280     auto dst_image_state = Get<IMAGE_STATE>(dstImage);
3281 
3282     // Make sure that all image slices are updated to correct layout
3283     for (uint32_t i = 0; i < regionCount; ++i) {
3284         cb_node->SetImageInitialLayout(*src_image_state, pRegions[i].srcSubresource, srcImageLayout);
3285         cb_node->SetImageInitialLayout(*dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
3286     }
3287 }
3288 
PreCallRecordCmdCopyImage2KHR(VkCommandBuffer commandBuffer,const VkCopyImageInfo2KHR * pCopyImageInfo)3289 void CoreChecks::PreCallRecordCmdCopyImage2KHR(VkCommandBuffer commandBuffer, const VkCopyImageInfo2KHR *pCopyImageInfo) {
3290     StateTracker::PreCallRecordCmdCopyImage2KHR(commandBuffer, pCopyImageInfo);
3291     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
3292     auto src_image_state = Get<IMAGE_STATE>(pCopyImageInfo->srcImage);
3293     auto dst_image_state = Get<IMAGE_STATE>(pCopyImageInfo->dstImage);
3294 
3295     // Make sure that all image slices are updated to correct layout
3296     for (uint32_t i = 0; i < pCopyImageInfo->regionCount; ++i) {
3297         cb_node->SetImageInitialLayout(*src_image_state, pCopyImageInfo->pRegions[i].srcSubresource,
3298                                        pCopyImageInfo->srcImageLayout);
3299         cb_node->SetImageInitialLayout(*dst_image_state, pCopyImageInfo->pRegions[i].dstSubresource,
3300                                        pCopyImageInfo->dstImageLayout);
3301     }
3302 }
3303 
3304 // Returns true if sub_rect is entirely contained within rect
ContainsRect(VkRect2D rect,VkRect2D sub_rect)3305 static inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
3306     if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
3307         (sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height)) {
3308         return false;
3309     }
3310     return true;
3311 }
3312 
ValidateClearAttachmentExtent(const CMD_BUFFER_STATE & cb_node,uint32_t attachment_index,const IMAGE_VIEW_STATE * image_view_state,const VkRect2D & render_area,uint32_t rect_count,const VkClearRect * clear_rects) const3313 bool CoreChecks::ValidateClearAttachmentExtent(const CMD_BUFFER_STATE &cb_node, uint32_t attachment_index,
3314                                                const IMAGE_VIEW_STATE* image_view_state,
3315                                                const VkRect2D &render_area, uint32_t rect_count, const VkClearRect *clear_rects) const {
3316     bool skip = false;
3317 
3318     for (uint32_t j = 0; j < rect_count; j++) {
3319         if (!ContainsRect(render_area, clear_rects[j].rect)) {
3320             skip |= LogError(cb_node.Handle(), "VUID-vkCmdClearAttachments-pRects-00016",
3321                              "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
3322                              "the current render pass instance.",
3323                              j);
3324         }
3325 
3326         if (image_view_state) {
3327             // The layers specified by a given element of pRects must be contained within every attachment that
3328             // pAttachments refers to
3329             const auto attachment_layer_count = image_view_state->normalized_subresource_range.layerCount;
3330             if ((clear_rects[j].baseArrayLayer >= attachment_layer_count) ||
3331                 (clear_rects[j].baseArrayLayer + clear_rects[j].layerCount > attachment_layer_count)) {
3332                 skip |= LogError(cb_node.Handle(), "VUID-vkCmdClearAttachments-pRects-00017",
3333                                  "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers "
3334                                  "of pAttachment[%d].",
3335                                  j, attachment_index);
3336             }
3337         }
3338     }
3339     return skip;
3340 }
3341 
PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer,uint32_t attachmentCount,const VkClearAttachment * pAttachments,uint32_t rectCount,const VkClearRect * pRects) const3342 bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
3343                                                     const VkClearAttachment *pAttachments, uint32_t rectCount,
3344                                                     const VkClearRect *pRects) const {
3345     bool skip = false;
3346     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);  // TODO: Should be const, and never modified during validation
3347     if (!cb_node) return skip;
3348 
3349     skip |= ValidateCmd(cb_node.get(), CMD_CLEARATTACHMENTS);
3350 
3351     // Validate that attachment is in reference list of active subpass
3352     if (cb_node->activeRenderPass) {
3353         const VkRenderPassCreateInfo2 *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
3354         const uint32_t renderpass_attachment_count = renderpass_create_info->attachmentCount;
3355         const VkSubpassDescription2 *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
3356         const auto *framebuffer = cb_node->activeFramebuffer.get();
3357         const auto &render_area = cb_node->activeRenderPassBeginInfo.renderArea;
3358 
3359         for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
3360             auto clear_desc = &pAttachments[attachment_index];
3361             uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
3362             const VkImageAspectFlags aspect_mask = clear_desc->aspectMask;
3363 
3364             if (aspect_mask & VK_IMAGE_ASPECT_METADATA_BIT) {
3365                 skip |= LogError(commandBuffer, "VUID-VkClearAttachment-aspectMask-00020",
3366                                  "vkCmdClearAttachments() pAttachments[%u] mask contains VK_IMAGE_ASPECT_METADATA_BIT",
3367                                  attachment_index);
3368             } else if (aspect_mask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
3369                                       VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
3370                 skip |=
3371                     LogError(commandBuffer, "VUID-VkClearAttachment-aspectMask-02246",
3372                              "vkCmdClearAttachments() pAttachments[%u] mask contains a VK_IMAGE_ASPECT_MEMORY_PLANE_*_BIT_EXT bit",
3373                              attachment_index);
3374             } else if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
3375                 uint32_t color_attachment = VK_ATTACHMENT_UNUSED;
3376                 if (subpass_desc) {
3377                     if (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount) {
3378                         color_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
3379                         if ((color_attachment != VK_ATTACHMENT_UNUSED) && (color_attachment >= renderpass_attachment_count)) {
3380                             skip |= LogError(
3381                                 commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02501",
3382                                 "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u is not VK_ATTACHMENT_UNUSED "
3383                                 "and not a valid attachment for %s attachmentCount=%u. Subpass %u pColorAttachment[%u]=%u.",
3384                                 attachment_index, clear_desc->colorAttachment,
3385                                 report_data->FormatHandle(cb_node->activeRenderPass->renderPass()).c_str(), cb_node->activeSubpass,
3386                                 clear_desc->colorAttachment, color_attachment, renderpass_attachment_count);
3387 
3388                             color_attachment = VK_ATTACHMENT_UNUSED;  // Defensive, prevent lookup past end of renderpass attachment
3389                         }
3390                     } else {
3391                         skip |= LogError(commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02501",
3392                                          "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u out of range for %s"
3393                                          " subpass %u. colorAttachmentCount=%u",
3394                                          attachment_index, clear_desc->colorAttachment,
3395                                          report_data->FormatHandle(cb_node->activeRenderPass->renderPass()).c_str(),
3396                                          cb_node->activeSubpass, subpass_desc->colorAttachmentCount);
3397                     }
3398                 }
3399                 fb_attachment = color_attachment;
3400 
3401                 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
3402                     (clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
3403                     skip |= LogError(commandBuffer, "VUID-VkClearAttachment-aspectMask-00019",
3404                                      "vkCmdClearAttachments() pAttachments[%u] aspectMask must set only VK_IMAGE_ASPECT_COLOR_BIT "
3405                                      "of a color attachment.",
3406                                      attachment_index);
3407                 }
3408             } else {  // Must be depth and/or stencil
3409                 bool subpass_depth = false;
3410                 bool subpass_stencil = false;
3411                 if (subpass_desc) {
3412                     if (subpass_desc->pDepthStencilAttachment &&
3413                         (subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
3414                         auto index = subpass_desc->pDepthStencilAttachment->attachment;
3415                         subpass_depth = FormatHasDepth(renderpass_create_info->pAttachments[index].format);
3416                         subpass_stencil = FormatHasStencil(renderpass_create_info->pAttachments[index].format);
3417                     }
3418                     if (!subpass_desc->pDepthStencilAttachment ||
3419                         (subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
3420                         if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) && !subpass_depth) {
3421                             skip |= LogError(
3422                                 commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02502",
3423                                 "vkCmdClearAttachments() pAttachments[%u] aspectMask has VK_IMAGE_ASPECT_DEPTH_BIT but there is no "
3424                                 "depth attachment in subpass",
3425                                 attachment_index);
3426                         }
3427                         if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && !subpass_stencil) {
3428                         skip |= LogError(
3429                             commandBuffer, "VUID-vkCmdClearAttachments-aspectMask-02503",
3430                             "vkCmdClearAttachments() pAttachments[%u] aspectMask has VK_IMAGE_ASPECT_STENCIL_BIT but there is no "
3431                                              "stencil attachment in subpass",
3432                                              attachment_index);
3433                         }
3434                     } else {
3435                         fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
3436                     }
3437                     if (subpass_depth) {
3438                         skip |= ValidateClearDepthStencilValue(commandBuffer, clear_desc->clearValue.depthStencil,
3439                                                                "vkCmdClearAttachments()");
3440                     }
3441                 }
3442             }
3443             if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
3444                 const IMAGE_VIEW_STATE* image_view_state = nullptr;
3445                 if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) && (fb_attachment < framebuffer->createInfo.attachmentCount)) {
3446                     image_view_state = cb_node->GetActiveAttachmentImageViewState(fb_attachment);
3447                 }
3448                 skip |= ValidateClearAttachmentExtent(*cb_node, attachment_index, image_view_state, render_area,
3449                                                       rectCount, pRects);
3450             }
3451 
3452             // Once the framebuffer attachment is found, can get the image view state
3453             if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) &&
3454                 (fb_attachment < framebuffer->createInfo.attachmentCount)) {
3455                 const auto *image_view_state = cb_node->GetActiveAttachmentImageViewState(fb_attachment);
3456                 if (image_view_state != nullptr) {
3457                     skip |= ValidateProtectedImage(cb_node.get(), image_view_state->image_state.get(), "vkCmdClearAttachments()",
3458                                                    "VUID-vkCmdClearAttachments-commandBuffer-02504");
3459                     skip |= ValidateUnprotectedImage(cb_node.get(), image_view_state->image_state.get(), "vkCmdClearAttachments()",
3460                                                      "VUID-vkCmdClearAttachments-commandBuffer-02505");
3461                 }
3462             }
3463 
3464             // When a subpass uses a non-zero view mask, multiview functionality is considered to be enabled
3465             if (subpass_desc && (subpass_desc->viewMask > 0)) {
3466                 for (uint32_t i = 0; i < rectCount; ++i) {
3467                     if (pRects[i].baseArrayLayer != 0 || pRects[i].layerCount != 1) {
3468                         skip |= LogError(commandBuffer, "VUID-vkCmdClearAttachments-baseArrayLayer-00018",
3469                                          "vkCmdClearAttachments(): pRects[%" PRIu32 "] baseArrayLayer is %" PRIu32
3470                                          " and layerCount is %" PRIu32 ", but the render pass instance uses multiview.",
3471                                          i, pRects[i].baseArrayLayer, pRects[i].layerCount);
3472                     }
3473                 }
3474             }
3475         }
3476     }
3477     return skip;
3478 }
3479 
PreCallRecordCmdClearAttachments(VkCommandBuffer commandBuffer,uint32_t attachmentCount,const VkClearAttachment * pAttachments,uint32_t rectCount,const VkClearRect * pRects)3480 void CoreChecks::PreCallRecordCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
3481                                                   const VkClearAttachment *pAttachments, uint32_t rectCount,
3482                                                   const VkClearRect *pRects) {
3483     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
3484     if (cb_node->activeRenderPass && (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)) {
3485         std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy;
3486         if (cb_node->activeRenderPass->use_dynamic_rendering_inherited) {
3487             for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
3488                 const auto clear_desc = &pAttachments[attachment_index];
3489                 auto colorAttachmentCount = cb_node->activeRenderPass->inheritance_rendering_info.colorAttachmentCount;
3490                 int image_index = -1;
3491                 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
3492                     (clear_desc->colorAttachment < colorAttachmentCount)) {
3493                     image_index = cb_node->GetDynamicColorAttachmentImageIndex(clear_desc->colorAttachment);
3494                 }
3495                 else if (clear_desc->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT)) {
3496                     image_index = cb_node->GetDynamicDepthAttachmentImageIndex();
3497                 }
3498                 else if (clear_desc->aspectMask & (VK_IMAGE_ASPECT_STENCIL_BIT)) {
3499                     image_index = cb_node->GetDynamicStencilAttachmentImageIndex();
3500                 }
3501 
3502                 if (image_index != -1) {
3503                     if (!clear_rect_copy) {
3504                         // We need a copy of the clear rectangles that will persist until the last lambda executes
3505                         // but we want to create it as lazily as possible
3506                         clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount));
3507                     }
3508                     // if a secondary level command buffer inherits the framebuffer from the primary command buffer
3509                     // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time
3510                     auto val_fn = [this, attachment_index, image_index, rectCount, clear_rect_copy](
3511                                         const CMD_BUFFER_STATE &secondary, const CMD_BUFFER_STATE *prim_cb,
3512                                         const FRAMEBUFFER_STATE *fb) {
3513                         assert(rectCount == clear_rect_copy->size());
3514                         bool skip = false;
3515                         const IMAGE_VIEW_STATE* image_view_state = nullptr;
3516                         if (image_index != -1) {
3517                             image_view_state = (*prim_cb->active_attachments)[image_index];
3518                         }
3519                         skip = ValidateClearAttachmentExtent(secondary, attachment_index, image_view_state,
3520                                                                 prim_cb->activeRenderPass->dynamic_rendering_begin_rendering_info.renderArea,
3521                                                                 rectCount, clear_rect_copy->data());
3522                         return skip;
3523                     };
3524                     cb_node->cmd_execute_commands_functions.emplace_back(val_fn);
3525                 }
3526             }
3527         }
3528         else if (cb_node->activeRenderPass->use_dynamic_rendering == false)
3529         {
3530             const VkRenderPassCreateInfo2* renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
3531             const VkSubpassDescription2* subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
3532 
3533             for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
3534                 const auto clear_desc = &pAttachments[attachment_index];
3535                 uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
3536                 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
3537                     (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount)) {
3538                     fb_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
3539                 }
3540                 else if ((clear_desc->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) &&
3541                     subpass_desc->pDepthStencilAttachment) {
3542                     fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
3543                 }
3544                 if (fb_attachment != VK_ATTACHMENT_UNUSED) {
3545                     if (!clear_rect_copy) {
3546                         // We need a copy of the clear rectangles that will persist until the last lambda executes
3547                         // but we want to create it as lazily as possible
3548                         clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount));
3549                     }
3550                     // if a secondary level command buffer inherits the framebuffer from the primary command buffer
3551                     // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time
3552                     auto val_fn = [this, attachment_index, fb_attachment, rectCount, clear_rect_copy](
3553                                       const CMD_BUFFER_STATE &secondary, const CMD_BUFFER_STATE *prim_cb,
3554                                       const FRAMEBUFFER_STATE *fb) {
3555                         assert(rectCount == clear_rect_copy->size());
3556                         const auto& render_area = prim_cb->activeRenderPassBeginInfo.renderArea;
3557                         bool skip = false;
3558                         const IMAGE_VIEW_STATE* image_view_state = nullptr;
3559                         if (fb && (fb_attachment != VK_ATTACHMENT_UNUSED) && (fb_attachment < fb->createInfo.attachmentCount)) {
3560                             image_view_state = prim_cb->GetActiveAttachmentImageViewState(fb_attachment);
3561                         }
3562                         skip = ValidateClearAttachmentExtent(secondary, attachment_index, image_view_state, render_area, rectCount,
3563                                                              clear_rect_copy->data());
3564                         return skip;
3565                     };
3566                     cb_node->cmd_execute_commands_functions.emplace_back(val_fn);
3567                 }
3568             }
3569         }
3570     }
3571 }
3572 
3573 template <typename RegionType>
ValidateCmdResolveImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const RegionType * pRegions,CopyCommandVersion version) const3574 bool CoreChecks::ValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3575                                          VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3576                                          const RegionType *pRegions, CopyCommandVersion version) const {
3577     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
3578     const auto src_image_state = Get<IMAGE_STATE>(srcImage);
3579     const auto dst_image_state = Get<IMAGE_STATE>(dstImage);
3580     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
3581     const CMD_TYPE cmd_type = is_2khr ? CMD_RESOLVEIMAGE2KHR : CMD_RESOLVEIMAGE;
3582     const char *func_name = CommandTypeString(cmd_type);
3583     const char *vuid;
3584 
3585     bool skip = false;
3586     if (cb_node && src_image_state && dst_image_state) {
3587         vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00256" : "VUID-vkCmdResolveImage-srcImage-00256";
3588         skip |= ValidateMemoryIsBoundToImage(src_image_state.get(), func_name, vuid);
3589         vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00258" : "VUID-vkCmdResolveImage-dstImage-00258";
3590         skip |= ValidateMemoryIsBoundToImage(dst_image_state.get(), func_name, vuid);
3591         skip |= ValidateCmd(cb_node.get(), cmd_type);
3592         vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-02003" : "VUID-vkCmdResolveImage-dstImage-02003";
3593         skip |= ValidateImageFormatFeatureFlags(dst_image_state.get(), VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, func_name, vuid);
3594         vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-01837" : "VUID-vkCmdResolveImage-commandBuffer-01837";
3595         skip |= ValidateProtectedImage(cb_node.get(), src_image_state.get(), func_name, vuid);
3596         vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-01838" : "VUID-vkCmdResolveImage-commandBuffer-01838";
3597         skip |= ValidateProtectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
3598         vuid = is_2khr ? "VUID-vkCmdResolveImage2KHR-commandBuffer-01839" : "VUID-vkCmdResolveImage-commandBuffer-01839";
3599         skip |= ValidateUnprotectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
3600 
3601         // Validation for VK_EXT_fragment_density_map
3602         if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
3603             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-02546" : "VUID-vkCmdResolveImage-dstImage-02546";
3604             skip |= LogError(cb_node->commandBuffer(), vuid,
3605                              "%s: srcImage must not have been created with flags containing "
3606                              "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3607                              func_name);
3608         }
3609         if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
3610             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-02546" : "VUID-vkCmdResolveImage-dstImage-02546";
3611             skip |= LogError(cb_node->commandBuffer(), vuid,
3612                              "%s: dstImage must not have been created with flags containing "
3613                              "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3614                              func_name);
3615         }
3616 
3617         bool hit_error = false;
3618         const char *invalid_src_layout_vuid =
3619             is_2khr ? ((src_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
3620                            ? "VUID-VkResolveImageInfo2KHR-srcImageLayout-01400"
3621                            : "VUID-VkResolveImageInfo2KHR-srcImageLayout-00261")
3622                     : ((src_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
3623                            ? "VUID-vkCmdResolveImage-srcImageLayout-01400"
3624                            : "VUID-vkCmdResolveImage-srcImageLayout-00261");
3625         const char *invalid_dst_layout_vuid =
3626             is_2khr ? ((dst_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
3627                            ? "VUID-VkResolveImageInfo2KHR-dstImageLayout-01401"
3628                            : "VUID-VkResolveImageInfo2KHR-dstImageLayout-00263")
3629                     : ((dst_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
3630                            ? "VUID-vkCmdResolveImage-dstImageLayout-01401"
3631                            : "VUID-vkCmdResolveImage-dstImageLayout-00263");
3632         // For each region, the number of layers in the image subresource should not be zero
3633         // For each region, src and dest image aspect must be color only
3634         for (uint32_t i = 0; i < regionCount; i++) {
3635             const RegionType region = pRegions[i];
3636             const VkImageSubresourceLayers src_subresource = region.srcSubresource;
3637             const VkImageSubresourceLayers dst_subresource = region.dstSubresource;
3638             skip |= ValidateImageSubresourceLayers(cb_node.get(), &src_subresource, func_name, "srcSubresource", i);
3639             skip |= ValidateImageSubresourceLayers(cb_node.get(), &dst_subresource, func_name, "dstSubresource", i);
3640             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImageLayout-00260" : "VUID-vkCmdResolveImage-srcImageLayout-00260";
3641             skip |= VerifyImageLayout(cb_node.get(), src_image_state.get(), src_subresource, srcImageLayout,
3642                                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, invalid_src_layout_vuid, vuid, &hit_error);
3643             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImageLayout-00262" : "VUID-vkCmdResolveImage-dstImageLayout-00262";
3644             skip |= VerifyImageLayout(cb_node.get(), dst_image_state.get(), dst_subresource, dstImageLayout,
3645                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, invalid_dst_layout_vuid, vuid, &hit_error);
3646             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcSubresource-01709" : "VUID-vkCmdResolveImage-srcSubresource-01709";
3647             skip |= ValidateImageMipLevel(cb_node.get(), src_image_state.get(), src_subresource.mipLevel, i, func_name,
3648                                           "srcSubresource", vuid);
3649             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstSubresource-01710" : "VUID-vkCmdResolveImage-dstSubresource-01710";
3650             skip |= ValidateImageMipLevel(cb_node.get(), dst_image_state.get(), dst_subresource.mipLevel, i, func_name,
3651                                           "dstSubresource", vuid);
3652             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcSubresource-01711" : "VUID-vkCmdResolveImage-srcSubresource-01711";
3653             skip |= ValidateImageArrayLayerRange(cb_node.get(), src_image_state.get(), src_subresource.baseArrayLayer,
3654                                                  src_subresource.layerCount, i, func_name, "srcSubresource", vuid);
3655             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstSubresource-01712" : "VUID-vkCmdResolveImage-dstSubresource-01712";
3656             skip |= ValidateImageArrayLayerRange(cb_node.get(), dst_image_state.get(), dst_subresource.baseArrayLayer,
3657                                                  dst_subresource.layerCount, i, func_name, "srcSubresource", vuid);
3658 
3659             // layer counts must match
3660             if (src_subresource.layerCount != dst_subresource.layerCount) {
3661                 vuid = is_2khr ? "VUID-VkImageResolve2KHR-layerCount-00267" : "VUID-VkImageResolve-layerCount-00267";
3662                 skip |=
3663                     LogError(cb_node->commandBuffer(), vuid,
3664                              "%s: layerCount in source and destination subresource of pRegions[%u] does not match.", func_name, i);
3665             }
3666             // For each region, src and dest image aspect must be color only
3667             if ((src_subresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
3668                 (dst_subresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)) {
3669                 vuid = is_2khr ? "VUID-VkImageResolve2KHR-aspectMask-00266" : "VUID-VkImageResolve-aspectMask-00266";
3670                 skip |= LogError(cb_node->commandBuffer(), vuid,
3671                                  "%s: src and dest aspectMasks for pRegions[%u] must specify only VK_IMAGE_ASPECT_COLOR_BIT.",
3672                                  func_name, i);
3673             }
3674 
3675             const VkImageType src_image_type = src_image_state->createInfo.imageType;
3676             const VkImageType dst_image_type = dst_image_state->createInfo.imageType;
3677 
3678             if ((VK_IMAGE_TYPE_3D == src_image_type) || (VK_IMAGE_TYPE_3D == dst_image_type)) {
3679                 if ((0 != src_subresource.baseArrayLayer) || (1 != src_subresource.layerCount)) {
3680                     LogObjectList objlist(cb_node->commandBuffer());
3681                     objlist.add(src_image_state->image());
3682                     objlist.add(dst_image_state->image());
3683                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-04446" : "VUID-vkCmdResolveImage-srcImage-04446";
3684                     skip |= LogError(objlist, vuid,
3685                                      "%s: pRegions[%u] baseArrayLayer must be 0 and layerCount must be 1 for all "
3686                                      "subresources if the src or dst image is 3D.",
3687                                      func_name, i);
3688                 }
3689                 if ((0 != dst_subresource.baseArrayLayer) || (1 != dst_subresource.layerCount)) {
3690                     LogObjectList objlist(cb_node->commandBuffer());
3691                     objlist.add(src_image_state->image());
3692                     objlist.add(dst_image_state->image());
3693                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-04447" : "VUID-vkCmdResolveImage-srcImage-04447";
3694                     skip |= LogError(objlist, vuid,
3695                                      "%s: pRegions[%u] baseArrayLayer must be 0 and layerCount must be 1 for all "
3696                                      "subresources if the src or dst image is 3D.",
3697                                      func_name, i);
3698                 }
3699             }
3700 
3701             if (VK_IMAGE_TYPE_1D == src_image_type) {
3702                 if ((pRegions[i].srcOffset.y != 0) || (pRegions[i].extent.height != 1)) {
3703                     LogObjectList objlist(cb_node->commandBuffer());
3704                     objlist.add(src_image_state->image());
3705                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00271" : "VUID-vkCmdResolveImage-srcImage-00271";
3706                     skip |= LogError(objlist, vuid,
3707                                      "%s: srcImage (%s) is 1D but pRegions[%u] srcOffset.y (%d) is not 0 or "
3708                                      "extent.height (%u) is not 1.",
3709                                      func_name, report_data->FormatHandle(src_image_state->image()).c_str(), i,
3710                                      pRegions[i].srcOffset.y, pRegions[i].extent.height);
3711                 }
3712             }
3713             if ((VK_IMAGE_TYPE_1D == src_image_type) || (VK_IMAGE_TYPE_2D == src_image_type)) {
3714                 if ((pRegions[i].srcOffset.z != 0) || (pRegions[i].extent.depth != 1)) {
3715                     LogObjectList objlist(cb_node->commandBuffer());
3716                     objlist.add(src_image_state->image());
3717                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00273" : "VUID-vkCmdResolveImage-srcImage-00273";
3718                     skip |= LogError(objlist, vuid,
3719                                      "%s: srcImage (%s) is 2D but pRegions[%u] srcOffset.z (%d) is not 0 or "
3720                                      "extent.depth (%u) is not 1.",
3721                                      func_name, report_data->FormatHandle(src_image_state->image()).c_str(), i,
3722                                      pRegions[i].srcOffset.z, pRegions[i].extent.depth);
3723                 }
3724             }
3725 
3726             if (VK_IMAGE_TYPE_1D == dst_image_type) {
3727                 if ((pRegions[i].dstOffset.y != 0) || (pRegions[i].extent.height != 1)) {
3728                     LogObjectList objlist(cb_node->commandBuffer());
3729                     objlist.add(dst_image_state->image());
3730                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00276" : "VUID-vkCmdResolveImage-dstImage-00276";
3731                     skip |= LogError(objlist, vuid,
3732                                      "%s: dstImage (%s) is 1D but pRegions[%u] dstOffset.y (%d) is not 0 or "
3733                                      "extent.height (%u) is not 1.",
3734                                      func_name, report_data->FormatHandle(dst_image_state->image()).c_str(), i,
3735                                      pRegions[i].dstOffset.y, pRegions[i].extent.height);
3736                 }
3737             }
3738             if ((VK_IMAGE_TYPE_1D == dst_image_type) || (VK_IMAGE_TYPE_2D == dst_image_type)) {
3739                 if ((pRegions[i].dstOffset.z != 0) || (pRegions[i].extent.depth != 1)) {
3740                     LogObjectList objlist(cb_node->commandBuffer());
3741                     objlist.add(dst_image_state->image());
3742                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00278" : "VUID-vkCmdResolveImage-dstImage-00278";
3743                     skip |= LogError(objlist, vuid,
3744                                      "%s: dstImage (%s) is 2D but pRegions[%u] dstOffset.z (%d) is not 0 or "
3745                                      "extent.depth (%u) is not 1.",
3746                                      func_name, report_data->FormatHandle(dst_image_state->image()).c_str(), i,
3747                                      pRegions[i].dstOffset.z, pRegions[i].extent.depth);
3748                 }
3749             }
3750 
3751             // Each srcImage dimension offset + extent limits must fall with image subresource extent
3752             VkExtent3D subresource_extent = src_image_state->GetSubresourceExtent(src_subresource);
3753             // MipLevel bound is checked already and adding extra errors with a "subresource extent of zero" is confusing to
3754             // developer
3755             if (src_subresource.mipLevel < src_image_state->createInfo.mipLevels) {
3756                 uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &(region.extent), &subresource_extent);
3757                 if ((extent_check & kXBit) != 0) {
3758                     LogObjectList objlist(cb_node->commandBuffer());
3759                     objlist.add(src_image_state->image());
3760                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcOffset-00269" : "VUID-vkCmdResolveImage-srcOffset-00269";
3761                     skip |= LogError(objlist, vuid,
3762                                      "%s: srcImage (%s) pRegions[%u] x-dimension offset [%1d] + extent [%u] "
3763                                      "exceeds subResource width [%u].",
3764                                      func_name, report_data->FormatHandle(src_image_state->image()).c_str(), i, region.srcOffset.x,
3765                                      region.extent.width, subresource_extent.width);
3766                 }
3767 
3768                 if ((extent_check & kYBit) != 0) {
3769                     LogObjectList objlist(cb_node->commandBuffer());
3770                     objlist.add(src_image_state->image());
3771                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcOffset-00270" : "VUID-vkCmdResolveImage-srcOffset-00270";
3772                     skip |= LogError(objlist, vuid,
3773                                      "%s: srcImage (%s) pRegions[%u] y-dimension offset [%1d] + extent [%u] "
3774                                      "exceeds subResource height [%u].",
3775                                      func_name, report_data->FormatHandle(src_image_state->image()).c_str(), i, region.srcOffset.y,
3776                                      region.extent.height, subresource_extent.height);
3777                 }
3778 
3779                 if ((extent_check & kZBit) != 0) {
3780                     LogObjectList objlist(cb_node->commandBuffer());
3781                     objlist.add(src_image_state->image());
3782                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcOffset-00272" : "VUID-vkCmdResolveImage-srcOffset-00272";
3783                     skip |= LogError(objlist, vuid,
3784                                      "%s: srcImage (%s) pRegions[%u] z-dimension offset [%1d] + extent [%u] "
3785                                      "exceeds subResource depth [%u].",
3786                                      func_name, report_data->FormatHandle(src_image_state->image()).c_str(), i, region.srcOffset.z,
3787                                      region.extent.depth, subresource_extent.depth);
3788                 }
3789             }
3790 
3791             // Each dstImage dimension offset + extent limits must fall with image subresource extent
3792             subresource_extent = dst_image_state->GetSubresourceExtent(dst_subresource);
3793             // MipLevel bound is checked already and adding extra errors with a "subresource extent of zero" is confusing to
3794             // developer
3795             if (dst_subresource.mipLevel < dst_image_state->createInfo.mipLevels) {
3796                 uint32_t extent_check = ExceedsBounds(&(region.dstOffset), &(region.extent), &subresource_extent);
3797                 if ((extent_check & kXBit) != 0) {
3798                     LogObjectList objlist(cb_node->commandBuffer());
3799                     objlist.add(dst_image_state->image());
3800                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstOffset-00274" : "VUID-vkCmdResolveImage-dstOffset-00274";
3801                     skip |= LogError(objlist, vuid,
3802                                      "%s: dstImage (%s) pRegions[%u] x-dimension offset [%1d] + extent [%u] "
3803                                      "exceeds subResource width [%u].",
3804                                      func_name, report_data->FormatHandle(dst_image_state->image()).c_str(), i, region.srcOffset.x,
3805                                      region.extent.width, subresource_extent.width);
3806                 }
3807 
3808                 if ((extent_check & kYBit) != 0) {
3809                     LogObjectList objlist(cb_node->commandBuffer());
3810                     objlist.add(dst_image_state->image());
3811                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstOffset-00275" : "VUID-vkCmdResolveImage-dstOffset-00275";
3812                     skip |= LogError(objlist, vuid,
3813                                      "%s: dstImage (%s) pRegions[%u] y-dimension offset [%1d] + extent [%u] "
3814                                      "exceeds subResource height [%u].",
3815                                      func_name, report_data->FormatHandle(dst_image_state->image()).c_str(), i, region.srcOffset.y,
3816                                      region.extent.height, subresource_extent.height);
3817                 }
3818 
3819                 if ((extent_check & kZBit) != 0) {
3820                     LogObjectList objlist(cb_node->commandBuffer());
3821                     objlist.add(dst_image_state->image());
3822                     vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstOffset-00277" : "VUID-vkCmdResolveImage-dstOffset-00277";
3823                     skip |= LogError(objlist, vuid,
3824                                      "%s: dstImage (%s) pRegions[%u] z-dimension offset [%1d] + extent [%u] "
3825                                      "exceeds subResource depth [%u].",
3826                                      func_name, report_data->FormatHandle(dst_image_state->image()).c_str(), i, region.srcOffset.z,
3827                                      region.extent.depth, subresource_extent.depth);
3828                 }
3829             }
3830         }
3831 
3832         if (src_image_state->createInfo.format != dst_image_state->createInfo.format) {
3833             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-01386" : "VUID-vkCmdResolveImage-srcImage-01386";
3834             skip |= LogError(cb_node->commandBuffer(), vuid, "%s: srcImage format (%s) and dstImage format (%s) are not the same.",
3835                              func_name, string_VkFormat(src_image_state->createInfo.format),
3836                              string_VkFormat(dst_image_state->createInfo.format));
3837         }
3838         if (src_image_state->createInfo.imageType != dst_image_state->createInfo.imageType) {
3839             skip |= LogWarning(cb_node->commandBuffer(), kVUID_Core_DrawState_MismatchedImageType,
3840                                "%s: srcImage type (%s) and dstImage type (%s) are not the same.", func_name,
3841                                string_VkImageType(src_image_state->createInfo.imageType),
3842                                string_VkImageType(dst_image_state->createInfo.imageType));
3843         }
3844         if (src_image_state->createInfo.samples == VK_SAMPLE_COUNT_1_BIT) {
3845             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-srcImage-00257" : "VUID-vkCmdResolveImage-srcImage-00257";
3846             skip |= LogError(cb_node->commandBuffer(), vuid, "%s: srcImage sample count is VK_SAMPLE_COUNT_1_BIT.", func_name);
3847         }
3848         if (dst_image_state->createInfo.samples != VK_SAMPLE_COUNT_1_BIT) {
3849             vuid = is_2khr ? "VUID-VkResolveImageInfo2KHR-dstImage-00259" : "VUID-vkCmdResolveImage-dstImage-00259";
3850             skip |= LogError(cb_node->commandBuffer(), vuid, "%s: dstImage sample count (%s) is not VK_SAMPLE_COUNT_1_BIT.",
3851                              func_name, string_VkSampleCountFlagBits(dst_image_state->createInfo.samples));
3852         }
3853     } else {
3854         assert(0);
3855     }
3856     return skip;
3857 }
3858 
PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageResolve * pRegions) const3859 bool CoreChecks::PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3860                                                 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3861                                                 const VkImageResolve *pRegions) const {
3862     return ValidateCmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions,
3863                                    COPY_COMMAND_VERSION_1);
3864 }
3865 
PreCallValidateCmdResolveImage2KHR(VkCommandBuffer commandBuffer,const VkResolveImageInfo2KHR * pResolveImageInfo) const3866 bool CoreChecks::PreCallValidateCmdResolveImage2KHR(VkCommandBuffer commandBuffer,
3867                                                     const VkResolveImageInfo2KHR *pResolveImageInfo) const {
3868     return ValidateCmdResolveImage(commandBuffer, pResolveImageInfo->srcImage, pResolveImageInfo->srcImageLayout,
3869                                    pResolveImageInfo->dstImage, pResolveImageInfo->dstImageLayout, pResolveImageInfo->regionCount,
3870                                    pResolveImageInfo->pRegions, COPY_COMMAND_VERSION_2);
3871 }
3872 
3873 template <typename RegionType>
ValidateCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const RegionType * pRegions,VkFilter filter,CopyCommandVersion version) const3874 bool CoreChecks::ValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3875                                       VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3876                                       const RegionType *pRegions, VkFilter filter, CopyCommandVersion version) const {
3877     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
3878     const auto src_image_state = Get<IMAGE_STATE>(srcImage);
3879     const auto dst_image_state = Get<IMAGE_STATE>(dstImage);
3880 
3881     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
3882     const CMD_TYPE cmd_type = is_2khr ? CMD_BLITIMAGE2KHR : CMD_BLITIMAGE;
3883     const char *func_name = CommandTypeString(cmd_type);
3884 
3885     bool skip = false;
3886     if (cb_node) {
3887         skip |= ValidateCmd(cb_node.get(), cmd_type);
3888     }
3889     if (cb_node && src_image_state && dst_image_state) {
3890         const char *vuid;
3891         const char *location;
3892         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00233" : "VUID-vkCmdBlitImage-srcImage-00233";
3893         location = is_2khr ? "vkCmdBlitImage2KHR(): pBlitImageInfo->srcImage" : "vkCmdBlitImage(): srcImage";
3894         skip |= ValidateImageSampleCount(src_image_state.get(), VK_SAMPLE_COUNT_1_BIT, location, vuid);
3895         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00234" : "VUID-vkCmdBlitImage-dstImage-00234";
3896         location = is_2khr ? "vkCmdBlitImage2KHR(): pBlitImageInfo->dstImage" : "vkCmdBlitImage(): dstImage";
3897         skip |= ValidateImageSampleCount(dst_image_state.get(), VK_SAMPLE_COUNT_1_BIT, location, vuid);
3898         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00220" : "VUID-vkCmdBlitImage-srcImage-00220";
3899         skip |= ValidateMemoryIsBoundToImage(src_image_state.get(), func_name, vuid);
3900         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00225" : "VUID-vkCmdBlitImage-dstImage-00225";
3901         skip |= ValidateMemoryIsBoundToImage(dst_image_state.get(), func_name, vuid);
3902         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00219" : "VUID-vkCmdBlitImage-srcImage-00219";
3903         skip |= ValidateImageUsageFlags(src_image_state.get(), VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
3904                                         "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
3905         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00224" : "VUID-vkCmdBlitImage-dstImage-00224";
3906         skip |= ValidateImageUsageFlags(dst_image_state.get(), VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
3907                                         "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
3908         skip |= ValidateCmd(cb_node.get(), cmd_type);
3909         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-01999" : "VUID-vkCmdBlitImage-srcImage-01999";
3910         skip |= ValidateImageFormatFeatureFlags(src_image_state.get(), VK_FORMAT_FEATURE_BLIT_SRC_BIT, func_name, vuid);
3911         vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-02000" : "VUID-vkCmdBlitImage-dstImage-02000";
3912         skip |= ValidateImageFormatFeatureFlags(dst_image_state.get(), VK_FORMAT_FEATURE_BLIT_DST_BIT, func_name, vuid);
3913         vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-01834" : "VUID-vkCmdBlitImage-commandBuffer-01834";
3914         skip |= ValidateProtectedImage(cb_node.get(), src_image_state.get(), func_name, vuid);
3915         vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-01835" : "VUID-vkCmdBlitImage-commandBuffer-01835";
3916         skip |= ValidateProtectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
3917         vuid = is_2khr ? "VUID-vkCmdBlitImage2KHR-commandBuffer-01836" : "VUID-vkCmdBlitImage-commandBuffer-01836";
3918         skip |= ValidateUnprotectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
3919 
3920         // Validation for VK_EXT_fragment_density_map
3921         if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
3922             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-02545" : "VUID-vkCmdBlitImage-dstImage-02545";
3923             skip |= LogError(cb_node->commandBuffer(), vuid,
3924                              "%s: srcImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3925                              func_name);
3926         }
3927         if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
3928             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-02545" : "VUID-vkCmdBlitImage-dstImage-02545";
3929             skip |= LogError(cb_node->commandBuffer(), vuid,
3930                              "%s: dstImage must not have been created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
3931                              func_name);
3932         }
3933 
3934         // TODO: Need to validate image layouts, which will include layout validation for shared presentable images
3935 
3936         VkFormat src_format = src_image_state->createInfo.format;
3937         VkFormat dst_format = dst_image_state->createInfo.format;
3938         VkImageType src_type = src_image_state->createInfo.imageType;
3939         VkImageType dst_type = dst_image_state->createInfo.imageType;
3940 
3941         if (VK_FILTER_LINEAR == filter) {
3942             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-filter-02001" : "VUID-vkCmdBlitImage-filter-02001";
3943             skip |= ValidateImageFormatFeatureFlags(src_image_state.get(), VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT,
3944                                                     func_name, vuid);
3945         } else if (VK_FILTER_CUBIC_IMG == filter) {
3946             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-filter-02002" : "VUID-vkCmdBlitImage-filter-02002";
3947             skip |= ValidateImageFormatFeatureFlags(src_image_state.get(), VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG,
3948                                                     func_name, vuid);
3949         }
3950 
3951         if (FormatRequiresYcbcrConversionExplicitly(src_format)) {
3952             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-06421" : "VUID-vkCmdBlitImage-srcImage-06421";
3953             skip |= LogError(device, vuid,
3954                              "%s: srcImage format (%s) must not be one of the formats requiring sampler YCBCR "
3955                              "conversion for VK_IMAGE_ASPECT_COLOR_BIT image views",
3956                              func_name, string_VkFormat(src_format));
3957         }
3958 
3959         if (FormatRequiresYcbcrConversionExplicitly(dst_format)) {
3960             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-06422" : "VUID-vkCmdBlitImage-dstImage-06422";
3961             skip |= LogError(device, vuid,
3962                              "%s: dstImage format (%s) must not be one of the formats requiring sampler YCBCR "
3963                              "conversion for VK_IMAGE_ASPECT_COLOR_BIT image views",
3964                              func_name, string_VkFormat(dst_format));
3965         }
3966 
3967         if ((VK_FILTER_CUBIC_IMG == filter) && (VK_IMAGE_TYPE_2D != src_type)) {
3968             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-filter-00237" : "VUID-vkCmdBlitImage-filter-00237";
3969             skip |= LogError(cb_node->commandBuffer(), vuid,
3970                              "%s: source image type must be VK_IMAGE_TYPE_2D when cubic filtering is specified.", func_name);
3971         }
3972 
3973         // Validate consistency for unsigned formats
3974         if (FormatIsUINT(src_format) != FormatIsUINT(dst_format)) {
3975             std::stringstream ss;
3976             ss << func_name << ": If one of srcImage and dstImage images has unsigned integer format, "
3977                << "the other one must also have unsigned integer format.  "
3978                << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
3979             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00230" : "VUID-vkCmdBlitImage-srcImage-00230";
3980             skip |= LogError(cb_node->commandBuffer(), vuid, "%s.", ss.str().c_str());
3981         }
3982 
3983         // Validate consistency for signed formats
3984         if (FormatIsSINT(src_format) != FormatIsSINT(dst_format)) {
3985             std::stringstream ss;
3986             ss << func_name << ": If one of srcImage and dstImage images has signed integer format, "
3987                << "the other one must also have signed integer format.  "
3988                << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
3989             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00229" : "VUID-vkCmdBlitImage-srcImage-00229";
3990             skip |= LogError(cb_node->commandBuffer(), vuid, "%s.", ss.str().c_str());
3991         }
3992 
3993         // Validate filter for Depth/Stencil formats
3994         if (FormatIsDepthOrStencil(src_format) && (filter != VK_FILTER_NEAREST)) {
3995             std::stringstream ss;
3996             ss << func_name << ": If the format of srcImage is a depth, stencil, or depth stencil "
3997                << "then filter must be VK_FILTER_NEAREST.";
3998             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00232" : "VUID-vkCmdBlitImage-srcImage-00232";
3999             skip |= LogError(cb_node->commandBuffer(), vuid, "%s.", ss.str().c_str());
4000         }
4001 
4002         // Validate aspect bits and formats for depth/stencil images
4003         if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
4004             if (src_format != dst_format) {
4005                 std::stringstream ss;
4006                 ss << func_name << ": If one of srcImage and dstImage images has a format of depth, stencil or depth "
4007                    << "stencil, the other one must have exactly the same format.  "
4008                    << "Source format is " << string_VkFormat(src_format) << " Destination format is "
4009                    << string_VkFormat(dst_format);
4010                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00231" : "VUID-vkCmdBlitImage-srcImage-00231";
4011                 skip |= LogError(cb_node->commandBuffer(), vuid, "%s.", ss.str().c_str());
4012             }
4013         }  // Depth or Stencil
4014 
4015         // Do per-region checks
4016         const char *invalid_src_layout_vuid =
4017             is_2khr ? ((src_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
4018                            ? "VUID-VkBlitImageInfo2KHR-srcImageLayout-01398"
4019                            : "VUID-VkBlitImageInfo2KHR-srcImageLayout-00222")
4020                     : ((src_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
4021                            ? "VUID-vkCmdBlitImage-srcImageLayout-01398"
4022                            : "VUID-vkCmdBlitImage-srcImageLayout-00222");
4023         const char *invalid_dst_layout_vuid =
4024             is_2khr ? ((dst_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
4025                            ? "VUID-VkBlitImageInfo2KHR-dstImageLayout-01399"
4026                            : "VUID-VkBlitImageInfo2KHR-dstImageLayout-00227")
4027                     : ((dst_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
4028                            ? "VUID-vkCmdBlitImage-dstImageLayout-01399"
4029                            : "VUID-vkCmdBlitImage-dstImageLayout-00227");
4030         for (uint32_t i = 0; i < regionCount; i++) {
4031             const RegionType rgn = pRegions[i];
4032             bool hit_error = false;
4033             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImageLayout-00221" : "VUID-vkCmdBlitImage-srcImageLayout-00221";
4034             skip |= VerifyImageLayout(cb_node.get(), src_image_state.get(), rgn.srcSubresource, srcImageLayout,
4035                                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, invalid_src_layout_vuid, vuid, &hit_error);
4036             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImageLayout-00226" : "VUID-vkCmdBlitImage-dstImageLayout-00226";
4037             skip |= VerifyImageLayout(cb_node.get(), dst_image_state.get(), rgn.dstSubresource, dstImageLayout,
4038                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, invalid_dst_layout_vuid, vuid, &hit_error);
4039             skip |= ValidateImageSubresourceLayers(cb_node.get(), &rgn.srcSubresource, func_name, "srcSubresource", i);
4040             skip |= ValidateImageSubresourceLayers(cb_node.get(), &rgn.dstSubresource, func_name, "dstSubresource", i);
4041             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcSubresource-01705" : "VUID-vkCmdBlitImage-srcSubresource-01705";
4042             skip |= ValidateImageMipLevel(cb_node.get(), src_image_state.get(), rgn.srcSubresource.mipLevel, i, func_name,
4043                                           "srcSubresource", vuid);
4044             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstSubresource-01706" : "VUID-vkCmdBlitImage-dstSubresource-01706";
4045             skip |= ValidateImageMipLevel(cb_node.get(), dst_image_state.get(), rgn.dstSubresource.mipLevel, i, func_name,
4046                                           "dstSubresource", vuid);
4047             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcSubresource-01707" : "VUID-vkCmdBlitImage-srcSubresource-01707";
4048             skip |= ValidateImageArrayLayerRange(cb_node.get(), src_image_state.get(), rgn.srcSubresource.baseArrayLayer,
4049                                                  rgn.srcSubresource.layerCount, i, func_name, "srcSubresource", vuid);
4050             vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstSubresource-01708" : "VUID-vkCmdBlitImage-dstSubresource-01708";
4051             skip |= ValidateImageArrayLayerRange(cb_node.get(), dst_image_state.get(), rgn.dstSubresource.baseArrayLayer,
4052                                                  rgn.dstSubresource.layerCount, i, func_name, "dstSubresource", vuid);
4053             // Warn for zero-sized regions
4054             if ((rgn.srcOffsets[0].x == rgn.srcOffsets[1].x) || (rgn.srcOffsets[0].y == rgn.srcOffsets[1].y) ||
4055                 (rgn.srcOffsets[0].z == rgn.srcOffsets[1].z)) {
4056                 std::stringstream ss;
4057                 ss << func_name << ": pRegions[" << i << "].srcOffsets specify a zero-volume area.";
4058                 skip |= LogWarning(cb_node->commandBuffer(), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
4059             }
4060             if ((rgn.dstOffsets[0].x == rgn.dstOffsets[1].x) || (rgn.dstOffsets[0].y == rgn.dstOffsets[1].y) ||
4061                 (rgn.dstOffsets[0].z == rgn.dstOffsets[1].z)) {
4062                 std::stringstream ss;
4063                 ss << func_name << ": pRegions[" << i << "].dstOffsets specify a zero-volume area.";
4064                 skip |= LogWarning(cb_node->commandBuffer(), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
4065             }
4066 
4067             // Check that src/dst layercounts match
4068             if (rgn.srcSubresource.layerCount != rgn.dstSubresource.layerCount) {
4069                 vuid = is_2khr ? "VUID-VkImageBlit2KHR-layerCount-00239" : "VUID-VkImageBlit-layerCount-00239";
4070                 skip |=
4071                     LogError(cb_node->commandBuffer(), vuid,
4072                              "%s: layerCount in source and destination subresource of pRegions[%d] does not match.", func_name, i);
4073             }
4074 
4075             if (rgn.srcSubresource.aspectMask != rgn.dstSubresource.aspectMask) {
4076                 vuid = is_2khr ? "VUID-VkImageBlit2KHR-aspectMask-00238" : "VUID-VkImageBlit-aspectMask-00238";
4077                 skip |=
4078                     LogError(cb_node->commandBuffer(), vuid, "%s: aspectMask members for pRegion[%d] do not match.", func_name, i);
4079             }
4080 
4081             if (!VerifyAspectsPresent(rgn.srcSubresource.aspectMask, src_format)) {
4082                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-aspectMask-00241" : "VUID-vkCmdBlitImage-aspectMask-00241";
4083                 skip |= LogError(cb_node->commandBuffer(), vuid,
4084                                  "%s: region [%d] source aspectMask (0x%x) specifies aspects not present in source "
4085                                  "image format %s.",
4086                                  func_name, i, rgn.srcSubresource.aspectMask, string_VkFormat(src_format));
4087             }
4088 
4089             if (!VerifyAspectsPresent(rgn.dstSubresource.aspectMask, dst_format)) {
4090                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-aspectMask-00242" : "VUID-vkCmdBlitImage-aspectMask-00242";
4091                 skip |= LogError(cb_node->commandBuffer(), vuid,
4092                                  "%s: region [%d] dest aspectMask (0x%x) specifies aspects not present in dest image format %s.",
4093                                  func_name, i, rgn.dstSubresource.aspectMask, string_VkFormat(dst_format));
4094             }
4095 
4096             // Validate source image offsets
4097             VkExtent3D src_extent = src_image_state->GetSubresourceExtent(rgn.srcSubresource);
4098             if (VK_IMAGE_TYPE_1D == src_type) {
4099                 if ((0 != rgn.srcOffsets[0].y) || (1 != rgn.srcOffsets[1].y)) {
4100                     vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00245" : "VUID-vkCmdBlitImage-srcImage-00245";
4101                     skip |= LogError(cb_node->commandBuffer(), vuid,
4102                                      "%s: region [%d], source image of type VK_IMAGE_TYPE_1D with srcOffset[].y values "
4103                                      "of (%1d, %1d). These must be (0, 1).",
4104                                      func_name, i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y);
4105                 }
4106             }
4107 
4108             if ((VK_IMAGE_TYPE_1D == src_type) || (VK_IMAGE_TYPE_2D == src_type)) {
4109                 if ((0 != rgn.srcOffsets[0].z) || (1 != rgn.srcOffsets[1].z)) {
4110                     vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00247" : "VUID-vkCmdBlitImage-srcImage-00247";
4111                     skip |= LogError(cb_node->commandBuffer(), vuid,
4112                                      "%s: region [%d], source image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
4113                                      "srcOffset[].z values of (%1d, %1d). These must be (0, 1).",
4114                                      func_name, i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z);
4115                 }
4116             }
4117 
4118             bool oob = false;
4119             if ((rgn.srcOffsets[0].x < 0) || (rgn.srcOffsets[0].x > static_cast<int32_t>(src_extent.width)) ||
4120                 (rgn.srcOffsets[1].x < 0) || (rgn.srcOffsets[1].x > static_cast<int32_t>(src_extent.width))) {
4121                 oob = true;
4122                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcOffset-00243" : "VUID-vkCmdBlitImage-srcOffset-00243";
4123                 skip |= LogError(cb_node->commandBuffer(), vuid,
4124                                  "%s: region [%d] srcOffset[].x values (%1d, %1d) exceed srcSubresource width extent (%1d).",
4125                                  func_name, i, rgn.srcOffsets[0].x, rgn.srcOffsets[1].x, src_extent.width);
4126             }
4127             if ((rgn.srcOffsets[0].y < 0) || (rgn.srcOffsets[0].y > static_cast<int32_t>(src_extent.height)) ||
4128                 (rgn.srcOffsets[1].y < 0) || (rgn.srcOffsets[1].y > static_cast<int32_t>(src_extent.height))) {
4129                 oob = true;
4130                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcOffset-00244" : "VUID-vkCmdBlitImage-srcOffset-00244";
4131                 skip |= LogError(cb_node->commandBuffer(), vuid,
4132                                  "%s: region [%d] srcOffset[].y values (%1d, %1d) exceed srcSubresource height extent (%1d).",
4133                                  func_name, i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y, src_extent.height);
4134             }
4135             if ((rgn.srcOffsets[0].z < 0) || (rgn.srcOffsets[0].z > static_cast<int32_t>(src_extent.depth)) ||
4136                 (rgn.srcOffsets[1].z < 0) || (rgn.srcOffsets[1].z > static_cast<int32_t>(src_extent.depth))) {
4137                 oob = true;
4138                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcOffset-00246" : "VUID-vkCmdBlitImage-srcOffset-00246";
4139                 skip |= LogError(cb_node->commandBuffer(), vuid,
4140                                  "%s: region [%d] srcOffset[].z values (%1d, %1d) exceed srcSubresource depth extent (%1d).",
4141                                  func_name, i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z, src_extent.depth);
4142             }
4143             if (oob) {
4144                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-pRegions-00215" : "VUID-vkCmdBlitImage-pRegions-00215";
4145                 skip |= LogError(cb_node->commandBuffer(), vuid, "%s: region [%d] source image blit region exceeds image dimensions.",
4146                                  func_name, i);
4147             }
4148 
4149             // Validate dest image offsets
4150             VkExtent3D dst_extent = dst_image_state->GetSubresourceExtent(rgn.dstSubresource);
4151             if (VK_IMAGE_TYPE_1D == dst_type) {
4152                 if ((0 != rgn.dstOffsets[0].y) || (1 != rgn.dstOffsets[1].y)) {
4153                     vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00250" : "VUID-vkCmdBlitImage-dstImage-00250";
4154                     skip |= LogError(cb_node->commandBuffer(), vuid,
4155                                      "%s: region [%d], dest image of type VK_IMAGE_TYPE_1D with dstOffset[].y values of "
4156                                      "(%1d, %1d). These must be (0, 1).",
4157                                      func_name, i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y);
4158                 }
4159             }
4160 
4161             if ((VK_IMAGE_TYPE_1D == dst_type) || (VK_IMAGE_TYPE_2D == dst_type)) {
4162                 if ((0 != rgn.dstOffsets[0].z) || (1 != rgn.dstOffsets[1].z)) {
4163                     vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstImage-00252" : "VUID-vkCmdBlitImage-dstImage-00252";
4164                     skip |= LogError(cb_node->commandBuffer(), vuid,
4165                                      "%s: region [%d], dest image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
4166                                      "dstOffset[].z values of (%1d, %1d). These must be (0, 1).",
4167                                      func_name, i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z);
4168                 }
4169             }
4170 
4171             oob = false;
4172             if ((rgn.dstOffsets[0].x < 0) || (rgn.dstOffsets[0].x > static_cast<int32_t>(dst_extent.width)) ||
4173                 (rgn.dstOffsets[1].x < 0) || (rgn.dstOffsets[1].x > static_cast<int32_t>(dst_extent.width))) {
4174                 oob = true;
4175                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstOffset-00248" : "VUID-vkCmdBlitImage-dstOffset-00248";
4176                 skip |= LogError(cb_node->commandBuffer(), vuid,
4177                                  "%s: region [%d] dstOffset[].x values (%1d, %1d) exceed dstSubresource width extent (%1d).",
4178                                  func_name, i, rgn.dstOffsets[0].x, rgn.dstOffsets[1].x, dst_extent.width);
4179             }
4180             if ((rgn.dstOffsets[0].y < 0) || (rgn.dstOffsets[0].y > static_cast<int32_t>(dst_extent.height)) ||
4181                 (rgn.dstOffsets[1].y < 0) || (rgn.dstOffsets[1].y > static_cast<int32_t>(dst_extent.height))) {
4182                 oob = true;
4183                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstOffset-00249" : "VUID-vkCmdBlitImage-dstOffset-00249";
4184                 skip |= LogError(cb_node->commandBuffer(), vuid,
4185                                  "%s: region [%d] dstOffset[].y values (%1d, %1d) exceed dstSubresource height extent (%1d).",
4186                                  func_name, i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y, dst_extent.height);
4187             }
4188             if ((rgn.dstOffsets[0].z < 0) || (rgn.dstOffsets[0].z > static_cast<int32_t>(dst_extent.depth)) ||
4189                 (rgn.dstOffsets[1].z < 0) || (rgn.dstOffsets[1].z > static_cast<int32_t>(dst_extent.depth))) {
4190                 oob = true;
4191                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-dstOffset-00251" : "VUID-vkCmdBlitImage-dstOffset-00251";
4192                 skip |= LogError(cb_node->commandBuffer(), vuid,
4193                                  "%s: region [%d] dstOffset[].z values (%1d, %1d) exceed dstSubresource depth extent (%1d).",
4194                                  func_name, i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z, dst_extent.depth);
4195             }
4196             if (oob) {
4197                 vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-pRegions-00216" : "VUID-vkCmdBlitImage-pRegions-00216";
4198                 skip |= LogError(cb_node->commandBuffer(), vuid,
4199                                  "%s: region [%d] destination image blit region exceeds image dimensions.", func_name, i);
4200             }
4201 
4202             if ((VK_IMAGE_TYPE_3D == src_type) || (VK_IMAGE_TYPE_3D == dst_type)) {
4203                 if ((0 != rgn.srcSubresource.baseArrayLayer) || (1 != rgn.srcSubresource.layerCount) ||
4204                     (0 != rgn.dstSubresource.baseArrayLayer) || (1 != rgn.dstSubresource.layerCount)) {
4205                     vuid = is_2khr ? "VUID-VkBlitImageInfo2KHR-srcImage-00240" : "VUID-vkCmdBlitImage-srcImage-00240";
4206                     skip |= LogError(cb_node->commandBuffer(), vuid,
4207                                      "%s: region [%d] blit to/from a 3D image type with a non-zero baseArrayLayer, or a "
4208                                      "layerCount other than 1.",
4209                                      func_name, i);
4210                 }
4211             }
4212         }  // per-region checks
4213     } else {
4214         assert(0);
4215     }
4216     return skip;
4217 }
4218 
PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageBlit * pRegions,VkFilter filter) const4219 bool CoreChecks::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
4220                                              VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
4221                                              const VkImageBlit *pRegions, VkFilter filter) const {
4222     return ValidateCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter,
4223                                 COPY_COMMAND_VERSION_1);
4224 }
4225 
PreCallValidateCmdBlitImage2KHR(VkCommandBuffer commandBuffer,const VkBlitImageInfo2KHR * pBlitImageInfo) const4226 bool CoreChecks::PreCallValidateCmdBlitImage2KHR(VkCommandBuffer commandBuffer, const VkBlitImageInfo2KHR *pBlitImageInfo) const {
4227     return ValidateCmdBlitImage(commandBuffer, pBlitImageInfo->srcImage, pBlitImageInfo->srcImageLayout, pBlitImageInfo->dstImage,
4228                                 pBlitImageInfo->dstImageLayout, pBlitImageInfo->regionCount, pBlitImageInfo->pRegions,
4229                                 pBlitImageInfo->filter, COPY_COMMAND_VERSION_2);
4230 }
4231 
4232 template <typename RegionType>
RecordCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const RegionType * pRegions,VkFilter filter)4233 void CoreChecks::RecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
4234                                     VkImageLayout dstImageLayout, uint32_t regionCount, const RegionType *pRegions,
4235                                     VkFilter filter) {
4236     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
4237     auto src_image_state = Get<IMAGE_STATE>(srcImage);
4238     auto dst_image_state = Get<IMAGE_STATE>(dstImage);
4239 
4240     // Make sure that all image slices are updated to correct layout
4241     for (uint32_t i = 0; i < regionCount; ++i) {
4242         cb_node->SetImageInitialLayout(*src_image_state, pRegions[i].srcSubresource, srcImageLayout);
4243         cb_node->SetImageInitialLayout(*dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
4244     }
4245 }
4246 
PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageBlit * pRegions,VkFilter filter)4247 void CoreChecks::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
4248                                            VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
4249                                            const VkImageBlit *pRegions, VkFilter filter) {
4250     StateTracker::PreCallRecordCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
4251                                             pRegions, filter);
4252     RecordCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
4253 }
4254 
PreCallRecordCmdBlitImage2KHR(VkCommandBuffer commandBuffer,const VkBlitImageInfo2KHR * pBlitImageInfo)4255 void CoreChecks::PreCallRecordCmdBlitImage2KHR(VkCommandBuffer commandBuffer, const VkBlitImageInfo2KHR *pBlitImageInfo) {
4256     StateTracker::PreCallRecordCmdBlitImage2KHR(commandBuffer, pBlitImageInfo);
4257     RecordCmdBlitImage(commandBuffer, pBlitImageInfo->srcImage, pBlitImageInfo->srcImageLayout, pBlitImageInfo->dstImage,
4258                        pBlitImageInfo->dstImageLayout, pBlitImageInfo->regionCount, pBlitImageInfo->pRegions,
4259                        pBlitImageInfo->filter);
4260 }
4261 
GetLayoutRangeMap(GlobalImageLayoutMap & map,const IMAGE_STATE & image_state)4262 GlobalImageLayoutRangeMap *GetLayoutRangeMap(GlobalImageLayoutMap &map, const IMAGE_STATE &image_state) {
4263     // This approach allows for a single hash lookup or/create new
4264     auto &layout_map = map[&image_state];
4265     if (!layout_map) {
4266         layout_map.emplace(image_state.subresource_encoder.SubresourceCount());
4267     }
4268     return &layout_map;
4269 }
4270 
GetLayoutRangeMap(const GlobalImageLayoutMap & map,const IMAGE_STATE & image_state)4271 const GlobalImageLayoutRangeMap *GetLayoutRangeMap(const GlobalImageLayoutMap &map, const IMAGE_STATE &image_state) {
4272     auto it = map.find(&image_state);
4273     if (it != map.end()) {
4274         return &it->second;
4275     }
4276     return nullptr;
4277 }
4278 
4279 // Helper to update the Global or Overlay layout map
4280 struct GlobalLayoutUpdater {
updateGlobalLayoutUpdater4281     bool update(VkImageLayout &dst, const image_layout_map::ImageSubresourceLayoutMap::LayoutEntry &src) const {
4282         if (src.current_layout != image_layout_map::kInvalidLayout && dst != src.current_layout) {
4283             dst = src.current_layout;
4284             return true;
4285         }
4286         return false;
4287     }
4288 
insertGlobalLayoutUpdater4289     layer_data::optional<VkImageLayout> insert(const image_layout_map::ImageSubresourceLayoutMap::LayoutEntry &src) const {
4290         layer_data::optional<VkImageLayout> result;
4291         if (src.current_layout != image_layout_map::kInvalidLayout) {
4292             result.emplace(src.current_layout);
4293         }
4294         return result;
4295     }
4296 };
4297 
4298 // This validates that the initial layout specified in the command buffer for the IMAGE is the same as the global IMAGE layout
ValidateCmdBufImageLayouts(const Location & loc,const CMD_BUFFER_STATE * pCB,const GlobalImageLayoutMap & globalImageLayoutMap,GlobalImageLayoutMap & overlayLayoutMap) const4299 bool CoreChecks::ValidateCmdBufImageLayouts(const Location &loc, const CMD_BUFFER_STATE *pCB,
4300                                             const GlobalImageLayoutMap &globalImageLayoutMap,
4301                                             GlobalImageLayoutMap &overlayLayoutMap) const {
4302     if (disabled[image_layout_validation]) return false;
4303     bool skip = false;
4304     // Iterate over the layout maps for each referenced image
4305     GlobalImageLayoutRangeMap empty_map(1);
4306     for (const auto &layout_map_entry : pCB->image_layout_map) {
4307         const auto *image_state = layout_map_entry.first;
4308         const auto &subres_map = layout_map_entry.second;
4309         const auto &layout_map = subres_map->GetLayoutMap();
4310         // Validate the initial_uses for each subresource referenced
4311         if (layout_map.empty()) continue;
4312 
4313         auto *overlay_map = GetLayoutRangeMap(overlayLayoutMap, *image_state);
4314         const auto *global_map = GetLayoutRangeMap(globalImageLayoutMap, *image_state);
4315         if (global_map == nullptr) {
4316             global_map = &empty_map;
4317         }
4318 
4319         // Note: don't know if it would matter
4320         // if (global_map->empty() && overlay_map->empty()) // skip this next loop...;
4321 
4322         auto pos = layout_map.begin();
4323         const auto end = layout_map.end();
4324         sparse_container::parallel_iterator<const GlobalImageLayoutRangeMap> current_layout(*overlay_map, *global_map,
4325                                                                                             pos->first.begin);
4326         while (pos != end) {
4327             VkImageLayout initial_layout = pos->second.initial_layout;
4328             assert(initial_layout != image_layout_map::kInvalidLayout);
4329             if (initial_layout == image_layout_map::kInvalidLayout) {
4330                 continue;
4331             }
4332 
4333             VkImageLayout image_layout = kInvalidLayout;
4334 
4335             if (current_layout->range.empty()) break;  // When we are past the end of data in overlay and global... stop looking
4336             if (current_layout->pos_A->valid) {        // pos_A denotes the overlay map in the parallel iterator
4337                 image_layout = current_layout->pos_A->lower_bound->second;
4338             } else if (current_layout->pos_B->valid) {  // pos_B denotes the global map in the parallel iterator
4339                 image_layout = current_layout->pos_B->lower_bound->second;
4340             }
4341             const auto intersected_range = pos->first & current_layout->range;
4342             if (initial_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
4343                 // TODO: Set memory invalid which is in mem_tracker currently
4344             } else if (image_layout != initial_layout) {
4345                 const auto aspect_mask = image_state->subresource_encoder.Decode(intersected_range.begin).aspectMask;
4346                 bool matches = ImageLayoutMatches(aspect_mask, image_layout, initial_layout);
4347                 if (!matches) {
4348                     // We can report all the errors for the intersected range directly
4349                     for (auto index : sparse_container::range_view<decltype(intersected_range)>(intersected_range)) {
4350                         const auto subresource = image_state->subresource_encoder.Decode(index);
4351                         skip |= LogError(
4352                             pCB->commandBuffer(), kVUID_Core_DrawState_InvalidImageLayout,
4353                             "%s command buffer %s expects %s (subresource: aspectMask 0x%X array layer %u, mip level %u) "
4354                             "to be in layout %s--instead, current layout is %s.",
4355                             loc.Message().c_str(), report_data->FormatHandle(pCB->commandBuffer()).c_str(),
4356                             report_data->FormatHandle(image_state->Handle()).c_str(), subresource.aspectMask, subresource.arrayLayer,
4357                             subresource.mipLevel, string_VkImageLayout(initial_layout), string_VkImageLayout(image_layout));
4358                     }
4359                 }
4360             }
4361             if (pos->first.includes(intersected_range.end)) {
4362                 current_layout.seek(intersected_range.end);
4363             } else {
4364                 ++pos;
4365                 if (pos != end) {
4366                     current_layout.seek(pos->first.begin);
4367                 }
4368             }
4369         }
4370         // Update all layout set operations (which will be a subset of the initial_layouts)
4371         sparse_container::splice(*overlay_map, subres_map->GetLayoutMap(), GlobalLayoutUpdater());
4372     }
4373 
4374     return skip;
4375 }
4376 
UpdateCmdBufImageLayouts(CMD_BUFFER_STATE * pCB)4377 void CoreChecks::UpdateCmdBufImageLayouts(CMD_BUFFER_STATE *pCB) {
4378     for (const auto &layout_map_entry : pCB->image_layout_map) {
4379         const auto *image_state = layout_map_entry.first;
4380         const auto &subres_map = layout_map_entry.second;
4381         auto *global_map = GetLayoutRangeMap(imageLayoutMap, *image_state);
4382         sparse_container::splice(*global_map, subres_map->GetLayoutMap(), GlobalLayoutUpdater());
4383     }
4384 }
4385 
4386 // ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
4387 // VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that READ_ONLY
4388 // layout attachments don't have CLEAR as their loadOp.
ValidateLayoutVsAttachmentDescription(const debug_report_data * report_data,RenderPassCreateVersion rp_version,const VkImageLayout first_layout,const uint32_t attachment,const VkAttachmentDescription2 & attachment_description) const4389 bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
4390                                                        const VkImageLayout first_layout, const uint32_t attachment,
4391                                                        const VkAttachmentDescription2 &attachment_description) const {
4392     bool skip = false;
4393     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
4394 
4395     // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
4396     // for both loadOp and stencilLoaOp rp2 has it in 1 VU while rp1 has it in 2 VU with half behind Maintenance2 extension
4397     // Each is VUID is below in following order: rp2 -> rp1 with Maintenance2 -> rp1 with no extenstion
4398     if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
4399         if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4400                         (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
4401                         (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL))) {
4402             skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-pAttachments-02522",
4403                              "vkCreateRenderPass2(): Cannot clear attachment %d with invalid first layout %s.", attachment,
4404                              string_VkImageLayout(first_layout));
4405         } else if ((use_rp2 == false) && IsExtEnabled(device_extensions.vk_khr_maintenance2) &&
4406                    (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)) {
4407             skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-01566",
4408                              "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
4409                              string_VkImageLayout(first_layout));
4410         } else if ((use_rp2 == false) && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4411                                           (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
4412             skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-00836",
4413                              "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
4414                              string_VkImageLayout(first_layout));
4415         }
4416     }
4417 
4418     // Same as above for loadOp, but for stencilLoadOp
4419     if (attachment_description.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
4420         if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4421                         (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
4422                         (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL))) {
4423             skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-pAttachments-02523",
4424                              "vkCreateRenderPass2(): Cannot clear attachment %d with invalid first layout %s.", attachment,
4425                              string_VkImageLayout(first_layout));
4426         } else if ((use_rp2 == false) && IsExtEnabled(device_extensions.vk_khr_maintenance2) &&
4427                    (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL)) {
4428             skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-01567",
4429                              "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
4430                              string_VkImageLayout(first_layout));
4431         } else if ((use_rp2 == false) && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
4432                                           (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
4433             skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pAttachments-02511",
4434                              "vkCreateRenderPass(): Cannot clear attachment %d with invalid first layout %s.", attachment,
4435                              string_VkImageLayout(first_layout));
4436         }
4437     }
4438 
4439     return skip;
4440 }
4441 
4442 // Helper function to validate correct usage bits set for buffers or images. Verify that (actual & desired) flags != 0 or, if strict
4443 // is true, verify that (actual & desired) flags == desired
4444 template <typename T1>
ValidateUsageFlags(VkFlags actual,VkFlags desired,VkBool32 strict,const T1 object,const VulkanTypedHandle & typed_handle,const char * msgCode,char const * func_name,char const * usage_str) const4445 bool CoreChecks::ValidateUsageFlags(VkFlags actual, VkFlags desired, VkBool32 strict, const T1 object,
4446                                     const VulkanTypedHandle &typed_handle, const char *msgCode, char const *func_name,
4447                                     char const *usage_str) const {
4448     bool correct_usage = false;
4449     bool skip = false;
4450     const char *type_str = object_string[typed_handle.type];
4451     if (strict) {
4452         correct_usage = ((actual & desired) == desired);
4453     } else {
4454         correct_usage = ((actual & desired) != 0);
4455     }
4456 
4457     if (!correct_usage) {
4458         // All callers should have a valid VUID
4459         assert(msgCode != kVUIDUndefined);
4460         skip =
4461             LogError(object, msgCode, "Invalid usage flag for %s used by %s. In this case, %s should have %s set during creation.",
4462                      report_data->FormatHandle(typed_handle).c_str(), func_name, type_str, usage_str);
4463     }
4464     return skip;
4465 }
4466 
4467 // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
4468 // where an error will be flagged if usage is not correct
ValidateImageUsageFlags(IMAGE_STATE const * image_state,VkFlags desired,bool strict,const char * msgCode,char const * func_name,char const * usage_string) const4469 bool CoreChecks::ValidateImageUsageFlags(IMAGE_STATE const *image_state, VkFlags desired, bool strict, const char *msgCode,
4470                                          char const *func_name, char const *usage_string) const {
4471     return ValidateUsageFlags(image_state->createInfo.usage, desired, strict, image_state->image(),
4472                               image_state->Handle(), msgCode, func_name, usage_string);
4473 }
4474 
ValidateImageFormatFeatureFlags(IMAGE_STATE const * image_state,VkFormatFeatureFlags desired,char const * func_name,const char * vuid) const4475 bool CoreChecks::ValidateImageFormatFeatureFlags(IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
4476                                                  char const *func_name, const char *vuid) const {
4477     bool skip = false;
4478     const VkFormatFeatureFlags image_format_features = image_state->format_features;
4479     if ((image_format_features & desired) != desired) {
4480         // Same error, but more details if it was an AHB external format
4481         if (image_state->HasAHBFormat()) {
4482             skip |= LogError(image_state->image(), vuid,
4483                              "In %s, VkFormatFeatureFlags (0x%08X) does not support required feature %s for the external format "
4484                              "found in VkAndroidHardwareBufferFormatPropertiesANDROID::formatFeatures used by %s.",
4485                              func_name, image_format_features, string_VkFormatFeatureFlags(desired).c_str(),
4486                              report_data->FormatHandle(image_state->image()).c_str());
4487         } else {
4488             skip |= LogError(image_state->image(), vuid,
4489                              "In %s, VkFormatFeatureFlags (0x%08X) does not support required feature %s for format %u used by %s "
4490                              "with tiling %s.",
4491                              func_name, image_format_features, string_VkFormatFeatureFlags(desired).c_str(),
4492                              image_state->createInfo.format, report_data->FormatHandle(image_state->image()).c_str(),
4493                              string_VkImageTiling(image_state->createInfo.tiling));
4494         }
4495     }
4496     return skip;
4497 }
4498 
ValidateImageSubresourceLayers(const CMD_BUFFER_STATE * cb_node,const VkImageSubresourceLayers * subresource_layers,char const * func_name,char const * member,uint32_t i) const4499 bool CoreChecks::ValidateImageSubresourceLayers(const CMD_BUFFER_STATE *cb_node, const VkImageSubresourceLayers *subresource_layers,
4500                                                 char const *func_name, char const *member, uint32_t i) const {
4501     bool skip = false;
4502     const VkImageAspectFlags apsect_mask = subresource_layers->aspectMask;
4503     // layerCount must not be zero
4504     if (subresource_layers->layerCount == 0) {
4505         skip |= LogError(cb_node->commandBuffer(), "VUID-VkImageSubresourceLayers-layerCount-01700",
4506                          "In %s, pRegions[%u].%s.layerCount must not be zero.", func_name, i, member);
4507     }
4508     // aspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT
4509     if (apsect_mask & VK_IMAGE_ASPECT_METADATA_BIT) {
4510         skip |= LogError(cb_node->commandBuffer(), "VUID-VkImageSubresourceLayers-aspectMask-00168",
4511                          "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_METADATA_BIT set.", func_name, i, member);
4512     }
4513     // if aspectMask contains COLOR, it must not contain either DEPTH or STENCIL
4514     if ((apsect_mask & VK_IMAGE_ASPECT_COLOR_BIT) && (apsect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
4515         skip |= LogError(cb_node->commandBuffer(), "VUID-VkImageSubresourceLayers-aspectMask-00167",
4516                          "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_COLOR_BIT and either VK_IMAGE_ASPECT_DEPTH_BIT or "
4517                          "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4518                          func_name, i, member);
4519     }
4520     // aspectMask must not contain VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT
4521     if (apsect_mask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
4522                        VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
4523         skip |= LogError(cb_node->commandBuffer(), "VUID-VkImageSubresourceLayers-aspectMask-02247",
4524                          "In %s, pRegions[%u].%s.aspectMask has a VK_IMAGE_ASPECT_MEMORY_PLANE_*_BIT_EXT bit set.", func_name, i,
4525                          member);
4526     }
4527     return skip;
4528 }
4529 
4530 // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
4531 // where an error will be flagged if usage is not correct
ValidateBufferUsageFlags(BUFFER_STATE const * buffer_state,VkFlags desired,bool strict,const char * msgCode,char const * func_name,char const * usage_string) const4532 bool CoreChecks::ValidateBufferUsageFlags(BUFFER_STATE const *buffer_state, VkFlags desired, bool strict, const char *msgCode,
4533                                           char const *func_name, char const *usage_string) const {
4534     return ValidateUsageFlags(buffer_state->createInfo.usage, desired, strict, buffer_state->buffer(),
4535                               buffer_state->Handle(), msgCode, func_name, usage_string);
4536 }
4537 
ValidateBufferViewRange(const BUFFER_STATE * buffer_state,const VkBufferViewCreateInfo * pCreateInfo,const VkPhysicalDeviceLimits * device_limits) const4538 bool CoreChecks::ValidateBufferViewRange(const BUFFER_STATE *buffer_state, const VkBufferViewCreateInfo *pCreateInfo,
4539                                          const VkPhysicalDeviceLimits *device_limits) const {
4540     bool skip = false;
4541 
4542     const VkDeviceSize &range = pCreateInfo->range;
4543     if (range != VK_WHOLE_SIZE) {
4544         // Range must be greater than 0
4545         if (range <= 0) {
4546             skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-range-00928",
4547                              "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
4548                              ") does not equal VK_WHOLE_SIZE, range must be greater than 0.",
4549                              range);
4550         }
4551         // Range must be a multiple of the element size of format
4552         const uint32_t format_size = FormatElementSize(pCreateInfo->format);
4553         if (SafeModulo(range, format_size) != 0) {
4554             skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-range-00929",
4555                              "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
4556                              ") does not equal VK_WHOLE_SIZE, range must be a multiple of the element size of the format "
4557                              "(%" PRIu32 ").",
4558                              range, format_size);
4559         }
4560         // Range divided by the element size of format must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements
4561         if (SafeDivision(range, format_size) > device_limits->maxTexelBufferElements) {
4562             skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-range-00930",
4563                              "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
4564                              ") does not equal VK_WHOLE_SIZE, range divided by the element size of the format (%" PRIu32
4565                              ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").",
4566                              range, format_size, device_limits->maxTexelBufferElements);
4567         }
4568         // The sum of range and offset must be less than or equal to the size of buffer
4569         if (range + pCreateInfo->offset > buffer_state->createInfo.size) {
4570             skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-offset-00931",
4571                              "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
4572                              ") does not equal VK_WHOLE_SIZE, the sum of offset (%" PRIuLEAST64
4573                              ") and range must be less than or equal to the size of the buffer (%" PRIuLEAST64 ").",
4574                              range, pCreateInfo->offset, buffer_state->createInfo.size);
4575         }
4576     } else {
4577         const uint32_t format_size = FormatElementSize(pCreateInfo->format);
4578 
4579         // Size of buffer - offset, divided by the element size of format must be less than or equal to
4580         // VkPhysicalDeviceLimits::maxTexelBufferElements
4581         if (SafeDivision(buffer_state->createInfo.size - pCreateInfo->offset, format_size) >
4582             device_limits->maxTexelBufferElements) {
4583             skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-range-04059",
4584                              "vkCreateBufferView(): If VkBufferViewCreateInfo range (%" PRIuLEAST64
4585                              ") equals VK_WHOLE_SIZE, the buffer's size (%" PRIuLEAST64 ") minus the offset (%" PRIuLEAST64
4586                              "), divided by the element size of the format (%" PRIu32
4587                              ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").",
4588                              range, buffer_state->createInfo.size, pCreateInfo->offset, format_size,
4589                              device_limits->maxTexelBufferElements);
4590         }
4591     }
4592     return skip;
4593 }
4594 
ValidateBufferViewBuffer(const BUFFER_STATE * buffer_state,const VkBufferViewCreateInfo * pCreateInfo) const4595 bool CoreChecks::ValidateBufferViewBuffer(const BUFFER_STATE *buffer_state, const VkBufferViewCreateInfo *pCreateInfo) const {
4596     bool skip = false;
4597     const VkFormatProperties format_properties = GetPDFormatProperties(pCreateInfo->format);
4598     if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) &&
4599         !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
4600         skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-buffer-00933",
4601                          "vkCreateBufferView(): If buffer was created with `usage` containing "
4602                          "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, format (%s) must "
4603                          "be supported for uniform texel buffers",
4604                          string_VkFormat(pCreateInfo->format));
4605     }
4606     if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) &&
4607         !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
4608         skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-buffer-00934",
4609                          "vkCreateBufferView(): If buffer was created with `usage` containing "
4610                          "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, format (%s) must "
4611                          "be supported for storage texel buffers",
4612                          string_VkFormat(pCreateInfo->format));
4613     }
4614     return skip;
4615 }
4616 
PreCallValidateCreateBuffer(VkDevice device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer) const4617 bool CoreChecks::PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
4618                                              const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) const {
4619     bool skip = false;
4620 
4621     // TODO: Add check for "VUID-vkCreateBuffer-flags-00911"        (sparse address space accounting)
4622 
4623     auto chained_devaddr_struct = LvlFindInChain<VkBufferDeviceAddressCreateInfoEXT>(pCreateInfo->pNext);
4624     if (chained_devaddr_struct) {
4625         if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT) &&
4626             chained_devaddr_struct->deviceAddress != 0) {
4627             skip |= LogError(device, "VUID-VkBufferCreateInfo-deviceAddress-02604",
4628                              "vkCreateBuffer(): Non-zero VkBufferDeviceAddressCreateInfoEXT::deviceAddress "
4629                              "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT.");
4630         }
4631     }
4632 
4633     auto chained_opaqueaddr_struct = LvlFindInChain<VkBufferOpaqueCaptureAddressCreateInfo>(pCreateInfo->pNext);
4634     if (chained_opaqueaddr_struct) {
4635         if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT) &&
4636             chained_opaqueaddr_struct->opaqueCaptureAddress != 0) {
4637             skip |= LogError(device, "VUID-VkBufferCreateInfo-opaqueCaptureAddress-03337",
4638                              "vkCreateBuffer(): Non-zero VkBufferOpaqueCaptureAddressCreateInfo::opaqueCaptureAddress"
4639                              "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT.");
4640         }
4641     }
4642 
4643     auto dedicated_allocation_buffer = LvlFindInChain<VkDedicatedAllocationBufferCreateInfoNV>(pCreateInfo->pNext);
4644     if (dedicated_allocation_buffer && dedicated_allocation_buffer->dedicatedAllocation == VK_TRUE) {
4645         if (pCreateInfo->flags &
4646             (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) {
4647             skip |= LogError(device, "VUID-VkBufferCreateInfo-pNext-01571",
4648                              "vkCreateBuffer(): pCreateInfos->flags must not include VK_BUFFER_CREATE_SPARSE_BINDING_BIT, "
4649                              "VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, or VK_BUFFER_CREATE_SPARSE_ALIASED_BIT when "
4650                              "VkDedicatedAllocationBufferCreateInfoNV is in pNext chain with dedicatedAllocation VK_TRUE.");
4651         }
4652     }
4653 
4654     if ((pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT) &&
4655         !enabled_features.core12.bufferDeviceAddressCaptureReplay &&
4656         !enabled_features.buffer_device_address_ext_features.bufferDeviceAddressCaptureReplay) {
4657         skip |= LogError(
4658             device, "VUID-VkBufferCreateInfo-flags-03338",
4659             "vkCreateBuffer(): the bufferDeviceAddressCaptureReplay device feature is disabled: Buffers cannot be created with "
4660             "the VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT set.");
4661     }
4662 
4663     if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
4664         const char *vuid = IsExtEnabled(device_extensions.vk_khr_get_physical_device_properties2)
4665                                ? "VUID-VkBufferCreateInfo-sharingMode-01419"
4666                                : "VUID-VkBufferCreateInfo-sharingMode-01391";
4667         skip |= ValidatePhysicalDeviceQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
4668                                                     "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices", vuid);
4669     }
4670 
4671     if ((pCreateInfo->flags & VK_BUFFER_CREATE_PROTECTED_BIT) != 0) {
4672         if (enabled_features.core11.protectedMemory == VK_FALSE) {
4673             skip |= LogError(device, "VUID-VkBufferCreateInfo-flags-01887",
4674                              "vkCreateBuffer(): the protectedMemory device feature is disabled: Buffers cannot be created with the "
4675                              "VK_BUFFER_CREATE_PROTECTED_BIT set.");
4676         }
4677         const VkBufferCreateFlags invalid_flags =
4678             VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT;
4679         if ((pCreateInfo->flags & invalid_flags) != 0) {
4680             skip |= LogError(device, "VUID-VkBufferCreateInfo-None-01888",
4681                              "vkCreateBuffer(): VK_BUFFER_CREATE_PROTECTED_BIT is set so no sparse create flags can be used at "
4682                              "same time (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | "
4683                              "VK_BUFFER_CREATE_SPARSE_ALIASED_BIT).");
4684         }
4685     }
4686 
4687     return skip;
4688 }
4689 
PreCallValidateCreateBufferView(VkDevice device,const VkBufferViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBufferView * pView) const4690 bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
4691                                                  const VkAllocationCallbacks *pAllocator, VkBufferView *pView) const {
4692     bool skip = false;
4693     const auto buffer_state = Get<BUFFER_STATE>(pCreateInfo->buffer);
4694 
4695     if (FormatIsDepthOrStencil(pCreateInfo->format)) {
4696         // Should never hopefully get here, but there are known driver advertising the wrong feature flags
4697         // see https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/4849
4698         skip |= LogError(device, kVUID_Core_invalidDepthStencilFormat,
4699                          "vkCreateBufferView(): format is a depth/stencil format (%s) but depth/stencil formats do not have a "
4700                          "defined sizes for alignment, replace with a color format.",
4701                          string_VkFormat(pCreateInfo->format));
4702     }
4703 
4704     // If this isn't a sparse buffer, it needs to have memory backing it at CreateBufferView time
4705     if (buffer_state) {
4706         skip |=
4707             ValidateMemoryIsBoundToBuffer(buffer_state.get(), "vkCreateBufferView()", "VUID-VkBufferViewCreateInfo-buffer-00935");
4708         // In order to create a valid buffer view, the buffer must have been created with at least one of the following flags:
4709         // UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
4710         skip |= ValidateBufferUsageFlags(buffer_state.get(),
4711                                          VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
4712                                          "VUID-VkBufferViewCreateInfo-buffer-00932", "vkCreateBufferView()",
4713                                          "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
4714 
4715         // Buffer view offset must be less than the size of buffer
4716         if (pCreateInfo->offset >= buffer_state->createInfo.size) {
4717             skip |= LogError(buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-offset-00925",
4718                              "vkCreateBufferView(): VkBufferViewCreateInfo offset (%" PRIuLEAST64
4719                              ") must be less than the size of the buffer (%" PRIuLEAST64 ").",
4720                              pCreateInfo->offset, buffer_state->createInfo.size);
4721         }
4722 
4723         const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
4724         // Buffer view offset must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment
4725         if ((pCreateInfo->offset % device_limits->minTexelBufferOffsetAlignment) != 0 &&
4726             !enabled_features.texel_buffer_alignment_features.texelBufferAlignment) {
4727             const char *vuid = IsExtEnabled(device_extensions.vk_ext_texel_buffer_alignment)
4728                                    ? "VUID-VkBufferViewCreateInfo-offset-02749"
4729                                    : "VUID-VkBufferViewCreateInfo-offset-00926";
4730             skip |= LogError(buffer_state->buffer(), vuid,
4731                              "vkCreateBufferView(): VkBufferViewCreateInfo offset (%" PRIuLEAST64
4732                              ") must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment (%" PRIuLEAST64 ").",
4733                              pCreateInfo->offset, device_limits->minTexelBufferOffsetAlignment);
4734         }
4735 
4736         if (enabled_features.texel_buffer_alignment_features.texelBufferAlignment) {
4737             VkDeviceSize element_size = FormatElementSize(pCreateInfo->format);
4738             if ((element_size % 3) == 0) {
4739                 element_size /= 3;
4740             }
4741             if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) {
4742                 VkDeviceSize alignment_requirement =
4743                     phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes;
4744                 if (phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment) {
4745                     alignment_requirement = std::min(alignment_requirement, element_size);
4746                 }
4747                 if (SafeModulo(pCreateInfo->offset, alignment_requirement) != 0) {
4748                     skip |= LogError(
4749                         buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-buffer-02750",
4750                         "vkCreateBufferView(): If buffer was created with usage containing "
4751                         "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, "
4752                         "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4753                         ") must be a multiple of the lesser of "
4754                         "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64
4755                         ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetSingleTexelAlignment "
4756                         "(%" PRId32
4757                         ") is VK_TRUE, the size of a texel of the requested format. "
4758                         "If the size of a texel is a multiple of three bytes, then the size of a "
4759                         "single component of format is used instead",
4760                         pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes,
4761                         phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment);
4762                 }
4763             }
4764             if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) {
4765                 VkDeviceSize alignment_requirement =
4766                     phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes;
4767                 if (phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment) {
4768                     alignment_requirement = std::min(alignment_requirement, element_size);
4769                 }
4770                 if (SafeModulo(pCreateInfo->offset, alignment_requirement) != 0) {
4771                     skip |= LogError(
4772                         buffer_state->buffer(), "VUID-VkBufferViewCreateInfo-buffer-02751",
4773                         "vkCreateBufferView(): If buffer was created with usage containing "
4774                         "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, "
4775                         "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4776                         ") must be a multiple of the lesser of "
4777                         "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64
4778                         ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetSingleTexelAlignment "
4779                         "(%" PRId32
4780                         ") is VK_TRUE, the size of a texel of the requested format. "
4781                         "If the size of a texel is a multiple of three bytes, then the size of a "
4782                         "single component of format is used instead",
4783                         pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes,
4784                         phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment);
4785                 }
4786             }
4787         }
4788 
4789         skip |= ValidateBufferViewRange(buffer_state.get(), pCreateInfo, device_limits);
4790 
4791         skip |= ValidateBufferViewBuffer(buffer_state.get(), pCreateInfo);
4792     }
4793     return skip;
4794 }
4795 
4796 // For the given format verify that the aspect masks make sense
ValidateImageAspectMask(VkImage image,VkFormat format,VkImageAspectFlags aspect_mask,const char * func_name,const char * vuid) const4797 bool CoreChecks::ValidateImageAspectMask(VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, const char *func_name,
4798                                          const char *vuid) const {
4799     bool skip = false;
4800     const auto image_state = Get<IMAGE_STATE>(image);
4801     // checks color format and (single-plane or non-disjoint)
4802     // if ycbcr extension is not supported then single-plane and non-disjoint are always both true
4803     if ((FormatIsColor(format)) && ((FormatIsMultiplane(format) == false) || (image_state->disjoint == false))) {
4804         if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
4805             skip |= LogError(
4806                 image, vuid,
4807                 "%s: Using format (%s) with aspect flags (%s) but color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set.",
4808                 func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4809         } else if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != aspect_mask) {
4810             skip |= LogError(image, vuid,
4811                              "%s: Using format (%s) with aspect flags (%s) but color image formats must have ONLY the "
4812                              "VK_IMAGE_ASPECT_COLOR_BIT set.",
4813                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4814         }
4815     } else if (FormatIsDepthAndStencil(format)) {
4816         if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) {
4817             skip |= LogError(image, vuid,
4818                              "%s: Using format (%s) with aspect flags (%s) but depth/stencil image formats must have at least one "
4819                              "of VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT set.",
4820                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4821         } else if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspect_mask) {
4822             skip |= LogError(image, vuid,
4823                              "%s: Using format (%s) with aspect flags (%s) but combination depth/stencil image formats can have "
4824                              "only the VK_IMAGE_ASPECT_DEPTH_BIT and VK_IMAGE_ASPECT_STENCIL_BIT set.",
4825                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4826         }
4827     } else if (FormatIsDepthOnly(format)) {
4828         if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
4829             skip |= LogError(image, vuid,
4830                              "%s: Using format (%s) with aspect flags (%s) but depth-only image formats must have the "
4831                              "VK_IMAGE_ASPECT_DEPTH_BIT set.",
4832                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4833         } else if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspect_mask) {
4834             skip |= LogError(image, vuid,
4835                              "%s: Using format (%s) with aspect flags (%s) but depth-only image formats can have only the "
4836                              "VK_IMAGE_ASPECT_DEPTH_BIT set.",
4837                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4838         }
4839     } else if (FormatIsStencilOnly(format)) {
4840         if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
4841             skip |= LogError(image, vuid,
4842                              "%s: Using format (%s) with aspect flags (%s) but stencil-only image formats must have the "
4843                              "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4844                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4845         } else if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspect_mask) {
4846             skip |= LogError(image, vuid,
4847                              "%s: Using format (%s) with aspect flags (%s) but stencil-only image formats can have only the "
4848                              "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4849                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4850         }
4851     } else if (FormatIsMultiplane(format)) {
4852         VkImageAspectFlags valid_flags = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
4853         if (3 == FormatPlaneCount(format)) {
4854             valid_flags = valid_flags | VK_IMAGE_ASPECT_PLANE_2_BIT;
4855         }
4856         if ((aspect_mask & valid_flags) != aspect_mask) {
4857             skip |= LogError(image, vuid,
4858                              "%s: Using format (%s) with aspect flags (%s) but multi-plane image formats may have only "
4859                              "VK_IMAGE_ASPECT_COLOR_BIT or VK_IMAGE_ASPECT_PLANE_n_BITs set, where n = [0, 1, 2].",
4860                              func_name, string_VkFormat(format), string_VkImageAspectFlags(aspect_mask).c_str());
4861         }
4862     }
4863     return skip;
4864 }
4865 
ValidateImageAcquired(IMAGE_STATE const & image_state,const char * func_name) const4866 bool CoreChecks::ValidateImageAcquired(IMAGE_STATE const &image_state, const char *func_name) const {
4867     bool skip = false;
4868 
4869     return skip;
4870 }
4871 
ValidateImageSubresourceRange(const uint32_t image_mip_count,const uint32_t image_layer_count,const VkImageSubresourceRange & subresourceRange,const char * cmd_name,const char * param_name,const char * image_layer_count_var_name,const VkImage image,const SubresourceRangeErrorCodes & errorCodes) const4872 bool CoreChecks::ValidateImageSubresourceRange(const uint32_t image_mip_count, const uint32_t image_layer_count,
4873                                                const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
4874                                                const char *param_name, const char *image_layer_count_var_name, const VkImage image,
4875                                                const SubresourceRangeErrorCodes &errorCodes) const {
4876     bool skip = false;
4877 
4878     // Validate mip levels
4879     if (subresourceRange.baseMipLevel >= image_mip_count) {
4880         skip |= LogError(image, errorCodes.base_mip_err,
4881                          "%s: %s.baseMipLevel (= %" PRIu32
4882                          ") is greater or equal to the mip level count of the image (i.e. greater or equal to %" PRIu32 ").",
4883                          cmd_name, param_name, subresourceRange.baseMipLevel, image_mip_count);
4884     }
4885 
4886     if (subresourceRange.levelCount != VK_REMAINING_MIP_LEVELS) {
4887         if (subresourceRange.levelCount == 0) {
4888             skip |=
4889                 LogError(image, "VUID-VkImageSubresourceRange-levelCount-01720", "%s: %s.levelCount is 0.", cmd_name, param_name);
4890         } else {
4891             const uint64_t necessary_mip_count = uint64_t{subresourceRange.baseMipLevel} + uint64_t{subresourceRange.levelCount};
4892 
4893             if (necessary_mip_count > image_mip_count) {
4894                 skip |= LogError(image, errorCodes.mip_count_err,
4895                                  "%s: %s.baseMipLevel + .levelCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
4896                                  ") is greater than the mip level count of the image (i.e. greater than %" PRIu32 ").",
4897                                  cmd_name, param_name, subresourceRange.baseMipLevel, subresourceRange.levelCount,
4898                                  necessary_mip_count, image_mip_count);
4899             }
4900         }
4901     }
4902 
4903     // Validate array layers
4904     if (subresourceRange.baseArrayLayer >= image_layer_count) {
4905         skip |= LogError(image, errorCodes.base_layer_err,
4906                          "%s: %s.baseArrayLayer (= %" PRIu32
4907                          ") is greater or equal to the %s of the image when it was created (i.e. greater or equal to %" PRIu32 ").",
4908                          cmd_name, param_name, subresourceRange.baseArrayLayer, image_layer_count_var_name, image_layer_count);
4909     }
4910 
4911     if (subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS) {
4912         if (subresourceRange.layerCount == 0) {
4913             skip |=
4914                 LogError(image, "VUID-VkImageSubresourceRange-layerCount-01721", "%s: %s.layerCount is 0.", cmd_name, param_name);
4915         } else {
4916             const uint64_t necessary_layer_count =
4917                 uint64_t{subresourceRange.baseArrayLayer} + uint64_t{subresourceRange.layerCount};
4918 
4919             if (necessary_layer_count > image_layer_count) {
4920                 skip |= LogError(image, errorCodes.layer_count_err,
4921                                  "%s: %s.baseArrayLayer + .layerCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
4922                                  ") is greater than the %s of the image when it was created (i.e. greater than %" PRIu32 ").",
4923                                  cmd_name, param_name, subresourceRange.baseArrayLayer, subresourceRange.layerCount,
4924                                  necessary_layer_count, image_layer_count_var_name, image_layer_count);
4925             }
4926         }
4927     }
4928 
4929     if (subresourceRange.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
4930         if (subresourceRange.aspectMask &
4931             (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) {
4932             skip |= LogError(image, "VUID-VkImageSubresourceRange-aspectMask-01670",
4933                              "%s: aspectMask includes both VK_IMAGE_ASPECT_COLOR_BIT and one of VK_IMAGE_ASPECT_PLANE_0_BIT, "
4934                              "VK_IMAGE_ASPECT_PLANE_1_BIT, or VK_IMAGE_ASPECT_PLANE_2_BIT.",
4935                              cmd_name);
4936         }
4937     }
4938 
4939     return skip;
4940 }
4941 
ValidateCreateImageViewSubresourceRange(const IMAGE_STATE * image_state,bool is_imageview_2d_type,const VkImageSubresourceRange & subresourceRange) const4942 bool CoreChecks::ValidateCreateImageViewSubresourceRange(const IMAGE_STATE *image_state, bool is_imageview_2d_type,
4943                                                          const VkImageSubresourceRange &subresourceRange) const {
4944     bool is_khr_maintenance1 = IsExtEnabled(device_extensions.vk_khr_maintenance1);
4945     bool is_image_slicable = image_state->createInfo.imageType == VK_IMAGE_TYPE_3D &&
4946                              (image_state->createInfo.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT);
4947     bool is_3_d_to_2_d_map = is_khr_maintenance1 && is_image_slicable && is_imageview_2d_type;
4948 
4949     uint32_t image_layer_count;
4950 
4951     if (is_3_d_to_2_d_map) {
4952         const auto layers = LayersFromRange(subresourceRange);
4953         const auto extent = image_state->GetSubresourceExtent(layers);
4954         image_layer_count = extent.depth;
4955     } else {
4956         image_layer_count = image_state->createInfo.arrayLayers;
4957     }
4958 
4959     const auto image_layer_count_var_name = is_3_d_to_2_d_map ? "extent.depth" : "arrayLayers";
4960 
4961     SubresourceRangeErrorCodes subresource_range_error_codes = {};
4962     subresource_range_error_codes.base_mip_err = "VUID-VkImageViewCreateInfo-subresourceRange-01478";
4963     subresource_range_error_codes.mip_count_err = "VUID-VkImageViewCreateInfo-subresourceRange-01718";
4964     subresource_range_error_codes.base_layer_err =
4965         is_khr_maintenance1
4966             ? (is_3_d_to_2_d_map ? "VUID-VkImageViewCreateInfo-image-02724" : "VUID-VkImageViewCreateInfo-image-01482")
4967             : "VUID-VkImageViewCreateInfo-subresourceRange-01480";
4968     subresource_range_error_codes.layer_count_err = is_khr_maintenance1
4969                                                         ? (is_3_d_to_2_d_map ? "VUID-VkImageViewCreateInfo-subresourceRange-02725"
4970                                                                              : "VUID-VkImageViewCreateInfo-subresourceRange-01483")
4971                                                         : "VUID-VkImageViewCreateInfo-subresourceRange-01719";
4972 
4973     return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_layer_count, subresourceRange,
4974                                          "vkCreateImageView", "pCreateInfo->subresourceRange", image_layer_count_var_name,
4975                                          image_state->image(), subresource_range_error_codes);
4976 }
4977 
ValidateCmdClearColorSubresourceRange(const IMAGE_STATE * image_state,const VkImageSubresourceRange & subresourceRange,const char * param_name) const4978 bool CoreChecks::ValidateCmdClearColorSubresourceRange(const IMAGE_STATE *image_state,
4979                                                        const VkImageSubresourceRange &subresourceRange,
4980                                                        const char *param_name) const {
4981     SubresourceRangeErrorCodes subresource_range_error_codes = {};
4982     subresource_range_error_codes.base_mip_err = "VUID-vkCmdClearColorImage-baseMipLevel-01470";
4983     subresource_range_error_codes.mip_count_err = "VUID-vkCmdClearColorImage-pRanges-01692";
4984     subresource_range_error_codes.base_layer_err = "VUID-vkCmdClearColorImage-baseArrayLayer-01472";
4985     subresource_range_error_codes.layer_count_err = "VUID-vkCmdClearColorImage-pRanges-01693";
4986 
4987     return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
4988                                          "vkCmdClearColorImage", param_name, "arrayLayers", image_state->image(),
4989                                          subresource_range_error_codes);
4990 }
4991 
ValidateCmdClearDepthSubresourceRange(const IMAGE_STATE * image_state,const VkImageSubresourceRange & subresourceRange,const char * param_name) const4992 bool CoreChecks::ValidateCmdClearDepthSubresourceRange(const IMAGE_STATE *image_state,
4993                                                        const VkImageSubresourceRange &subresourceRange,
4994                                                        const char *param_name) const {
4995     SubresourceRangeErrorCodes subresource_range_error_codes = {};
4996     subresource_range_error_codes.base_mip_err = "VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474";
4997     subresource_range_error_codes.mip_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01694";
4998     subresource_range_error_codes.base_layer_err = "VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476";
4999     subresource_range_error_codes.layer_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01695";
5000 
5001     return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
5002                                          "vkCmdClearDepthStencilImage", param_name, "arrayLayers", image_state->image(),
5003                                          subresource_range_error_codes);
5004 }
5005 
ValidateImageBarrierSubresourceRange(const Location & loc,const IMAGE_STATE * image_state,const VkImageSubresourceRange & subresourceRange) const5006 bool CoreChecks::ValidateImageBarrierSubresourceRange(const Location &loc, const IMAGE_STATE *image_state,
5007                                                       const VkImageSubresourceRange &subresourceRange) const {
5008     return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
5009                                          loc.StringFunc().c_str(), loc.StringField().c_str(), "arrayLayers", image_state->image(),
5010                                          sync_vuid_maps::GetSubResourceVUIDs(loc));
5011 }
5012 
5013 namespace barrier_queue_families {
5014 using sync_vuid_maps::GetBarrierQueueVUID;
5015 using sync_vuid_maps::kQueueErrorSummary;
5016 using sync_vuid_maps::QueueError;
5017 
5018 class ValidatorState {
5019   public:
ValidatorState(const ValidationStateTracker * device_data,LogObjectList && obj,const core_error::Location & location,const VulkanTypedHandle & barrier_handle,const VkSharingMode sharing_mode)5020     ValidatorState(const ValidationStateTracker *device_data, LogObjectList &&obj, const core_error::Location &location,
5021                    const VulkanTypedHandle &barrier_handle, const VkSharingMode sharing_mode)
5022         : device_data_(device_data),
5023           objects_(std::move(obj)),
5024           loc_(location),
5025           barrier_handle_(barrier_handle),
5026           sharing_mode_(sharing_mode),
5027           limit_(static_cast<uint32_t>(device_data->physical_device_state->queue_family_properties.size())),
5028           mem_ext_(IsExtEnabled(device_data->device_extensions.vk_khr_external_memory)) {}
5029 
5030     // Log the messages using boilerplate from object state, and Vu specific information from the template arg
5031     // One and two family versions, in the single family version, Vu holds the name of the passed parameter
LogMsg(QueueError vu_index,uint32_t family,const char * param_name) const5032     bool LogMsg(QueueError vu_index, uint32_t family, const char *param_name) const {
5033         const std::string val_code = GetBarrierQueueVUID(loc_, vu_index);
5034         const char *annotation = GetFamilyAnnotation(family);
5035         return device_data_->LogError(objects_, val_code, "%s Barrier using %s %s created with sharingMode %s, has %s %u%s. %s",
5036                                       loc_.Message().c_str(), GetTypeString(),
5037                                       device_data_->report_data->FormatHandle(barrier_handle_).c_str(), GetModeString(), param_name,
5038                                       family, annotation, kQueueErrorSummary.at(vu_index).c_str());
5039     }
5040 
LogMsg(QueueError vu_index,uint32_t src_family,uint32_t dst_family) const5041     bool LogMsg(QueueError vu_index, uint32_t src_family, uint32_t dst_family) const {
5042         const std::string val_code = GetBarrierQueueVUID(loc_, vu_index);
5043         const char *src_annotation = GetFamilyAnnotation(src_family);
5044         const char *dst_annotation = GetFamilyAnnotation(dst_family);
5045         return device_data_->LogError(
5046             objects_, val_code,
5047             "%s Barrier using %s %s created with sharingMode %s, has srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
5048             loc_.Message().c_str(), GetTypeString(), device_data_->report_data->FormatHandle(barrier_handle_).c_str(),
5049             GetModeString(), src_family, src_annotation, dst_family, dst_annotation, kQueueErrorSummary.at(vu_index).c_str());
5050     }
5051 
5052     // This abstract Vu can only be tested at submit time, thus we need a callback from the closure containing the needed
5053     // data. Note that the mem_barrier is copied to the closure as the lambda lifespan exceed the guarantees of validity for
5054     // application input.
ValidateAtQueueSubmit(const QUEUE_STATE * queue_state,const ValidationStateTracker * device_data,uint32_t src_family,uint32_t dst_family,const ValidatorState & val)5055     static bool ValidateAtQueueSubmit(const QUEUE_STATE *queue_state, const ValidationStateTracker *device_data,
5056                                       uint32_t src_family, uint32_t dst_family, const ValidatorState &val) {
5057         auto error_code = QueueError::kSubmitQueueMustMatchSrcOrDst;
5058         uint32_t queue_family = queue_state->queueFamilyIndex;
5059         if ((src_family != queue_family) && (dst_family != queue_family)) {
5060             const std::string val_code = GetBarrierQueueVUID(val.loc_, error_code);
5061             const char *src_annotation = val.GetFamilyAnnotation(src_family);
5062             const char *dst_annotation = val.GetFamilyAnnotation(dst_family);
5063             return device_data->LogError(
5064                 queue_state->Handle(), val_code,
5065                 "%s Barrier submitted to queue with family index %u, using %s %s created with sharingMode %s, has "
5066                 "srcQueueFamilyIndex %u%s and dstQueueFamilyIndex %u%s. %s",
5067                 val.loc_.Message().c_str(), queue_family, val.GetTypeString(),
5068                 device_data->report_data->FormatHandle(val.barrier_handle_).c_str(), val.GetModeString(), src_family,
5069                 src_annotation, dst_family, dst_annotation, kQueueErrorSummary.at(error_code).c_str());
5070         }
5071         return false;
5072     }
5073     // Logical helpers for semantic clarity
KhrExternalMem() const5074     inline bool KhrExternalMem() const { return mem_ext_; }
IsValid(uint32_t queue_family) const5075     inline bool IsValid(uint32_t queue_family) const { return (queue_family < limit_); }
IsValidOrSpecial(uint32_t queue_family) const5076     inline bool IsValidOrSpecial(uint32_t queue_family) const {
5077         return IsValid(queue_family) || (mem_ext_ && QueueFamilyIsExternal(queue_family));
5078     }
5079 
5080     // Helpers for LogMsg
GetModeString() const5081     const char *GetModeString() const { return string_VkSharingMode(sharing_mode_); }
5082 
5083     // Descriptive text for the various types of queue family index
GetFamilyAnnotation(uint32_t family) const5084     const char *GetFamilyAnnotation(uint32_t family) const {
5085         const char *external = " (VK_QUEUE_FAMILY_EXTERNAL)";
5086         const char *foreign = " (VK_QUEUE_FAMILY_FOREIGN_EXT)";
5087         const char *ignored = " (VK_QUEUE_FAMILY_IGNORED)";
5088         const char *valid = " (VALID)";
5089         const char *invalid = " (INVALID)";
5090         switch (family) {
5091             case VK_QUEUE_FAMILY_EXTERNAL:
5092                 return external;
5093             case VK_QUEUE_FAMILY_FOREIGN_EXT:
5094                 return foreign;
5095             case VK_QUEUE_FAMILY_IGNORED:
5096                 return ignored;
5097             default:
5098                 if (IsValid(family)) {
5099                     return valid;
5100                 }
5101                 return invalid;
5102         };
5103     }
GetTypeString() const5104     const char *GetTypeString() const { return object_string[barrier_handle_.type]; }
GetSharingMode() const5105     VkSharingMode GetSharingMode() const { return sharing_mode_; }
5106 
5107   protected:
5108     const ValidationStateTracker *device_data_;
5109     const LogObjectList objects_;
5110     const core_error::Location loc_;
5111     const VulkanTypedHandle barrier_handle_;
5112     const VkSharingMode sharing_mode_;
5113     const uint32_t limit_;
5114     const bool mem_ext_;
5115 };
5116 
Validate(const CoreChecks * device_data,const CMD_BUFFER_STATE * cb_state,const ValidatorState & val,const uint32_t src_queue_family,const uint32_t dst_queue_family)5117 bool Validate(const CoreChecks *device_data, const CMD_BUFFER_STATE *cb_state, const ValidatorState &val,
5118               const uint32_t src_queue_family, const uint32_t dst_queue_family) {
5119     bool skip = false;
5120 
5121     const bool mode_concurrent = val.GetSharingMode() == VK_SHARING_MODE_CONCURRENT;
5122     const bool src_ignored = QueueFamilyIsIgnored(src_queue_family);
5123     const bool dst_ignored = QueueFamilyIsIgnored(dst_queue_family);
5124     if (val.KhrExternalMem()) {
5125         if (mode_concurrent) {
5126             bool sync2 = device_data->enabled_features.synchronization2_features.synchronization2 != 0;
5127             // this requirement is removed by VK_KHR_synchronization2
5128             if (!(src_ignored || dst_ignored) && !sync2) {
5129                 skip |= val.LogMsg(QueueError::kSrcOrDstMustBeIgnore, src_queue_family, dst_queue_family);
5130             }
5131             if ((src_ignored && !(dst_ignored || QueueFamilyIsExternal(dst_queue_family))) ||
5132                 (dst_ignored && !(src_ignored || QueueFamilyIsExternal(src_queue_family)))) {
5133                 skip |= val.LogMsg(QueueError::kSpecialOrIgnoreOnly, src_queue_family, dst_queue_family);
5134             }
5135         } else {
5136             // VK_SHARING_MODE_EXCLUSIVE
5137             if (src_queue_family != dst_queue_family) {
5138                 if (!val.IsValidOrSpecial(dst_queue_family)) {
5139                     skip |= val.LogMsg(QueueError::kSrcAndDstValidOrSpecial, dst_queue_family, "dstQueueFamilyIndex");
5140                 }
5141                 if (!val.IsValidOrSpecial(src_queue_family)) {
5142                     skip |= val.LogMsg(QueueError::kSrcAndDstValidOrSpecial, src_queue_family, "srcQueueFamilyIndex");
5143                 }
5144             }
5145         }
5146     } else {
5147         // No memory extension
5148         if (mode_concurrent) {
5149             bool sync2 = device_data->enabled_features.synchronization2_features.synchronization2 != 0;
5150             // this requirement is removed by VK_KHR_synchronization2
5151             if ((!src_ignored || !dst_ignored) && !sync2) {
5152                 skip |= val.LogMsg(QueueError::kSrcAndDestMustBeIgnore, src_queue_family, dst_queue_family);
5153             }
5154         } else {
5155             // VK_SHARING_MODE_EXCLUSIVE
5156             if ((src_queue_family != dst_queue_family) && !(val.IsValid(src_queue_family) && val.IsValid(dst_queue_family))) {
5157                 skip |= val.LogMsg(QueueError::kSrcAndDstBothValid, src_queue_family, dst_queue_family);
5158             }
5159         }
5160     }
5161     return skip;
5162 }
5163 }  // namespace barrier_queue_families
5164 
ValidateConcurrentBarrierAtSubmit(const Location & loc,const ValidationStateTracker & state_data,const QUEUE_STATE & queue_state,const CMD_BUFFER_STATE & cb_state,const VulkanTypedHandle & typed_handle,uint32_t src_queue_family,uint32_t dst_queue_family)5165 bool CoreChecks::ValidateConcurrentBarrierAtSubmit(const Location &loc, const ValidationStateTracker &state_data,
5166                                                    const QUEUE_STATE &queue_state, const CMD_BUFFER_STATE &cb_state,
5167                                                    const VulkanTypedHandle &typed_handle, uint32_t src_queue_family,
5168                                                    uint32_t dst_queue_family) {
5169     using barrier_queue_families::ValidatorState;
5170     ValidatorState val(&state_data, LogObjectList(cb_state.Handle()), loc, typed_handle, VK_SHARING_MODE_CONCURRENT);
5171     return ValidatorState::ValidateAtQueueSubmit(&queue_state, &state_data, src_queue_family, dst_queue_family, val);
5172 }
5173 
5174 // Type specific wrapper for image barriers
5175 template <typename ImgBarrier>
ValidateBarrierQueueFamilies(const Location & loc,const CMD_BUFFER_STATE * cb_state,const ImgBarrier & barrier,const IMAGE_STATE * state_data) const5176 bool CoreChecks::ValidateBarrierQueueFamilies(const Location &loc, const CMD_BUFFER_STATE *cb_state, const ImgBarrier &barrier,
5177                                               const IMAGE_STATE *state_data) const {
5178     // State data is required
5179     if (!state_data) {
5180         return false;
5181     }
5182 
5183     // Create the validator state from the image state
5184     barrier_queue_families::ValidatorState val(this, LogObjectList(cb_state->commandBuffer()), loc,
5185                                                state_data->Handle(), state_data->createInfo.sharingMode);
5186     const uint32_t src_queue_family = barrier.srcQueueFamilyIndex;
5187     const uint32_t dst_queue_family = barrier.dstQueueFamilyIndex;
5188     return barrier_queue_families::Validate(this, cb_state, val, src_queue_family, dst_queue_family);
5189 }
5190 
5191 // Type specific wrapper for buffer barriers
5192 template <typename BufBarrier>
ValidateBarrierQueueFamilies(const Location & loc,const CMD_BUFFER_STATE * cb_state,const BufBarrier & barrier,const BUFFER_STATE * state_data) const5193 bool CoreChecks::ValidateBarrierQueueFamilies(const Location &loc, const CMD_BUFFER_STATE *cb_state, const BufBarrier &barrier,
5194                                               const BUFFER_STATE *state_data) const {
5195     // State data is required
5196     if (!state_data) {
5197         return false;
5198     }
5199 
5200     // Create the validator state from the buffer state
5201     barrier_queue_families::ValidatorState val(this, LogObjectList(cb_state->commandBuffer()), loc,
5202                                                state_data->Handle(), state_data->createInfo.sharingMode);
5203     const uint32_t src_queue_family = barrier.srcQueueFamilyIndex;
5204     const uint32_t dst_queue_family = barrier.dstQueueFamilyIndex;
5205     return barrier_queue_families::Validate(this, cb_state, val, src_queue_family, dst_queue_family);
5206 }
5207 
5208 template <typename Barrier>
ValidateBufferBarrier(const LogObjectList & objects,const Location & loc,const CMD_BUFFER_STATE * cb_state,const Barrier & mem_barrier) const5209 bool CoreChecks::ValidateBufferBarrier(const LogObjectList &objects, const Location &loc, const CMD_BUFFER_STATE *cb_state,
5210                                        const Barrier &mem_barrier) const {
5211     using sync_vuid_maps::BufferError;
5212     using sync_vuid_maps::GetBufferBarrierVUID;
5213 
5214     bool skip = false;
5215 
5216     skip |= ValidateQFOTransferBarrierUniqueness(loc, cb_state, mem_barrier, cb_state->qfo_transfer_buffer_barriers);
5217 
5218     // Validate buffer barrier queue family indices
5219     auto buffer_state = Get<BUFFER_STATE>(mem_barrier.buffer);
5220     if (buffer_state) {
5221         auto buf_loc = loc.dot(Field::buffer);
5222         const auto &mem_vuid = GetBufferBarrierVUID(buf_loc, BufferError::kNoMemory);
5223         skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), loc.StringFunc().c_str(), mem_vuid.c_str());
5224 
5225         skip |= ValidateBarrierQueueFamilies(buf_loc, cb_state, mem_barrier, buffer_state.get());
5226 
5227         auto buffer_size = buffer_state->createInfo.size;
5228         if (mem_barrier.offset >= buffer_size) {
5229             auto offset_loc = loc.dot(Field::offset);
5230             const auto &vuid = GetBufferBarrierVUID(offset_loc, BufferError::kOffsetTooBig);
5231 
5232             skip |= LogError(objects, vuid, "%s %s has offset 0x%" PRIx64 " which is not less than total size 0x%" PRIx64 ".",
5233                              offset_loc.Message().c_str(), report_data->FormatHandle(mem_barrier.buffer).c_str(),
5234                              HandleToUint64(mem_barrier.offset), HandleToUint64(buffer_size));
5235         } else if (mem_barrier.size != VK_WHOLE_SIZE && (mem_barrier.offset + mem_barrier.size > buffer_size)) {
5236             auto size_loc = loc.dot(Field::size);
5237             const auto &vuid = GetBufferBarrierVUID(size_loc, BufferError::kSizeOutOfRange);
5238             skip |= LogError(objects, vuid,
5239                              "%s %s has offset 0x%" PRIx64 " and size 0x%" PRIx64 " whose sum is greater than total size 0x%" PRIx64
5240                              ".",
5241                              size_loc.Message().c_str(), report_data->FormatHandle(mem_barrier.buffer).c_str(),
5242                              HandleToUint64(mem_barrier.offset), HandleToUint64(mem_barrier.size), HandleToUint64(buffer_size));
5243         }
5244         if (mem_barrier.size == 0) {
5245             auto size_loc = loc.dot(Field::size);
5246             const auto &vuid = GetBufferBarrierVUID(size_loc, BufferError::kSizeZero);
5247             skip |= LogError(objects, vuid, "%s %s has a size of 0.", loc.Message().c_str(),
5248                              report_data->FormatHandle(mem_barrier.buffer).c_str());
5249         }
5250     }
5251     return skip;
5252 }
5253 
5254 template <typename Barrier>
ValidateImageBarrier(const LogObjectList & objects,const Location & loc,const CMD_BUFFER_STATE * cb_state,const Barrier & mem_barrier) const5255 bool CoreChecks::ValidateImageBarrier(const LogObjectList &objects, const Location &loc, const CMD_BUFFER_STATE *cb_state,
5256                                       const Barrier &mem_barrier) const {
5257     bool skip = false;
5258 
5259     skip |= ValidateQFOTransferBarrierUniqueness(loc, cb_state, mem_barrier, cb_state->qfo_transfer_image_barriers);
5260 
5261     bool is_ilt = true;
5262     if (enabled_features.synchronization2_features.synchronization2) {
5263         is_ilt = mem_barrier.oldLayout != mem_barrier.newLayout;
5264     }
5265 
5266     if (is_ilt) {
5267         if (mem_barrier.newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier.newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
5268             auto layout_loc = loc.dot(Field::newLayout);
5269             const auto &vuid = sync_vuid_maps::GetImageBarrierVUID(loc, sync_vuid_maps::ImageError::kBadLayout);
5270             skip |=
5271                 LogError(cb_state->commandBuffer(), vuid, "%s Image Layout cannot be transitioned to UNDEFINED or PREINITIALIZED.",
5272                          layout_loc.Message().c_str());
5273         }
5274     }
5275 
5276     auto image_data = Get<IMAGE_STATE>(mem_barrier.image);
5277     if (image_data) {
5278         auto image_loc = loc.dot(Field::image);
5279 
5280         skip |= ValidateMemoryIsBoundToImage(image_data.get(), loc);
5281 
5282         skip |= ValidateBarrierQueueFamilies(image_loc, cb_state, mem_barrier, image_data.get());
5283 
5284         skip |= ValidateImageAspectMask(image_data->image(), image_data->createInfo.format, mem_barrier.subresourceRange.aspectMask,
5285                                         loc.StringFunc().c_str());
5286 
5287         skip |=
5288             ValidateImageBarrierSubresourceRange(loc.dot(Field::subresourceRange), image_data.get(), mem_barrier.subresourceRange);
5289         skip |= ValidateImageAcquired(*image_data, loc.StringFunc().c_str());
5290     }
5291     return skip;
5292 }
5293 
ValidateBarriers(const Location & outer_loc,const CMD_BUFFER_STATE * cb_state,VkPipelineStageFlags src_stage_mask,VkPipelineStageFlags dst_stage_mask,uint32_t memBarrierCount,const VkMemoryBarrier * pMemBarriers,uint32_t bufferBarrierCount,const VkBufferMemoryBarrier * pBufferMemBarriers,uint32_t imageMemBarrierCount,const VkImageMemoryBarrier * pImageMemBarriers) const5294 bool CoreChecks::ValidateBarriers(const Location &outer_loc, const CMD_BUFFER_STATE *cb_state, VkPipelineStageFlags src_stage_mask,
5295                                   VkPipelineStageFlags dst_stage_mask, uint32_t memBarrierCount,
5296                                   const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
5297                                   const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
5298                                   const VkImageMemoryBarrier *pImageMemBarriers) const {
5299     bool skip = false;
5300     LogObjectList objects(cb_state->commandBuffer());
5301 
5302     for (uint32_t i = 0; i < memBarrierCount; ++i) {
5303         const auto &mem_barrier = pMemBarriers[i];
5304         auto loc = outer_loc.dot(Struct::VkMemoryBarrier, Field::pMemoryBarriers, i);
5305         skip |= ValidateMemoryBarrier(objects, loc, cb_state, mem_barrier, src_stage_mask, dst_stage_mask);
5306     }
5307     for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
5308         const auto &mem_barrier = pImageMemBarriers[i];
5309         auto loc = outer_loc.dot(Struct::VkImageMemoryBarrier, Field::pImageMemoryBarriers, i);
5310         skip |= ValidateMemoryBarrier(objects, loc, cb_state, mem_barrier, src_stage_mask, dst_stage_mask);
5311         skip |= ValidateImageBarrier(objects, loc, cb_state, mem_barrier);
5312     }
5313     {
5314         Location loc(outer_loc.function, Struct::VkImageMemoryBarrier);
5315         skip |= ValidateBarriersToImages(loc, cb_state, imageMemBarrierCount, pImageMemBarriers);
5316     }
5317     for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
5318         const auto &mem_barrier = pBufferMemBarriers[i];
5319         auto loc = outer_loc.dot(Struct::VkBufferMemoryBarrier, Field::pMemoryBarriers, i);
5320         skip |= ValidateMemoryBarrier(objects, loc, cb_state, mem_barrier, src_stage_mask, dst_stage_mask);
5321         skip |= ValidateBufferBarrier(objects, loc, cb_state, mem_barrier);
5322     }
5323     return skip;
5324 }
5325 
ValidateDependencyInfo(const LogObjectList & objects,const Location & outer_loc,const CMD_BUFFER_STATE * cb_state,const VkDependencyInfoKHR * dep_info) const5326 bool CoreChecks::ValidateDependencyInfo(const LogObjectList &objects, const Location &outer_loc, const CMD_BUFFER_STATE *cb_state,
5327                                         const VkDependencyInfoKHR *dep_info) const {
5328     bool skip = false;
5329 
5330     if (cb_state->activeRenderPass) {
5331         skip |= ValidateRenderPassPipelineBarriers(outer_loc, cb_state, dep_info);
5332         if (skip) return true;  // Early return to avoid redundant errors from below calls
5333     }
5334     for (uint32_t i = 0; i < dep_info->memoryBarrierCount; ++i) {
5335         const auto &mem_barrier = dep_info->pMemoryBarriers[i];
5336         auto loc = outer_loc.dot(Struct::VkMemoryBarrier2KHR, Field::pMemoryBarriers, i);
5337         skip |= ValidateMemoryBarrier(objects, loc, cb_state, mem_barrier);
5338     }
5339     for (uint32_t i = 0; i < dep_info->imageMemoryBarrierCount; ++i) {
5340         const auto &mem_barrier = dep_info->pImageMemoryBarriers[i];
5341         auto loc = outer_loc.dot(Struct::VkImageMemoryBarrier2KHR, Field::pImageMemoryBarriers, i);
5342         skip |= ValidateMemoryBarrier(objects, loc, cb_state, mem_barrier);
5343         skip |= ValidateImageBarrier(objects, loc, cb_state, mem_barrier);
5344     }
5345     {
5346         Location loc(outer_loc.function, Struct::VkImageMemoryBarrier2KHR);
5347         skip |= ValidateBarriersToImages(loc, cb_state, dep_info->imageMemoryBarrierCount, dep_info->pImageMemoryBarriers);
5348     }
5349 
5350     for (uint32_t i = 0; i < dep_info->bufferMemoryBarrierCount; ++i) {
5351         const auto &mem_barrier = dep_info->pBufferMemoryBarriers[i];
5352         auto loc = outer_loc.dot(Struct::VkBufferMemoryBarrier2KHR, Field::pBufferMemoryBarriers, i);
5353         skip |= ValidateMemoryBarrier(objects, loc, cb_state, mem_barrier);
5354         skip |= ValidateBufferBarrier(objects, loc, cb_state, mem_barrier);
5355     }
5356 
5357     return skip;
5358 }
5359 
5360 // template to check all original barrier structures
5361 template <typename Barrier>
ValidateMemoryBarrier(const LogObjectList & objects,const Location & loc,const CMD_BUFFER_STATE * cb_state,const Barrier & barrier,VkPipelineStageFlags src_stage_mask,VkPipelineStageFlags dst_stage_mask) const5362 bool CoreChecks::ValidateMemoryBarrier(const LogObjectList &objects, const Location &loc, const CMD_BUFFER_STATE *cb_state,
5363                                        const Barrier &barrier, VkPipelineStageFlags src_stage_mask,
5364                                        VkPipelineStageFlags dst_stage_mask) const {
5365     bool skip = false;
5366     assert(cb_state);
5367     auto queue_flags = cb_state->GetQueueFlags();
5368 
5369     if (!cb_state->IsAcquireOp(barrier)) {
5370         skip |= ValidateAccessMask(objects, loc.dot(Field::srcAccessMask), queue_flags, barrier.srcAccessMask, src_stage_mask);
5371     }
5372     if (!cb_state->IsReleaseOp(barrier)) {
5373         skip |= ValidateAccessMask(objects, loc.dot(Field::dstAccessMask), queue_flags, barrier.dstAccessMask, dst_stage_mask);
5374     }
5375     return skip;
5376 }
5377 
5378 // template to check all synchronization2 barrier structures
5379 template <typename Barrier>
ValidateMemoryBarrier(const LogObjectList & objects,const Location & loc,const CMD_BUFFER_STATE * cb_state,const Barrier & barrier) const5380 bool CoreChecks::ValidateMemoryBarrier(const LogObjectList &objects, const Location &loc, const CMD_BUFFER_STATE *cb_state,
5381                                        const Barrier &barrier) const {
5382     bool skip = false;
5383     assert(cb_state);
5384     auto queue_flags = cb_state->GetQueueFlags();
5385 
5386     skip |= ValidatePipelineStage(objects, loc.dot(Field::srcStageMask), queue_flags, barrier.srcStageMask);
5387     if (!cb_state->IsAcquireOp(barrier)) {
5388         skip |=
5389             ValidateAccessMask(objects, loc.dot(Field::srcAccessMask), queue_flags, barrier.srcAccessMask, barrier.srcStageMask);
5390     }
5391 
5392     skip |= ValidatePipelineStage(objects, loc.dot(Field::dstStageMask), queue_flags, barrier.dstStageMask);
5393     if (!cb_state->IsReleaseOp(barrier)) {
5394         skip |=
5395             ValidateAccessMask(objects, loc.dot(Field::dstAccessMask), queue_flags, barrier.dstAccessMask, barrier.dstStageMask);
5396     }
5397     return skip;
5398 }
5399 
5400 // VkSubpassDependency validation happens when vkCreateRenderPass() is called.
5401 // Dependencies between subpasses can only use pipeline stages compatible with VK_QUEUE_GRAPHICS_BIT,
5402 // for external subpasses we don't have a yet command buffer so we have to assume all of them are valid.
SubpassToQueueFlags(uint32_t subpass)5403 static inline VkQueueFlags SubpassToQueueFlags(uint32_t subpass) {
5404     return subpass == VK_SUBPASS_EXTERNAL ? sync_utils::kAllQueueTypes : static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT);
5405 }
5406 
ValidateSubpassDependency(const LogObjectList & objects,const Location & in_loc,const VkSubpassDependency2 & dependency) const5407 bool CoreChecks::ValidateSubpassDependency(const LogObjectList &objects, const Location &in_loc,
5408                                            const VkSubpassDependency2 &dependency) const {
5409     bool skip = false;
5410     Location loc = in_loc;
5411     VkMemoryBarrier2KHR converted_barrier;
5412     const auto *mem_barrier = LvlFindInChain<VkMemoryBarrier2KHR>(dependency.pNext);
5413 
5414     if (mem_barrier && enabled_features.synchronization2_features.synchronization2) {
5415         if (dependency.srcAccessMask != 0) {
5416             skip |= LogError(objects, "UNASSIGNED-CoreChecks-VkSubpassDependency2-srcAccessMask",
5417                              "%s is non-zero when a VkMemoryBarrier2KHR is present in pNext.",
5418                              loc.dot(Field::srcAccessMask).Message().c_str());
5419         }
5420         if (dependency.dstAccessMask != 0) {
5421             skip |= LogError(objects, "UNASSIGNED-CoreChecks-VkSubpassDependency2-dstAccessMask",
5422                              "%s dstAccessMask is non-zero when a VkMemoryBarrier2KHR is present in pNext.",
5423                              loc.dot(Field::dstAccessMask).Message().c_str());
5424         }
5425         if (dependency.srcStageMask != 0) {
5426             skip |= LogError(objects, "UNASSIGNED-CoreChecks-VkSubpassDependency2-srcStageMask",
5427                              "%s srcStageMask is non-zero when a VkMemoryBarrier2KHR is present in pNext.",
5428                              loc.dot(Field::srcStageMask).Message().c_str());
5429         }
5430         if (dependency.dstStageMask != 0) {
5431             skip |= LogError(objects, "UNASSIGNED-CoreChecks-VkSubpassDependency2-dstStageMask",
5432                              "%s dstStageMask is non-zero when a VkMemoryBarrier2KHR is present in pNext.",
5433                              loc.dot(Field::dstStageMask).Message().c_str());
5434         }
5435         loc = in_loc.dot(Field::pNext);
5436         converted_barrier = *mem_barrier;
5437     } else {
5438         if (mem_barrier) {
5439             skip |= LogError(objects, "UNASSIGNED-CoreChecks-VkSubpassDependency2-pNext",
5440                              "%s a VkMemoryBarrier2KHR is present in pNext but synchronization2 is not enabled.",
5441                              loc.Message().c_str());
5442         }
5443         // use the subpass dependency flags, upconverted into wider synchronization2 fields.
5444         converted_barrier.srcStageMask = dependency.srcStageMask;
5445         converted_barrier.dstStageMask = dependency.dstStageMask;
5446         converted_barrier.srcAccessMask = dependency.srcAccessMask;
5447         converted_barrier.dstAccessMask = dependency.dstAccessMask;
5448     }
5449     auto src_queue_flags = SubpassToQueueFlags(dependency.srcSubpass);
5450     skip |= ValidatePipelineStage(objects, loc.dot(Field::srcStageMask), src_queue_flags, converted_barrier.srcStageMask);
5451     skip |= ValidateAccessMask(objects, loc.dot(Field::srcAccessMask), src_queue_flags, converted_barrier.srcAccessMask,
5452                                converted_barrier.srcStageMask);
5453 
5454     auto dst_queue_flags = SubpassToQueueFlags(dependency.dstSubpass);
5455     skip |= ValidatePipelineStage(objects, loc.dot(Field::dstStageMask), dst_queue_flags, converted_barrier.dstStageMask);
5456     skip |= ValidateAccessMask(objects, loc.dot(Field::dstAccessMask), dst_queue_flags, converted_barrier.dstAccessMask,
5457                                converted_barrier.dstStageMask);
5458     return skip;
5459 }
5460 
ValidateImageViewFormatFeatures(const IMAGE_STATE * image_state,const VkFormat view_format,const VkImageUsageFlags image_usage) const5461 bool CoreChecks::ValidateImageViewFormatFeatures(const IMAGE_STATE *image_state, const VkFormat view_format,
5462                                                  const VkImageUsageFlags image_usage) const {
5463     // Pass in image_usage here instead of extracting it from image_state in case there's a chained VkImageViewUsageCreateInfo
5464     bool skip = false;
5465 
5466     VkFormatFeatureFlags tiling_features = 0;
5467     const VkImageTiling image_tiling = image_state->createInfo.tiling;
5468 
5469     if (image_state->HasAHBFormat()) {
5470         // AHB image view and image share same feature sets
5471         tiling_features = image_state->format_features;
5472     } else if (image_tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
5473         // Parameter validation should catch if this is used without VK_EXT_image_drm_format_modifier
5474         assert(IsExtEnabled(device_extensions.vk_ext_image_drm_format_modifier));
5475         VkImageDrmFormatModifierPropertiesEXT drm_format_properties = {VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
5476                                                                        nullptr};
5477         DispatchGetImageDrmFormatModifierPropertiesEXT(device, image_state->image(), &drm_format_properties);
5478 
5479         auto fmt_drm_props = LvlInitStruct<VkDrmFormatModifierPropertiesListEXT>();
5480         auto fmt_props_2 = LvlInitStruct<VkFormatProperties2>(&fmt_drm_props);
5481         DispatchGetPhysicalDeviceFormatProperties2(physical_device, view_format, &fmt_props_2);
5482 
5483         std::vector<VkDrmFormatModifierPropertiesEXT> drm_properties;
5484         drm_properties.resize(fmt_drm_props.drmFormatModifierCount);
5485         fmt_drm_props.pDrmFormatModifierProperties = drm_properties.data();
5486 
5487         DispatchGetPhysicalDeviceFormatProperties2(physical_device, view_format, &fmt_props_2);
5488 
5489         for (uint32_t i = 0; i < fmt_drm_props.drmFormatModifierCount; i++) {
5490             if (fmt_drm_props.pDrmFormatModifierProperties[i].drmFormatModifier == drm_format_properties.drmFormatModifier) {
5491                 tiling_features = fmt_drm_props.pDrmFormatModifierProperties[i].drmFormatModifierTilingFeatures;
5492                 break;
5493             }
5494         }
5495     } else {
5496         VkFormatProperties format_properties = GetPDFormatProperties(view_format);
5497         tiling_features = (image_tiling == VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
5498                                                                    : format_properties.optimalTilingFeatures;
5499     }
5500 
5501     if (tiling_features == 0) {
5502         skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-None-02273",
5503                          "vkCreateImageView(): pCreateInfo->format %s with tiling %s has no supported format features on this "
5504                          "physical device.",
5505                          string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5506     } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
5507         skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-usage-02274",
5508                          "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5509                          "VK_IMAGE_USAGE_SAMPLED_BIT.",
5510                          string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5511     } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
5512         skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-usage-02275",
5513                          "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5514                          "VK_IMAGE_USAGE_STORAGE_BIT.",
5515                          string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5516     } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
5517         skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-usage-02276",
5518                          "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5519                          "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.",
5520                          string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5521     } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
5522                !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
5523         skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-usage-02277",
5524                          "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5525                          "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT.",
5526                          string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5527     } else if ((image_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
5528                !(tiling_features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))) {
5529         skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-usage-02652",
5530                          "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5531                          "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT or VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.",
5532                          string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5533     } else if ((image_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) &&
5534                !(tiling_features & VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR)) {
5535         if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
5536             skip |= LogError(image_state->image(), "VUID-VkImageViewCreateInfo-usage-04550",
5537                              "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
5538                              "VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR.",
5539                              string_VkFormat(view_format), string_VkImageTiling(image_tiling));
5540         }
5541     }
5542 
5543     return skip;
5544 }
5545 
PreCallValidateCreateImageView(VkDevice device,const VkImageViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImageView * pView) const5546 bool CoreChecks::PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
5547                                                 const VkAllocationCallbacks *pAllocator, VkImageView *pView) const {
5548     bool skip = false;
5549     const auto image_state = Get<IMAGE_STATE>(pCreateInfo->image);
5550     if (image_state) {
5551         skip |=
5552             ValidateImageUsageFlags(image_state.get(),
5553                                     VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
5554                                         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
5555                                         VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV |
5556                                         VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
5557                                     false, "VUID-VkImageViewCreateInfo-image-04441", "vkCreateImageView()",
5558                                     "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT|"
5559                                     "TRANSIENT_ATTACHMENT|SHADING_RATE_IMAGE|FRAGMENT_DENSITY_MAP]_BIT");
5560         // If this isn't a sparse image, it needs to have memory backing it at CreateImageView time
5561         skip |= ValidateMemoryIsBoundToImage(image_state.get(), "vkCreateImageView()", "VUID-VkImageViewCreateInfo-image-01020");
5562         // Checks imported from image layer
5563         skip |= ValidateCreateImageViewSubresourceRange(
5564             image_state.get(),
5565             pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D || pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY,
5566             pCreateInfo->subresourceRange);
5567 
5568         VkImageCreateFlags image_flags = image_state->createInfo.flags;
5569         VkFormat image_format = image_state->createInfo.format;
5570         VkImageUsageFlags image_usage = image_state->createInfo.usage;
5571         VkFormat view_format = pCreateInfo->format;
5572         VkImageAspectFlags aspect_mask = pCreateInfo->subresourceRange.aspectMask;
5573         VkImageType image_type = image_state->createInfo.imageType;
5574         VkImageViewType view_type = pCreateInfo->viewType;
5575         uint32_t layer_count = pCreateInfo->subresourceRange.layerCount;
5576 
5577         // If there's a chained VkImageViewUsageCreateInfo struct, modify image_usage to match
5578         auto chained_ivuci_struct = LvlFindInChain<VkImageViewUsageCreateInfo>(pCreateInfo->pNext);
5579         if (chained_ivuci_struct) {
5580             if (IsExtEnabled(device_extensions.vk_khr_maintenance2)) {
5581                 if (!IsExtEnabled(device_extensions.vk_ext_separate_stencil_usage)) {
5582                     if ((image_usage | chained_ivuci_struct->usage) != image_usage) {
5583                         skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02661",
5584                                          "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo, usage must not "
5585                                          "include any bits that were not set in VkImageCreateInfo::usage used to create image");
5586                     }
5587                 } else {
5588                     const auto image_stencil_struct = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_state->createInfo.pNext);
5589                     if (image_stencil_struct == nullptr) {
5590                         if ((image_usage | chained_ivuci_struct->usage) != image_usage) {
5591                             skip |= LogError(
5592                                 pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02662",
5593                                 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo and image was not created "
5594                                 "with a VkImageStencilUsageCreateInfo in pNext of vkImageCreateInfo, usage must not include "
5595                                 "any bits that were not set in VkImageCreateInfo::usage used to create image");
5596                         }
5597                     } else {
5598                         if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) == VK_IMAGE_ASPECT_STENCIL_BIT &&
5599                             (image_stencil_struct->stencilUsage | chained_ivuci_struct->usage) !=
5600                                 image_stencil_struct->stencilUsage) {
5601                             skip |= LogError(
5602                                 pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02663",
5603                                 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo, image was created with a "
5604                                 "VkImageStencilUsageCreateInfo in pNext of vkImageCreateInfo, and subResourceRange.aspectMask "
5605                                 "includes VK_IMAGE_ASPECT_STENCIL_BIT, VkImageViewUsageCreateInfo::usage must not include any "
5606                                 "bits that were not set in VkImageStencilUsageCreateInfo::stencilUsage used to create image");
5607                         }
5608                         if ((aspect_mask & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
5609                             (image_usage | chained_ivuci_struct->usage) != image_usage) {
5610                             skip |= LogError(
5611                                 pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-02664",
5612                                 "vkCreateImageView(): pNext chain includes VkImageViewUsageCreateInfo, image was created with a "
5613                                 "VkImageStencilUsageCreateInfo in pNext of vkImageCreateInfo, and subResourceRange.aspectMask "
5614                                 "includes bits other than VK_IMAGE_ASPECT_STENCIL_BIT, VkImageViewUsageCreateInfo::usage must not "
5615                                 "include any bits that were not set in VkImageCreateInfo::usage used to create image");
5616                         }
5617                     }
5618                 }
5619             }
5620 
5621             image_usage = chained_ivuci_struct->usage;
5622         }
5623 
5624         // If image used VkImageFormatListCreateInfo need to make sure a format from list is used
5625         const auto format_list_info = LvlFindInChain<VkImageFormatListCreateInfo>(image_state->createInfo.pNext);
5626         if (format_list_info && (format_list_info->viewFormatCount > 0)) {
5627             bool foundFormat = false;
5628             for (uint32_t i = 0; i < format_list_info->viewFormatCount; i++) {
5629                 if (format_list_info->pViewFormats[i] == view_format) {
5630                     foundFormat = true;
5631                     break;
5632                 }
5633             }
5634             if (foundFormat == false) {
5635                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-pNext-01585",
5636                                  "vkCreateImageView(): image was created with a VkImageFormatListCreateInfo in pNext of "
5637                                  "vkImageCreateInfo, but none of the formats match the VkImageViewCreateInfo::format (%s).",
5638                                  string_VkFormat(view_format));
5639             }
5640         }
5641 
5642         // Validate VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT state, if view/image formats differ
5643         if ((image_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && (image_format != view_format)) {
5644             if (FormatIsMultiplane(image_format)) {
5645                 VkFormat compat_format = FindMultiplaneCompatibleFormat(image_format, aspect_mask);
5646                 if (view_format != compat_format) {
5647                     // View format must match the multiplane compatible format
5648                     std::stringstream ss;
5649                     ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
5650                        << " is not compatible with plane " << GetPlaneIndex(aspect_mask) << " of underlying image format "
5651                        << string_VkFormat(image_format) << ", must be " << string_VkFormat(compat_format) << ".";
5652                     skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01586", "%s", ss.str().c_str());
5653                 }
5654             } else {
5655                 if (!(image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT)) {
5656                     // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
5657                     auto image_class = FormatCompatibilityClass(image_format);
5658                     auto view_class = FormatCompatibilityClass(view_format);
5659                     // Need to only check if one is NONE to handle edge case both are NONE
5660                     if ((image_class != view_class) || (image_class == FORMAT_COMPATIBILITY_CLASS::NONE)) {
5661                         const char *error_vuid;
5662                         if ((!IsExtEnabled(device_extensions.vk_khr_maintenance2)) &&
5663                             (!IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion))) {
5664                             error_vuid = "VUID-VkImageViewCreateInfo-image-01018";
5665                         } else if ((IsExtEnabled(device_extensions.vk_khr_maintenance2)) &&
5666                                    (!IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion))) {
5667                             error_vuid = "VUID-VkImageViewCreateInfo-image-01759";
5668                         } else if ((!IsExtEnabled(device_extensions.vk_khr_maintenance2)) &&
5669                                    (IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion))) {
5670                             error_vuid = "VUID-VkImageViewCreateInfo-image-01760";
5671                         } else {
5672                             // both enabled
5673                             error_vuid = "VUID-VkImageViewCreateInfo-image-01761";
5674                         }
5675                         std::stringstream ss;
5676                         ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
5677                            << " is not in the same format compatibility class as "
5678                            << report_data->FormatHandle(pCreateInfo->image).c_str() << "  format " << string_VkFormat(image_format)
5679                            << ".  Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
5680                            << "can support ImageViews with differing formats but they must be in the same compatibility class.";
5681                         skip |= LogError(pCreateInfo->image, error_vuid, "%s", ss.str().c_str());
5682                     }
5683                 }
5684             }
5685         } else {
5686             // Format MUST be IDENTICAL to the format the image was created with
5687             // Unless it is a multi-planar color bit aspect
5688             if ((image_format != view_format) &&
5689                 ((FormatIsMultiplane(image_format) == false) || (aspect_mask != VK_IMAGE_ASPECT_COLOR_BIT))) {
5690                 const char *vuid = IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)
5691                                        ? "VUID-VkImageViewCreateInfo-image-01762"
5692                                        : "VUID-VkImageViewCreateInfo-image-01019";
5693                 std::stringstream ss;
5694                 ss << "vkCreateImageView() format " << string_VkFormat(view_format) << " differs from "
5695                    << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
5696                    << ".  Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
5697                 skip |= LogError(pCreateInfo->image, vuid, "%s", ss.str().c_str());
5698             }
5699         }
5700 
5701         if (image_state->createInfo.samples != VK_SAMPLE_COUNT_1_BIT && view_type != VK_IMAGE_VIEW_TYPE_2D &&
5702             view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
5703             skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-04972",
5704                              "vkCreateImageView(): image was created with sample count %s, but pCreateInfo->viewType is %s.",
5705                              string_VkSampleCountFlagBits(image_state->createInfo.samples), string_VkImageViewType(view_type));
5706         }
5707 
5708         // Validate correct image aspect bits for desired formats and format consistency
5709         skip |= ValidateImageAspectMask(image_state->image(), image_format, aspect_mask, "vkCreateImageView()");
5710 
5711         // Valdiate Image/ImageView type compatibility #resources-image-views-compatibility
5712         switch (image_type) {
5713             case VK_IMAGE_TYPE_1D:
5714                 if (view_type != VK_IMAGE_VIEW_TYPE_1D && view_type != VK_IMAGE_VIEW_TYPE_1D_ARRAY) {
5715                     skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5716                                      "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5717                                      string_VkImageViewType(view_type), string_VkImageType(image_type));
5718                 }
5719                 break;
5720             case VK_IMAGE_TYPE_2D:
5721                 if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
5722                     if ((view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) &&
5723                         !(image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
5724                         skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01003",
5725                                          "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5726                                          string_VkImageViewType(view_type), string_VkImageType(image_type));
5727                     } else if (view_type != VK_IMAGE_VIEW_TYPE_CUBE && view_type != VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
5728                         skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5729                                          "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5730                                          string_VkImageViewType(view_type), string_VkImageType(image_type));
5731                     }
5732                 }
5733                 break;
5734             case VK_IMAGE_TYPE_3D:
5735                 if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
5736                     if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
5737                         if ((view_type == VK_IMAGE_VIEW_TYPE_2D || view_type == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
5738                             if (!(image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)) {
5739                                 skip |=
5740                                     LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01005",
5741                                              "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type "
5742                                              "%s since the image doesn't have VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT flag set.",
5743                                              string_VkImageViewType(view_type), string_VkImageType(image_type));
5744                             } else if ((image_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT |
5745                                                        VK_IMAGE_CREATE_SPARSE_ALIASED_BIT))) {
5746                                 skip |= LogError(
5747                                     pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-04971",
5748                                     "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s "
5749                                     "when the VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or "
5750                                     "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags are enabled.",
5751                                     string_VkImageViewType(view_type), string_VkImageType(image_type));
5752                             } else if (pCreateInfo->subresourceRange.levelCount != 1) {
5753                                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-04970",
5754                                                  "vkCreateImageView(): pCreateInfo->viewType %s is with image type %s must have a "
5755                                                  "levelCount of 1 but it is %u.",
5756                                                  string_VkImageViewType(view_type), string_VkImageType(image_type),
5757                                                  pCreateInfo->subresourceRange.levelCount);
5758                             }
5759                         } else {
5760                             skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5761                                              "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5762                                              string_VkImageViewType(view_type), string_VkImageType(image_type));
5763                         }
5764                     }
5765                 } else {
5766                     if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
5767                         // Help point to VK_KHR_maintenance1
5768                         if ((view_type == VK_IMAGE_VIEW_TYPE_2D || view_type == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
5769                             skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5770                                              "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s "
5771                                              "without VK_KHR_maintenance1 enabled which was promoted in Vulkan 1.0.",
5772                                              string_VkImageViewType(view_type), string_VkImageType(image_type));
5773                         } else {
5774                             skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-subResourceRange-01021",
5775                                              "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
5776                                              string_VkImageViewType(view_type), string_VkImageType(image_type));
5777                         }
5778                     }
5779                 }
5780                 break;
5781             default:
5782                 break;
5783         }
5784 
5785         // External format checks needed when VK_ANDROID_external_memory_android_hardware_buffer enabled
5786         if (IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5787             skip |= ValidateCreateImageViewANDROID(pCreateInfo);
5788         }
5789 
5790         skip |= ValidateImageViewFormatFeatures(image_state.get(), view_format, image_usage);
5791 
5792         if (enabled_features.shading_rate_image_features.shadingRateImage) {
5793             if (image_usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) {
5794                 if (view_format != VK_FORMAT_R8_UINT) {
5795                     skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-02087",
5796                                      "vkCreateImageView() If image was created with usage containing "
5797                                      "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, format must be VK_FORMAT_R8_UINT.");
5798                 }
5799             }
5800         }
5801 
5802         if (enabled_features.shading_rate_image_features.shadingRateImage ||
5803             enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
5804             if (image_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) {
5805                 if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
5806                     skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-02086",
5807                                      "vkCreateImageView() If image was created with usage containing "
5808                                      "VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, viewType must be "
5809                                      "VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
5810                 }
5811             }
5812         }
5813 
5814         if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate &&
5815             !phys_dev_ext_props.fragment_shading_rate_props.layeredShadingRateAttachments &&
5816             image_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR && layer_count != 1) {
5817             skip |= LogError(device, "VUID-VkImageViewCreateInfo-usage-04551",
5818                              "vkCreateImageView(): subresourceRange.layerCount is %u for a shading rate attachment image view.",
5819                              layer_count);
5820         }
5821 
5822         if (layer_count == VK_REMAINING_ARRAY_LAYERS) {
5823             const uint32_t remaining_layers = image_state->createInfo.arrayLayers - pCreateInfo->subresourceRange.baseArrayLayer;
5824             if (view_type == VK_IMAGE_VIEW_TYPE_CUBE && remaining_layers != 6) {
5825                 skip |= LogError(device, "VUID-VkImageViewCreateInfo-viewType-02962",
5826                                  "vkCreateImageView(): subresourceRange.layerCount VK_REMAINING_ARRAY_LAYERS=(%d) must be 6",
5827                                  remaining_layers);
5828             }
5829             if (view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && ((remaining_layers) % 6) != 0) {
5830                 skip |= LogError(
5831                     device, "VUID-VkImageViewCreateInfo-viewType-02963",
5832                     "vkCreateImageView(): subresourceRange.layerCount VK_REMAINING_ARRAY_LAYERS=(%d) must be a multiple of 6",
5833                     remaining_layers);
5834             }
5835             if ((remaining_layers != 1) && ((view_type == VK_IMAGE_VIEW_TYPE_1D) || (view_type == VK_IMAGE_VIEW_TYPE_2D) ||
5836                                             (view_type == VK_IMAGE_VIEW_TYPE_3D))) {
5837                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-imageViewType-04974",
5838                                  "vkCreateImageView(): Using pCreateInfo->viewType %s and the subresourceRange.layerCount "
5839                                  "VK_REMAINING_ARRAY_LAYERS=(%d) and must 1 (try looking into VK_IMAGE_VIEW_TYPE_*_ARRAY).",
5840                                  string_VkImageViewType(view_type), remaining_layers);
5841             }
5842         } else {
5843             if ((layer_count != 1) && ((view_type == VK_IMAGE_VIEW_TYPE_1D) || (view_type == VK_IMAGE_VIEW_TYPE_2D) ||
5844                                        (view_type == VK_IMAGE_VIEW_TYPE_3D))) {
5845                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-imageViewType-04973",
5846                                  "vkCreateImageView(): Using pCreateInfo->viewType %s and the subresourceRange.layerCount is %d "
5847                                  "and must 1 (try looking into VK_IMAGE_VIEW_TYPE_*_ARRAY).",
5848                                  string_VkImageViewType(view_type), layer_count);
5849             }
5850         }
5851 
5852         if (image_usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) {
5853             if (pCreateInfo->subresourceRange.levelCount != 1) {
5854                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-02571",
5855                                  "vkCreateImageView(): If image was created with usage containing "
5856                                  "VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, subresourceRange.levelCount (%d) must: be 1",
5857                                  pCreateInfo->subresourceRange.levelCount);
5858             }
5859         }
5860         if (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT) {
5861             if (!enabled_features.fragment_density_map_features.fragmentDensityMapDynamic) {
5862                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-02572",
5863                                  "vkCreateImageView(): If the fragmentDensityMapDynamic feature is not enabled, "
5864                                  "flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT");
5865             }
5866         } else {
5867             if (image_usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) {
5868                 if (image_flags & (VK_IMAGE_CREATE_PROTECTED_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
5869                                    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_ALIASED_BIT)) {
5870                     skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-04116",
5871                                      "vkCreateImageView(): If image was created with usage containing "
5872                                      "VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT flags must not contain any of "
5873                                      "VK_IMAGE_CREATE_PROTECTED_BIT, VK_IMAGE_CREATE_SPARSE_BINDING_BIT, "
5874                                      "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or VK_IMAGE_CREATE_SPARSE_ALIASED_BIT");
5875                 }
5876             }
5877         }
5878 
5879         if (image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) {
5880             if (pCreateInfo->subresourceRange.levelCount != 1) {
5881                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01584",
5882                                  "vkCreateImageView(): Image was created with VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT bit, "
5883                                  "but subresourcesRange.levelCount (%" PRIu32 ") is not 1.",
5884                                  pCreateInfo->subresourceRange.levelCount);
5885             }
5886             if (pCreateInfo->subresourceRange.layerCount != 1) {
5887                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-01584",
5888                                  "vkCreateImageView(): Image was created with VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT bit, "
5889                                  "but subresourcesRange.layerCount (%" PRIu32 ") is not 1.",
5890                                  pCreateInfo->subresourceRange.layerCount);
5891             }
5892         }
5893 
5894         if (image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT && !FormatIsCompressed(view_format) &&
5895             pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_3D) {
5896             skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-04739",
5897                              "vkCreateImageView(): Image was created with VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT bit and "
5898                              "non-compressed format (%s), but pCreateInfo->viewType is VK_IMAGE_VIEW_TYPE_3D.",
5899                              string_VkFormat(image_format));
5900         }
5901 
5902         if (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT) {
5903             if (!enabled_features.fragment_density_map2_features.fragmentDensityMapDeferred) {
5904                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-03567",
5905                                  "vkCreateImageView(): If the fragmentDensityMapDeferred feature is not enabled, "
5906                                  "flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT");
5907             }
5908             if (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT) {
5909                 skip |=
5910                     LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-flags-03568",
5911                              "vkCreateImageView(): If flags contains VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT, "
5912                              "flags must not contain VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT");
5913             }
5914         }
5915         if (IsExtEnabled(device_extensions.vk_ext_fragment_density_map2)) {
5916             if ((image_flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) && (image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) &&
5917                 (layer_count > phys_dev_ext_props.fragment_density_map2_props.maxSubsampledArrayLayers)) {
5918                 skip |= LogError(pCreateInfo->image, "VUID-VkImageViewCreateInfo-image-03569",
5919                                  "vkCreateImageView(): If image was created with flags containing "
5920                                  "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT and usage containing VK_IMAGE_USAGE_SAMPLED_BIT "
5921                                  "subresourceRange.layerCount (%d) must: be less than or equal to maxSubsampledArrayLayers (%d)",
5922                                  layer_count, phys_dev_ext_props.fragment_density_map2_props.maxSubsampledArrayLayers);
5923             }
5924         }
5925 
5926         auto astc_decode_mode = LvlFindInChain<VkImageViewASTCDecodeModeEXT>(pCreateInfo->pNext);
5927         if (IsExtEnabled(device_extensions.vk_ext_astc_decode_mode) && (astc_decode_mode != nullptr)) {
5928             if ((enabled_features.astc_decode_features.decodeModeSharedExponent == VK_FALSE) &&
5929                 (astc_decode_mode->decodeMode == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) {
5930                 skip |= LogError(device, "VUID-VkImageViewASTCDecodeModeEXT-decodeMode-02231",
5931                                  "vkCreateImageView(): decodeModeSharedExponent is not enabled but "
5932                                  "VkImageViewASTCDecodeModeEXT::decodeMode is VK_FORMAT_E5B9G9R9_UFLOAT_PACK32.");
5933             }
5934         }
5935 
5936         if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
5937             // If swizzling is disabled, make sure it isn't used
5938             // NOTE: as of spec version 1.2.183, VUID 04465 states: "all elements of components _must_ be
5939             // VK_COMPONENT_SWIZZLE_IDENTITY."
5940             //       However, issue https://github.com/KhronosGroup/Vulkan-Portability/issues/27 points out that the identity can
5941             //       also be defined via R, G, B, A enums in the correct order.
5942             //       Spec change is at https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/4600
5943             if ((VK_FALSE == enabled_features.portability_subset_features.imageViewFormatSwizzle) &&
5944                 !IsIdentitySwizzle(pCreateInfo->components)) {
5945                 skip |= LogError(device, "VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465",
5946                                  "vkCreateImageView (portability error): swizzle is disabled for this device.");
5947             }
5948 
5949             // Ensure ImageView's format has the same number of bits and components as Image's format if format reinterpretation is
5950             // disabled
5951             // TODO (ncesario): This is not correct for some cases (e.g., VK_FORMAT_B10G11R11_UFLOAT_PACK32 and
5952             // VK_FORMAT_E5B9G9R9_UFLOAT_PACK32), but requires additional information that should probably be generated from the
5953             // spec. See Github issue #2361.
5954             if ((VK_FALSE == enabled_features.portability_subset_features.imageViewFormatReinterpretation) &&
5955                 ((FormatElementSize(pCreateInfo->format, VK_IMAGE_ASPECT_COLOR_BIT) !=
5956                   FormatElementSize(image_state->createInfo.format, VK_IMAGE_ASPECT_COLOR_BIT)) ||
5957                  (FormatComponentCount(pCreateInfo->format) != FormatComponentCount(image_state->createInfo.format)))) {
5958                 skip |= LogError(device, "VUID-VkImageViewCreateInfo-imageViewFormatReinterpretation-04466",
5959                                  "vkCreateImageView (portability error): ImageView format must have"
5960                                  " the same number of components and bits per component as the Image's format");
5961             }
5962         }
5963 
5964         auto image_view_min_lod = LvlFindInChain<VkImageViewMinLodCreateInfoEXT>(pCreateInfo->pNext);
5965         if (image_view_min_lod) {
5966             if ((!enabled_features.image_view_min_lod_features.minLod) && (image_view_min_lod->minLod != 0)) {
5967                 skip |= LogError(device, "VUID-VkImageViewMinLodCreateInfoEXT-minLod-06455",
5968                                  "vkCreateImageView(): VkImageViewMinLodCreateInfoEXT::minLod = %f, but the minLod feature is not "
5969                                  "enabled.  If the minLod feature is not enabled, minLod must be 0.0",
5970                                  image_view_min_lod->minLod);
5971             }
5972             auto max_level = (pCreateInfo->subresourceRange.baseMipLevel + (pCreateInfo->subresourceRange.levelCount - 1));
5973             if (image_view_min_lod->minLod > max_level) {
5974                 skip |= LogError(device, "VUID-VkImageViewMinLodCreateInfoEXT-minLod-06456",
5975                                  "vkCreateImageView(): minLod (%f) must be less or equal to the index of the last mipmap level "
5976                                  "accessible to the view (%" PRIu32 ")",
5977                                  image_view_min_lod->minLod, max_level);
5978             }
5979         }
5980     }
5981     return skip;
5982 }
5983 
5984 template <typename RegionType>
ValidateCmdCopyBufferBounds(const BUFFER_STATE * src_buffer_state,const BUFFER_STATE * dst_buffer_state,uint32_t regionCount,const RegionType * pRegions,CopyCommandVersion version) const5985 bool CoreChecks::ValidateCmdCopyBufferBounds(const BUFFER_STATE *src_buffer_state, const BUFFER_STATE *dst_buffer_state,
5986                                              uint32_t regionCount, const RegionType *pRegions, CopyCommandVersion version) const {
5987     bool skip = false;
5988     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
5989     const char *func_name = is_2khr ? "vkCmdCopyBuffer2KHR()" : "vkCmdCopyBuffer()";
5990     const char *vuid;
5991 
5992     VkDeviceSize src_buffer_size = src_buffer_state->createInfo.size;
5993     VkDeviceSize dst_buffer_size = dst_buffer_state->createInfo.size;
5994     VkDeviceSize src_min = UINT64_MAX;
5995     VkDeviceSize src_max = 0;
5996     VkDeviceSize dst_min = UINT64_MAX;
5997     VkDeviceSize dst_max = 0;
5998 
5999     for (uint32_t i = 0; i < regionCount; i++) {
6000         src_min = std::min(src_min, pRegions[i].srcOffset);
6001         src_max = std::max(src_max, (pRegions[i].srcOffset + pRegions[i].size));
6002         dst_min = std::min(dst_min, pRegions[i].dstOffset);
6003         dst_max = std::max(dst_max, (pRegions[i].dstOffset + pRegions[i].size));
6004 
6005         // The srcOffset member of each element of pRegions must be less than the size of srcBuffer
6006         if (pRegions[i].srcOffset >= src_buffer_size) {
6007             vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-srcOffset-00113" : "VUID-vkCmdCopyBuffer-srcOffset-00113";
6008             skip |= LogError(src_buffer_state->buffer(), vuid,
6009                              "%s: pRegions[%" PRIu32 "].srcOffset (%" PRIuLEAST64
6010                              ") is greater than size of srcBuffer (%" PRIuLEAST64 ").",
6011                              func_name, i, pRegions[i].srcOffset, src_buffer_size);
6012         }
6013 
6014         // The dstOffset member of each element of pRegions must be less than the size of dstBuffer
6015         if (pRegions[i].dstOffset >= dst_buffer_size) {
6016             vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-dstOffset-00114" : "VUID-vkCmdCopyBuffer-dstOffset-00114";
6017             skip |= LogError(dst_buffer_state->buffer(), vuid,
6018                              "%s: pRegions[%" PRIu32 "].dstOffset (%" PRIuLEAST64
6019                              ") is greater than size of dstBuffer (%" PRIuLEAST64 ").",
6020                              func_name, i, pRegions[i].dstOffset, dst_buffer_size);
6021         }
6022 
6023         // The size member of each element of pRegions must be less than or equal to the size of srcBuffer minus srcOffset
6024         if (pRegions[i].size > (src_buffer_size - pRegions[i].srcOffset)) {
6025             vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-size-00115" : "VUID-vkCmdCopyBuffer-size-00115";
6026             skip |= LogError(src_buffer_state->buffer(), vuid,
6027                              "%s: pRegions[%d].size (%" PRIuLEAST64 ") is greater than the source buffer size (%" PRIuLEAST64
6028                              ") minus pRegions[%d].srcOffset (%" PRIuLEAST64 ").",
6029                              func_name, i, pRegions[i].size, src_buffer_size, i, pRegions[i].srcOffset);
6030         }
6031 
6032         // The size member of each element of pRegions must be less than or equal to the size of dstBuffer minus dstOffset
6033         if (pRegions[i].size > (dst_buffer_size - pRegions[i].dstOffset)) {
6034             vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-size-00116" : "VUID-vkCmdCopyBuffer-size-00116";
6035             skip |= LogError(dst_buffer_state->buffer(), vuid,
6036                              "%s: pRegions[%d].size (%" PRIuLEAST64 ") is greater than the destination buffer size (%" PRIuLEAST64
6037                              ") minus pRegions[%d].dstOffset (%" PRIuLEAST64 ").",
6038                              func_name, i, pRegions[i].size, dst_buffer_size, i, pRegions[i].dstOffset);
6039         }
6040     }
6041 
6042     // The union of the source regions, and the union of the destination regions, must not overlap in memory
6043     if (src_buffer_state->buffer() == dst_buffer_state->buffer()) {
6044         if (((src_min > dst_min) && (src_min < dst_max)) || ((src_max > dst_min) && (src_max < dst_max))) {
6045             vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-pRegions-00117" : "VUID-vkCmdCopyBuffer-pRegions-00117";
6046             skip |= LogError(src_buffer_state->buffer(), vuid, "%s: Detected overlap between source and dest regions in memory.",
6047                              func_name);
6048         }
6049     }
6050 
6051     return skip;
6052 }
6053 template <typename RegionType>
ValidateCmdCopyBuffer(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkBuffer dstBuffer,uint32_t regionCount,const RegionType * pRegions,CopyCommandVersion version) const6054 bool CoreChecks::ValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount,
6055                                        const RegionType *pRegions, CopyCommandVersion version) const {
6056     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6057     const auto src_buffer_state = Get<BUFFER_STATE>(srcBuffer);
6058     const auto dst_buffer_state = Get<BUFFER_STATE>(dstBuffer);
6059 
6060     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
6061     const CMD_TYPE cmd_type = is_2khr ? CMD_COPYBUFFER2KHR : CMD_COPYBUFFER;
6062     const char *func_name = CommandTypeString(cmd_type);
6063     const char *vuid;
6064 
6065     bool skip = false;
6066     vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-srcBuffer-00119" : "VUID-vkCmdCopyBuffer-srcBuffer-00119";
6067     skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state.get(), func_name, vuid);
6068     vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-dstBuffer-00121" : "VUID-vkCmdCopyBuffer-dstBuffer-00121";
6069     skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state.get(), func_name, vuid);
6070 
6071     // Validate that SRC & DST buffers have correct usage flags set
6072     vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-srcBuffer-00118" : "VUID-vkCmdCopyBuffer-srcBuffer-00118";
6073     skip |= ValidateBufferUsageFlags(src_buffer_state.get(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
6074                                      "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
6075     vuid = is_2khr ? "VUID-VkCopyBufferInfo2KHR-dstBuffer-00120" : "VUID-vkCmdCopyBuffer-dstBuffer-00120";
6076     skip |= ValidateBufferUsageFlags(dst_buffer_state.get(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
6077                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
6078 
6079     skip |= ValidateCmd(cb_node.get(), cmd_type);
6080     skip |= ValidateCmdCopyBufferBounds(src_buffer_state.get(), dst_buffer_state.get(), regionCount, pRegions, version);
6081 
6082     vuid = is_2khr ? "VUID-vkCmdCopyBuffer2KHR-commandBuffer-01822" : "VUID-vkCmdCopyBuffer-commandBuffer-01822";
6083     skip |= ValidateProtectedBuffer(cb_node.get(), src_buffer_state.get(), func_name, vuid);
6084     vuid = is_2khr ? "VUID-vkCmdCopyBuffer2KHR-commandBuffer-01823" : "VUID-vkCmdCopyBuffer-commandBuffer-01823";
6085     skip |= ValidateProtectedBuffer(cb_node.get(), dst_buffer_state.get(), func_name, vuid);
6086     vuid = is_2khr ? "VUID-vkCmdCopyBuffer2KHR-commandBuffer-01824" : "VUID-vkCmdCopyBuffer-commandBuffer-01824";
6087     skip |= ValidateUnprotectedBuffer(cb_node.get(), dst_buffer_state.get(), func_name, vuid);
6088     return skip;
6089 }
6090 
PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferCopy * pRegions) const6091 bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
6092                                               uint32_t regionCount, const VkBufferCopy *pRegions) const {
6093     return ValidateCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions, COPY_COMMAND_VERSION_1);
6094 }
6095 
PreCallValidateCmdCopyBuffer2KHR(VkCommandBuffer commandBuffer,const VkCopyBufferInfo2KHR * pCopyBufferInfos) const6096 bool CoreChecks::PreCallValidateCmdCopyBuffer2KHR(VkCommandBuffer commandBuffer,
6097                                                   const VkCopyBufferInfo2KHR *pCopyBufferInfos) const {
6098     return ValidateCmdCopyBuffer(commandBuffer, pCopyBufferInfos->srcBuffer, pCopyBufferInfos->dstBuffer,
6099                                  pCopyBufferInfos->regionCount, pCopyBufferInfos->pRegions, COPY_COMMAND_VERSION_2);
6100 }
6101 
ValidateIdleBuffer(VkBuffer buffer) const6102 bool CoreChecks::ValidateIdleBuffer(VkBuffer buffer) const {
6103     bool skip = false;
6104     auto buffer_state = Get<BUFFER_STATE>(buffer);
6105     if (buffer_state) {
6106         if (buffer_state->InUse()) {
6107             skip |= LogError(buffer, "VUID-vkDestroyBuffer-buffer-00922", "Cannot free %s that is in use by a command buffer.",
6108                              report_data->FormatHandle(buffer).c_str());
6109         }
6110     }
6111     return skip;
6112 }
6113 
PreCallValidateDestroyImageView(VkDevice device,VkImageView imageView,const VkAllocationCallbacks * pAllocator) const6114 bool CoreChecks::PreCallValidateDestroyImageView(VkDevice device, VkImageView imageView,
6115                                                  const VkAllocationCallbacks *pAllocator) const {
6116     const auto image_view_state = Get<IMAGE_VIEW_STATE>(imageView);
6117 
6118     bool skip = false;
6119     if (image_view_state) {
6120         skip |= ValidateObjectNotInUse(image_view_state.get(), "vkDestroyImageView", "VUID-vkDestroyImageView-imageView-01026");
6121     }
6122     return skip;
6123 }
6124 
PreCallValidateDestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator) const6125 bool CoreChecks::PreCallValidateDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) const {
6126     return ValidateIdleBuffer(buffer);
6127 }
6128 
PreCallRecordDestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator)6129 void CoreChecks::PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
6130     const auto buffer_state = Get<BUFFER_STATE>(buffer);
6131     if (buffer_state) {
6132         auto itr = buffer_address_map_.find(buffer_state->deviceAddress);
6133         if (itr != buffer_address_map_.end()) {
6134             buffer_address_map_.erase(itr);
6135         }
6136     }
6137     StateTracker::PreCallRecordDestroyBuffer(device, buffer, pAllocator);
6138 }
6139 
PreCallValidateDestroyBufferView(VkDevice device,VkBufferView bufferView,const VkAllocationCallbacks * pAllocator) const6140 bool CoreChecks::PreCallValidateDestroyBufferView(VkDevice device, VkBufferView bufferView,
6141                                                   const VkAllocationCallbacks *pAllocator) const {
6142     auto buffer_view_state = Get<BUFFER_VIEW_STATE>(bufferView);
6143     bool skip = false;
6144     if (buffer_view_state) {
6145         skip |= ValidateObjectNotInUse(buffer_view_state.get(), "vkDestroyBufferView", "VUID-vkDestroyBufferView-bufferView-00936");
6146     }
6147     return skip;
6148 }
6149 
PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer,VkBuffer dstBuffer,VkDeviceSize dstOffset,VkDeviceSize size,uint32_t data) const6150 bool CoreChecks::PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
6151                                               VkDeviceSize size, uint32_t data) const {
6152     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6153     auto buffer_state = Get<BUFFER_STATE>(dstBuffer);
6154     bool skip = false;
6155     skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-dstBuffer-00031");
6156     skip |= ValidateCmd(cb_node.get(), CMD_FILLBUFFER);
6157     // Validate that DST buffer has correct usage flags set
6158     skip |=
6159         ValidateBufferUsageFlags(buffer_state.get(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdFillBuffer-dstBuffer-00029",
6160                                  "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
6161 
6162     skip |=
6163         ValidateProtectedBuffer(cb_node.get(), buffer_state.get(), "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-commandBuffer-01811");
6164     skip |= ValidateUnprotectedBuffer(cb_node.get(), buffer_state.get(), "vkCmdFillBuffer()",
6165                                       "VUID-vkCmdFillBuffer-commandBuffer-01812");
6166 
6167     if (dstOffset >= buffer_state->createInfo.size) {
6168         skip |= LogError(dstBuffer, "VUID-vkCmdFillBuffer-dstOffset-00024",
6169                          "vkCmdFillBuffer(): dstOffset (0x%" PRIxLEAST64
6170                          ") is not less than destination buffer (%s) size (0x%" PRIxLEAST64 ").",
6171                          dstOffset, report_data->FormatHandle(dstBuffer).c_str(), buffer_state->createInfo.size);
6172     }
6173 
6174     if ((size != VK_WHOLE_SIZE) && (size > (buffer_state->createInfo.size - dstOffset))) {
6175         skip |= LogError(dstBuffer, "VUID-vkCmdFillBuffer-size-00027",
6176                          "vkCmdFillBuffer(): size (0x%" PRIxLEAST64 ") is greater than dstBuffer (%s) size (0x%" PRIxLEAST64
6177                          ") minus dstOffset (0x%" PRIxLEAST64 ").",
6178                          size, report_data->FormatHandle(dstBuffer).c_str(), buffer_state->createInfo.size, dstOffset);
6179     }
6180 
6181     if (!IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
6182         skip |= ValidateCmdQueueFlags(cb_node.get(), "vkCmdFillBuffer()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
6183                                       "VUID-vkCmdFillBuffer-commandBuffer-00030");
6184     }
6185 
6186     return skip;
6187 }
6188 
6189 template <typename BufferImageCopyRegionType>
ValidateBufferImageCopyData(const CMD_BUFFER_STATE * cb_node,uint32_t regionCount,const BufferImageCopyRegionType * pRegions,const IMAGE_STATE * image_state,const char * function,CopyCommandVersion version,bool image_to_buffer) const6190 bool CoreChecks::ValidateBufferImageCopyData(const CMD_BUFFER_STATE *cb_node, uint32_t regionCount,
6191                                              const BufferImageCopyRegionType *pRegions, const IMAGE_STATE *image_state,
6192                                              const char *function, CopyCommandVersion version, bool image_to_buffer) const {
6193     bool skip = false;
6194     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
6195     const char *vuid;
6196 
6197     assert(image_state != nullptr);
6198     const VkFormat image_format = image_state->createInfo.format;
6199 
6200     for (uint32_t i = 0; i < regionCount; i++) {
6201         const VkImageAspectFlags region_aspect_mask = pRegions[i].imageSubresource.aspectMask;
6202         if (image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
6203             if ((pRegions[i].imageOffset.y != 0) || (pRegions[i].imageExtent.height != 1)) {
6204                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00199", image_to_buffer, is_2khr),
6205                                  "%s: pRegion[%d] imageOffset.y is %d and imageExtent.height is %d. For 1D images these must be 0 "
6206                                  "and 1, respectively.",
6207                                  function, i, pRegions[i].imageOffset.y, pRegions[i].imageExtent.height);
6208             }
6209         }
6210 
6211         if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) || (image_state->createInfo.imageType == VK_IMAGE_TYPE_2D)) {
6212             if ((pRegions[i].imageOffset.z != 0) || (pRegions[i].imageExtent.depth != 1)) {
6213                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00201", image_to_buffer, is_2khr),
6214                                  "%s: pRegion[%d] imageOffset.z is %d and imageExtent.depth is %d. For 1D and 2D images these "
6215                                  "must be 0 and 1, respectively.",
6216                                  function, i, pRegions[i].imageOffset.z, pRegions[i].imageExtent.depth);
6217             }
6218         }
6219 
6220         if (image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
6221             if ((0 != pRegions[i].imageSubresource.baseArrayLayer) || (1 != pRegions[i].imageSubresource.layerCount)) {
6222                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00213", image_to_buffer, is_2khr),
6223                                  "%s: pRegion[%d] imageSubresource.baseArrayLayer is %d and imageSubresource.layerCount is %d. "
6224                                  "For 3D images these must be 0 and 1, respectively.",
6225                                  function, i, pRegions[i].imageSubresource.baseArrayLayer, pRegions[i].imageSubresource.layerCount);
6226             }
6227         }
6228 
6229         // If the the calling command's VkImage parameter's format is not a depth/stencil format,
6230         // then bufferOffset must be a multiple of the calling command's VkImage parameter's element size
6231         const uint32_t element_size =
6232             FormatIsDepthOrStencil(image_format) ? 0 : FormatElementSize(image_format, region_aspect_mask);
6233         const VkDeviceSize bufferOffset = pRegions[i].bufferOffset;
6234 
6235         if (FormatIsDepthOrStencil(image_format)) {
6236             if (SafeModulo(bufferOffset, 4) != 0) {
6237                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("04053", image_to_buffer, is_2khr),
6238                                  "%s: pRegion[%d] bufferOffset 0x%" PRIxLEAST64
6239                                  " must be a multiple 4 if using a depth/stencil format (%s).",
6240                                  function, i, bufferOffset, string_VkFormat(image_format));
6241             }
6242         } else {
6243             // If not depth/stencil and not multi-plane
6244             if (!FormatIsMultiplane(image_format) && (SafeModulo(bufferOffset, element_size) != 0)) {
6245                 vuid = IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)
6246                            ? GetBufferImageCopyCommandVUID("01558", image_to_buffer, is_2khr)
6247                            : GetBufferImageCopyCommandVUID("00193", image_to_buffer, is_2khr);
6248                 skip |= LogError(image_state->image(), vuid,
6249                                  "%s: pRegion[%d] bufferOffset 0x%" PRIxLEAST64
6250                                  " must be a multiple of this format's texel size (%" PRIu32 ").",
6251                                  function, i, bufferOffset, element_size);
6252             }
6253         }
6254 
6255         //  BufferRowLength must be 0, or greater than or equal to the width member of imageExtent
6256         if ((pRegions[i].bufferRowLength != 0) && (pRegions[i].bufferRowLength < pRegions[i].imageExtent.width)) {
6257             vuid = (is_2khr) ? "VUID-VkBufferImageCopy2KHR-bufferRowLength-00195" : "VUID-VkBufferImageCopy-bufferRowLength-00195";
6258             skip |=
6259                 LogError(image_state->image(), vuid,
6260                          "%s: pRegion[%d] bufferRowLength (%d) must be zero or greater-than-or-equal-to imageExtent.width (%d).",
6261                          function, i, pRegions[i].bufferRowLength, pRegions[i].imageExtent.width);
6262         }
6263 
6264         //  BufferImageHeight must be 0, or greater than or equal to the height member of imageExtent
6265         if ((pRegions[i].bufferImageHeight != 0) && (pRegions[i].bufferImageHeight < pRegions[i].imageExtent.height)) {
6266             vuid =
6267                 (is_2khr) ? "VUID-VkBufferImageCopy2KHR-bufferImageHeight-00196" : "VUID-VkBufferImageCopy-bufferImageHeight-00196";
6268             skip |=
6269                 LogError(image_state->image(), vuid,
6270                          "%s: pRegion[%d] bufferImageHeight (%d) must be zero or greater-than-or-equal-to imageExtent.height (%d).",
6271                          function, i, pRegions[i].bufferImageHeight, pRegions[i].imageExtent.height);
6272         }
6273 
6274         // Calculate adjusted image extent, accounting for multiplane image factors
6275         VkExtent3D adjusted_image_extent = image_state->GetSubresourceExtent(pRegions[i].imageSubresource);
6276         // imageOffset.x and (imageExtent.width + imageOffset.x) must both be >= 0 and <= image subresource width
6277         if ((pRegions[i].imageOffset.x < 0) || (pRegions[i].imageOffset.x > static_cast<int32_t>(adjusted_image_extent.width)) ||
6278             ((pRegions[i].imageOffset.x + static_cast<int32_t>(pRegions[i].imageExtent.width)) >
6279              static_cast<int32_t>(adjusted_image_extent.width))) {
6280             skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00197", image_to_buffer, is_2khr),
6281                              "%s: Both pRegion[%d] imageoffset.x (%d) and (imageExtent.width + imageOffset.x) (%d) must be >= "
6282                              "zero or <= image subresource width (%d).",
6283                              function, i, pRegions[i].imageOffset.x, (pRegions[i].imageOffset.x + pRegions[i].imageExtent.width),
6284                              adjusted_image_extent.width);
6285         }
6286 
6287         // imageOffset.y and (imageExtent.height + imageOffset.y) must both be >= 0 and <= image subresource height
6288         if ((pRegions[i].imageOffset.y < 0) || (pRegions[i].imageOffset.y > static_cast<int32_t>(adjusted_image_extent.height)) ||
6289             ((pRegions[i].imageOffset.y + static_cast<int32_t>(pRegions[i].imageExtent.height)) >
6290              static_cast<int32_t>(adjusted_image_extent.height))) {
6291             skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00198", image_to_buffer, is_2khr),
6292                              "%s: Both pRegion[%d] imageoffset.y (%d) and (imageExtent.height + imageOffset.y) (%d) must be >= "
6293                              "zero or <= image subresource height (%d).",
6294                              function, i, pRegions[i].imageOffset.y, (pRegions[i].imageOffset.y + pRegions[i].imageExtent.height),
6295                              adjusted_image_extent.height);
6296         }
6297 
6298         // imageOffset.z and (imageExtent.depth + imageOffset.z) must both be >= 0 and <= image subresource depth
6299         if ((pRegions[i].imageOffset.z < 0) || (pRegions[i].imageOffset.z > static_cast<int32_t>(adjusted_image_extent.depth)) ||
6300             ((pRegions[i].imageOffset.z + static_cast<int32_t>(pRegions[i].imageExtent.depth)) >
6301              static_cast<int32_t>(adjusted_image_extent.depth))) {
6302             skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00200", image_to_buffer, is_2khr),
6303                              "%s: Both pRegion[%d] imageoffset.z (%d) and (imageExtent.depth + imageOffset.z) (%d) must be >= "
6304                              "zero or <= image subresource depth (%d).",
6305                              function, i, pRegions[i].imageOffset.z, (pRegions[i].imageOffset.z + pRegions[i].imageExtent.depth),
6306                              adjusted_image_extent.depth);
6307         }
6308 
6309         // subresource aspectMask must have exactly 1 bit set
6310         const int num_bits = sizeof(VkFlags) * CHAR_BIT;
6311         std::bitset<num_bits> aspect_mask_bits(region_aspect_mask);
6312         if (aspect_mask_bits.count() != 1) {
6313             vuid = (is_2khr) ? "VUID-VkBufferImageCopy2KHR-aspectMask-00212" : "VUID-VkBufferImageCopy-aspectMask-00212";
6314             skip |= LogError(image_state->image(), vuid,
6315                              "%s: aspectMasks for imageSubresource in pRegion[%d] must have only a single bit set.", function, i);
6316         }
6317 
6318         // image subresource aspect bit must match format
6319         if (!VerifyAspectsPresent(region_aspect_mask, image_format)) {
6320             skip |=
6321                 LogError(image_state->image(), GetBufferImageCopyCommandVUID("00211", image_to_buffer, is_2khr),
6322                          "%s: pRegion[%d] subresource aspectMask 0x%x specifies aspects that are not present in image format 0x%x.",
6323                          function, i, region_aspect_mask, image_format);
6324         }
6325 
6326         // Checks that apply only to compressed images
6327         if (FormatIsBlockedImage(image_format)) {
6328             auto block_size = FormatTexelBlockExtent(image_format);
6329 
6330             //  BufferRowLength must be a multiple of block width
6331             if (SafeModulo(pRegions[i].bufferRowLength, block_size.width) != 0) {
6332                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00203", image_to_buffer, is_2khr),
6333                                  "%s: pRegion[%d] bufferRowLength (%d) must be a multiple of the blocked image's texel width (%d).",
6334                                  function, i, pRegions[i].bufferRowLength, block_size.width);
6335             }
6336 
6337             //  BufferRowHeight must be a multiple of block height
6338             if (SafeModulo(pRegions[i].bufferImageHeight, block_size.height) != 0) {
6339                 skip |=
6340                     LogError(image_state->image(), GetBufferImageCopyCommandVUID("00204", image_to_buffer, is_2khr),
6341                              "%s: pRegion[%d] bufferImageHeight (%d) must be a multiple of the blocked image's texel height (%d).",
6342                              function, i, pRegions[i].bufferImageHeight, block_size.height);
6343             }
6344 
6345             //  image offsets must be multiples of block dimensions
6346             if ((SafeModulo(pRegions[i].imageOffset.x, block_size.width) != 0) ||
6347                 (SafeModulo(pRegions[i].imageOffset.y, block_size.height) != 0) ||
6348                 (SafeModulo(pRegions[i].imageOffset.z, block_size.depth) != 0)) {
6349                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00205", image_to_buffer, is_2khr),
6350                                  "%s: pRegion[%d] imageOffset(x,y) (%d, %d) must be multiples of the blocked image's texel "
6351                                  "width & height (%d, %d).",
6352                                  function, i, pRegions[i].imageOffset.x, pRegions[i].imageOffset.y, block_size.width,
6353                                  block_size.height);
6354             }
6355 
6356             // bufferOffset must be a multiple of block size (linear bytes)
6357             if (SafeModulo(bufferOffset, element_size) != 0) {
6358                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00206", image_to_buffer, is_2khr),
6359                                  "%s: pRegion[%d] bufferOffset (0x%" PRIxLEAST64
6360                                  ") must be a multiple of the blocked image's texel block size (%" PRIu32 ").",
6361                                  function, i, bufferOffset, element_size);
6362             }
6363 
6364             // imageExtent width must be a multiple of block width, or extent+offset width must equal subresource width
6365             VkExtent3D mip_extent = image_state->GetSubresourceExtent(pRegions[i].imageSubresource);
6366             if ((SafeModulo(pRegions[i].imageExtent.width, block_size.width) != 0) &&
6367                 (pRegions[i].imageExtent.width + pRegions[i].imageOffset.x != mip_extent.width)) {
6368                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00207", image_to_buffer, is_2khr),
6369                                  "%s: pRegion[%d] extent width (%d) must be a multiple of the blocked texture block width "
6370                                  "(%d), or when added to offset.x (%d) must equal the image subresource width (%d).",
6371                                  function, i, pRegions[i].imageExtent.width, block_size.width, pRegions[i].imageOffset.x,
6372                                  mip_extent.width);
6373             }
6374 
6375             // imageExtent height must be a multiple of block height, or extent+offset height must equal subresource height
6376             if ((SafeModulo(pRegions[i].imageExtent.height, block_size.height) != 0) &&
6377                 (pRegions[i].imageExtent.height + pRegions[i].imageOffset.y != mip_extent.height)) {
6378                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00208", image_to_buffer, is_2khr),
6379                                  "%s: pRegion[%d] extent height (%d) must be a multiple of the blocked texture block height "
6380                                  "(%d), or when added to offset.y (%d) must equal the image subresource height (%d).",
6381                                  function, i, pRegions[i].imageExtent.height, block_size.height, pRegions[i].imageOffset.y,
6382                                  mip_extent.height);
6383             }
6384 
6385             // imageExtent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
6386             if ((SafeModulo(pRegions[i].imageExtent.depth, block_size.depth) != 0) &&
6387                 (pRegions[i].imageExtent.depth + pRegions[i].imageOffset.z != mip_extent.depth)) {
6388                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("00209", image_to_buffer, is_2khr),
6389                                  "%s: pRegion[%d] extent width (%d) must be a multiple of the blocked texture block depth "
6390                                  "(%d), or when added to offset.z (%d) must equal the image subresource depth (%d).",
6391                                  function, i, pRegions[i].imageExtent.depth, block_size.depth, pRegions[i].imageOffset.z,
6392                                  mip_extent.depth);
6393             }
6394         }
6395 
6396         // Checks that apply only to multi-planar format images
6397         if (FormatIsMultiplane(image_format)) {
6398             // VK_IMAGE_ASPECT_PLANE_2_BIT valid only for image formats with three planes
6399             if ((FormatPlaneCount(image_format) < 3) && (region_aspect_mask == VK_IMAGE_ASPECT_PLANE_2_BIT)) {
6400                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("01560", image_to_buffer, is_2khr),
6401                                  "%s: pRegion[%d] subresource aspectMask cannot be VK_IMAGE_ASPECT_PLANE_2_BIT unless image "
6402                                  "format has three planes.",
6403                                  function, i);
6404             }
6405 
6406             // image subresource aspectMask must be VK_IMAGE_ASPECT_PLANE_*_BIT
6407             if (0 ==
6408                 (region_aspect_mask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT))) {
6409                 skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("01560", image_to_buffer, is_2khr),
6410                                  "%s: pRegion[%d] subresource aspectMask for multi-plane image formats must have a "
6411                                  "VK_IMAGE_ASPECT_PLANE_*_BIT when copying to or from.",
6412                                  function, i);
6413             } else {
6414                 // Know aspect mask is valid
6415                 const VkFormat compatible_format = FindMultiplaneCompatibleFormat(image_format, region_aspect_mask);
6416                 const uint32_t compatible_size = FormatElementSize(compatible_format);
6417                 if (SafeModulo(bufferOffset, compatible_size) != 0) {
6418                     skip |= LogError(
6419                         image_state->image(), GetBufferImageCopyCommandVUID("01559", image_to_buffer, is_2khr),
6420                         "%s: pRegion[%d]->bufferOffset is 0x%" PRIxLEAST64
6421                         " but must be a multiple of the multi-plane compatible format's texel size (%u) for plane %u (%s).",
6422                         function, i, bufferOffset, element_size, GetPlaneIndex(region_aspect_mask),
6423                         string_VkFormat(compatible_format));
6424                 }
6425             }
6426         }
6427 
6428         // TODO - Don't use ValidateCmdQueueFlags due to currently not having way to add more descriptive message
6429         const COMMAND_POOL_STATE *command_pool = cb_node->command_pool;
6430         assert(command_pool != nullptr);
6431         const uint32_t queue_family_index = command_pool->queueFamilyIndex;
6432         const VkQueueFlags queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
6433         if (((queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) == 0) && (SafeModulo(bufferOffset, 4) != 0)) {
6434             LogObjectList objlist(cb_node->commandBuffer());
6435             objlist.add(command_pool->commandPool());
6436             skip |= LogError(image_state->image(), GetBufferImageCopyCommandVUID("04052", image_to_buffer, is_2khr),
6437                              "%s: pRegion[%d] bufferOffset 0x%" PRIxLEAST64
6438                              " must be a multiple 4 because the command buffer %s was allocated from the command pool %s "
6439                              "which was created with queueFamilyIndex %u, which doesn't contain the VK_QUEUE_GRAPHICS_BIT or "
6440                              "VK_QUEUE_COMPUTE_BIT flag.",
6441                              function, i, bufferOffset, report_data->FormatHandle(cb_node->commandBuffer()).c_str(),
6442                              report_data->FormatHandle(command_pool->commandPool()).c_str(), queue_family_index);
6443         }
6444     }
6445 
6446     return skip;
6447 }
6448 
6449 template <typename BufferImageCopyRegionType>
ValidateImageBounds(const IMAGE_STATE * image_state,const uint32_t regionCount,const BufferImageCopyRegionType * pRegions,const char * func_name,const char * msg_code) const6450 bool CoreChecks::ValidateImageBounds(const IMAGE_STATE *image_state, const uint32_t regionCount,
6451                                      const BufferImageCopyRegionType *pRegions, const char *func_name, const char *msg_code) const {
6452     bool skip = false;
6453     const VkImageCreateInfo *image_info = &(image_state->createInfo);
6454 
6455     for (uint32_t i = 0; i < regionCount; i++) {
6456         VkExtent3D extent = pRegions[i].imageExtent;
6457         VkOffset3D offset = pRegions[i].imageOffset;
6458 
6459         if (IsExtentSizeZero(&extent))  // Warn on zero area subresource
6460         {
6461             skip |= LogWarning(image_state->image(), kVUID_Core_Image_ZeroAreaSubregion,
6462                                "%s: pRegion[%d] imageExtent of {%1d, %1d, %1d} has zero area", func_name, i, extent.width,
6463                                extent.height, extent.depth);
6464         }
6465 
6466         VkExtent3D image_extent = image_state->GetSubresourceExtent(pRegions[i].imageSubresource);
6467 
6468         // If we're using a blocked image format, valid extent is rounded up to multiple of block size (per
6469         // vkspec.html#_common_operation)
6470         if (FormatIsBlockedImage(image_info->format)) {
6471             auto block_extent = FormatTexelBlockExtent(image_info->format);
6472             if (image_extent.width % block_extent.width) {
6473                 image_extent.width += (block_extent.width - (image_extent.width % block_extent.width));
6474             }
6475             if (image_extent.height % block_extent.height) {
6476                 image_extent.height += (block_extent.height - (image_extent.height % block_extent.height));
6477             }
6478             if (image_extent.depth % block_extent.depth) {
6479                 image_extent.depth += (block_extent.depth - (image_extent.depth % block_extent.depth));
6480             }
6481         }
6482 
6483         if (0 != ExceedsBounds(&offset, &extent, &image_extent)) {
6484             skip |= LogError(image_state->image(), msg_code, "%s: pRegion[%d] exceeds image bounds.", func_name, i);
6485         }
6486     }
6487 
6488     return skip;
6489 }
6490 
6491 template <typename BufferImageCopyRegionType>
ValidateBufferBounds(const IMAGE_STATE * image_state,const BUFFER_STATE * buff_state,uint32_t regionCount,const BufferImageCopyRegionType * pRegions,const char * func_name,const char * msg_code) const6492 bool CoreChecks::ValidateBufferBounds(const IMAGE_STATE *image_state, const BUFFER_STATE *buff_state, uint32_t regionCount,
6493                                       const BufferImageCopyRegionType *pRegions, const char *func_name,
6494                                       const char *msg_code) const {
6495     bool skip = false;
6496 
6497     const VkDeviceSize buffer_size = buff_state->createInfo.size;
6498 
6499     for (uint32_t i = 0; i < regionCount; i++) {
6500         const VkDeviceSize buffer_copy_size = GetBufferSizeFromCopyImage(pRegions[i], image_state->createInfo.format);
6501         // This blocks against invalid VkBufferCopyImage that already have been caught elsewhere
6502         if (buffer_copy_size != 0) {
6503             const VkDeviceSize max_buffer_copy = buffer_copy_size + pRegions[i].bufferOffset;
6504             if (buffer_size < max_buffer_copy) {
6505                 skip |= LogError(device, msg_code,
6506                                  "%s: pRegion[%" PRIu32 "] is trying to copy  %" PRIu64 " bytes plus %" PRIu64
6507                                  " offset to/from the VkBuffer (%s) which exceeds the VkBuffer total size of %" PRIu64 " bytes.",
6508                                  func_name, i, buffer_copy_size, pRegions[i].bufferOffset,
6509                                  report_data->FormatHandle(buff_state->buffer()).c_str(), buffer_size);
6510             }
6511         }
6512     }
6513 
6514     return skip;
6515 }
6516 
6517 template <typename BufferImageCopyRegionType>
ValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkBuffer dstBuffer,uint32_t regionCount,const BufferImageCopyRegionType * pRegions,CopyCommandVersion version) const6518 bool CoreChecks::ValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6519                                               VkBuffer dstBuffer, uint32_t regionCount, const BufferImageCopyRegionType *pRegions,
6520                                               CopyCommandVersion version) const {
6521     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6522     const auto src_image_state = Get<IMAGE_STATE>(srcImage);
6523     const auto dst_buffer_state = Get<BUFFER_STATE>(dstBuffer);
6524 
6525     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
6526     const CMD_TYPE cmd_type = is_2khr ? CMD_COPYIMAGETOBUFFER2KHR : CMD_COPYIMAGETOBUFFER;
6527     const char *func_name = CommandTypeString(cmd_type);
6528     const char *vuid;
6529 
6530     bool skip = ValidateBufferImageCopyData(cb_node.get(), regionCount, pRegions, src_image_state.get(), func_name, version, true);
6531 
6532     // Validate command buffer state
6533     skip |= ValidateCmd(cb_node.get(), cmd_type);
6534 
6535     // Command pool must support graphics, compute, or transfer operations
6536     const auto pool = cb_node->command_pool;
6537 
6538     VkQueueFlags queue_flags = physical_device_state->queue_family_properties[pool->queueFamilyIndex].queueFlags;
6539 
6540     if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
6541         vuid =
6542             is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-cmdpool" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-cmdpool";
6543         skip |= LogError(cb_node->createInfo.commandPool, vuid,
6544                          "Cannot call %s on a command buffer allocated from a pool without graphics, compute, "
6545                          "or transfer capabilities.",
6546                          func_name);
6547     }
6548     vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-pRegions-00182" : "VUID-vkCmdCopyImageToBuffer-pRegions-06220";
6549     skip |= ValidateImageBounds(src_image_state.get(), regionCount, pRegions, func_name, vuid);
6550     vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-pRegions-00183" : "VUID-vkCmdCopyImageToBuffer-pRegions-00183";
6551     skip |= ValidateBufferBounds(src_image_state.get(), dst_buffer_state.get(), regionCount, pRegions, func_name, vuid);
6552 
6553     vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00188" : "VUID-vkCmdCopyImageToBuffer-srcImage-00188";
6554     const char *location = is_2khr ? "vkCmdCopyImageToBuffer2KHR(): srcImage" : "vkCmdCopyImageToBuffer(): srcImage";
6555     skip |= ValidateImageSampleCount(src_image_state.get(), VK_SAMPLE_COUNT_1_BIT, location, vuid);
6556 
6557     vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00187" : "VUID-vkCmdCopyImageToBuffer-srcImage-00187";
6558     skip |= ValidateMemoryIsBoundToImage(src_image_state.get(), func_name, vuid);
6559     vuid = is_2khr ? "vkCmdCopyImageToBuffer-dstBuffer2KHR-00192" : "vkCmdCopyImageToBuffer dstBuffer-00192";
6560     skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state.get(), func_name, vuid);
6561 
6562     // Validate that SRC image & DST buffer have correct usage flags set
6563     vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-00186" : "VUID-vkCmdCopyImageToBuffer-srcImage-00186";
6564     skip |= ValidateImageUsageFlags(src_image_state.get(), VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
6565                                     "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
6566     vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-dstBuffer-00191" : "VUID-vkCmdCopyImageToBuffer-dstBuffer-00191";
6567     skip |= ValidateBufferUsageFlags(dst_buffer_state.get(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
6568                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
6569     vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-01831" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-01831";
6570     skip |= ValidateProtectedImage(cb_node.get(), src_image_state.get(), func_name, vuid);
6571     vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-01832" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-01832";
6572     skip |= ValidateProtectedBuffer(cb_node.get(), dst_buffer_state.get(), func_name, vuid);
6573     vuid = is_2khr ? "VUID-vkCmdCopyImageToBuffer2KHR-commandBuffer-01833" : "VUID-vkCmdCopyImageToBuffer-commandBuffer-01833";
6574     skip |= ValidateUnprotectedBuffer(cb_node.get(), dst_buffer_state.get(), func_name, vuid);
6575 
6576     // Validation for VK_EXT_fragment_density_map
6577     if (src_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
6578         vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-02544" : "VUID-vkCmdCopyImageToBuffer-srcImage-02544";
6579         skip |= LogError(cb_node->commandBuffer(), vuid,
6580                          "%s: srcImage must not have been created with flags containing "
6581                          "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
6582                          func_name);
6583     }
6584 
6585     if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
6586         vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImage-01998" : "VUID-vkCmdCopyImageToBuffer-srcImage-01998";
6587         skip |= ValidateImageFormatFeatureFlags(src_image_state.get(), VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, func_name, vuid);
6588     }
6589     bool hit_error = false;
6590 
6591     const char *src_invalid_layout_vuid =
6592         (src_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
6593             ? (vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImageLayout-01397"
6594                               : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-01397")
6595             : (vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImageLayout-00190"
6596                               : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190");
6597 
6598     for (uint32_t i = 0; i < regionCount; ++i) {
6599         skip |= ValidateImageSubresourceLayers(cb_node.get(), &pRegions[i].imageSubresource, func_name, "imageSubresource", i);
6600         vuid =
6601             is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-srcImageLayout-00189" : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00189";
6602         skip |= VerifyImageLayout(cb_node.get(), src_image_state.get(), pRegions[i].imageSubresource, srcImageLayout,
6603                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, func_name, src_invalid_layout_vuid, vuid, &hit_error);
6604         vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-imageOffset-01794" : "VUID-vkCmdCopyImageToBuffer-imageOffset-01794";
6605         skip |= ValidateCopyBufferImageTransferGranularityRequirements(cb_node.get(), src_image_state.get(), &pRegions[i], i,
6606                                                                        func_name, vuid);
6607         vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-imageSubresource-01703"
6608                        : "VUID-vkCmdCopyImageToBuffer-imageSubresource-01703";
6609         skip |= ValidateImageMipLevel(cb_node.get(), src_image_state.get(), pRegions[i].imageSubresource.mipLevel, i, func_name,
6610                                       "imageSubresource", vuid);
6611         vuid = is_2khr ? "VUID-VkCopyImageToBufferInfo2KHR-imageSubresource-01704"
6612                        : "VUID-vkCmdCopyImageToBuffer-imageSubresource-01704";
6613         skip |= ValidateImageArrayLayerRange(cb_node.get(), src_image_state.get(), pRegions[i].imageSubresource.baseArrayLayer,
6614                                              pRegions[i].imageSubresource.layerCount, i, func_name, "imageSubresource", vuid);
6615     }
6616     return skip;
6617 }
6618 
PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferImageCopy * pRegions) const6619 bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6620                                                      VkBuffer dstBuffer, uint32_t regionCount,
6621                                                      const VkBufferImageCopy *pRegions) const {
6622     return ValidateCmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions,
6623                                         COPY_COMMAND_VERSION_1);
6624 }
6625 
PreCallValidateCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer,const VkCopyImageToBufferInfo2KHR * pCopyImageToBufferInfo) const6626 bool CoreChecks::PreCallValidateCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer,
6627                                                          const VkCopyImageToBufferInfo2KHR *pCopyImageToBufferInfo) const {
6628     return ValidateCmdCopyImageToBuffer(commandBuffer, pCopyImageToBufferInfo->srcImage, pCopyImageToBufferInfo->srcImageLayout,
6629                                         pCopyImageToBufferInfo->dstBuffer, pCopyImageToBufferInfo->regionCount,
6630                                         pCopyImageToBufferInfo->pRegions, COPY_COMMAND_VERSION_2);
6631 }
6632 
PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferImageCopy * pRegions)6633 void CoreChecks::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
6634                                                    VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
6635     StateTracker::PreCallRecordCmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
6636 
6637     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6638     auto src_image_state = Get<IMAGE_STATE>(srcImage);
6639     // Make sure that all image slices record referenced layout
6640     for (uint32_t i = 0; i < regionCount; ++i) {
6641         cb_node->SetImageInitialLayout(*src_image_state, pRegions[i].imageSubresource, srcImageLayout);
6642     }
6643 }
6644 
PreCallRecordCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer,const VkCopyImageToBufferInfo2KHR * pCopyImageToBufferInfo)6645 void CoreChecks::PreCallRecordCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer,
6646                                                        const VkCopyImageToBufferInfo2KHR *pCopyImageToBufferInfo) {
6647     StateTracker::PreCallRecordCmdCopyImageToBuffer2KHR(commandBuffer, pCopyImageToBufferInfo);
6648 
6649     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6650     auto src_image_state = Get<IMAGE_STATE>(pCopyImageToBufferInfo->srcImage);
6651     // Make sure that all image slices record referenced layout
6652     for (uint32_t i = 0; i < pCopyImageToBufferInfo->regionCount; ++i) {
6653         cb_node->SetImageInitialLayout(*src_image_state, pCopyImageToBufferInfo->pRegions[i].imageSubresource,
6654                                        pCopyImageToBufferInfo->srcImageLayout);
6655     }
6656 }
6657 
6658 template <typename RegionType>
ValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const RegionType * pRegions,CopyCommandVersion version) const6659 bool CoreChecks::ValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
6660                                               VkImageLayout dstImageLayout, uint32_t regionCount, const RegionType *pRegions,
6661                                               CopyCommandVersion version) const {
6662     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6663     const auto src_buffer_state = Get<BUFFER_STATE>(srcBuffer);
6664     const auto dst_image_state = Get<IMAGE_STATE>(dstImage);
6665 
6666     const bool is_2khr = (version == COPY_COMMAND_VERSION_2);
6667     const CMD_TYPE cmd_type = is_2khr ? CMD_COPYBUFFERTOIMAGE2KHR : CMD_COPYBUFFERTOIMAGE;
6668     const char *func_name = CommandTypeString(cmd_type);
6669     const char *vuid;
6670 
6671     bool skip = ValidateBufferImageCopyData(cb_node.get(), regionCount, pRegions, dst_image_state.get(), func_name, version, false);
6672 
6673     // Validate command buffer state
6674     skip |= ValidateCmd(cb_node.get(), cmd_type);
6675 
6676     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-pRegions-00172" : "VUID-vkCmdCopyBufferToImage-pRegions-06217";
6677     skip |= ValidateImageBounds(dst_image_state.get(), regionCount, pRegions, func_name, vuid);
6678     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-pRegions-00171" : "VUID-vkCmdCopyBufferToImage-pRegions-00171";
6679     skip |= ValidateBufferBounds(dst_image_state.get(), src_buffer_state.get(), regionCount, pRegions, func_name, vuid);
6680 
6681     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00179" : "VUID-vkCmdCopyBufferToImage-dstImage-00179";
6682     const char *location = is_2khr ? "vkCmdCopyBufferToImage2KHR(): dstImage" : "vkCmdCopyBufferToImage(): dstImage";
6683     skip |= ValidateImageSampleCount(dst_image_state.get(), VK_SAMPLE_COUNT_1_BIT, location, vuid);
6684     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-srcBuffer-00176" : "VUID-vkCmdCopyBufferToImage-srcBuffer-00176";
6685     skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state.get(), func_name, vuid);
6686     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00178" : "VUID-vkCmdCopyBufferToImage-dstImage-00178";
6687     skip |= ValidateMemoryIsBoundToImage(dst_image_state.get(), func_name, vuid);
6688     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-srcBuffer-00174" : "VUID-vkCmdCopyBufferToImage-srcBuffer-00174";
6689     skip |= ValidateBufferUsageFlags(src_buffer_state.get(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, vuid, func_name,
6690                                      "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
6691     vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00177" : "VUID-vkCmdCopyBufferToImage-dstImage-00177";
6692     skip |= ValidateImageUsageFlags(dst_image_state.get(), VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, vuid, func_name,
6693                                     "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
6694     vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage2KHR-commandBuffer-01828" : "VUID-vkCmdCopyBufferToImage-commandBuffer-01828";
6695     skip |= ValidateProtectedBuffer(cb_node.get(), src_buffer_state.get(), func_name, vuid);
6696     vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage2KHR-commandBuffer-01829" : "VUID-vkCmdCopyBufferToImage-commandBuffer-01829";
6697     skip |= ValidateProtectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
6698     vuid = is_2khr ? "VUID-vkCmdCopyBufferToImage-commandBuffer-01830" : "VUID-vkCmdCopyBufferToImage-commandBuffer-01830";
6699     skip |= ValidateUnprotectedImage(cb_node.get(), dst_image_state.get(), func_name, vuid);
6700 
6701     // Validation for VK_EXT_fragment_density_map
6702     if (dst_image_state->createInfo.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
6703         vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-02543" : "VUID-vkCmdCopyBufferToImage-dstImage-02543";
6704         skip |= LogError(cb_node->commandBuffer(), vuid,
6705                          "%s: dstImage must not have been created with flags containing "
6706                          "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT",
6707                          func_name);
6708     }
6709 
6710     if (IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
6711         vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImage-01997" : "VUID-vkCmdCopyBufferToImage-dstImage-01997";
6712         skip |= ValidateImageFormatFeatureFlags(dst_image_state.get(), VK_FORMAT_FEATURE_TRANSFER_DST_BIT, func_name, vuid);
6713     }
6714     bool hit_error = false;
6715 
6716     const char *dst_invalid_layout_vuid =
6717         (dst_image_state->shared_presentable && IsExtEnabled(device_extensions.vk_khr_shared_presentable_image))
6718             ? (is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImageLayout-01396"
6719                        : "VUID-vkCmdCopyBufferToImage-dstImageLayout-01396")
6720             : (is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImageLayout-00181"
6721                        : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00181");
6722 
6723     for (uint32_t i = 0; i < regionCount; ++i) {
6724         skip |= ValidateImageSubresourceLayers(cb_node.get(), &pRegions[i].imageSubresource, func_name, "imageSubresource", i);
6725         vuid =
6726             is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-dstImageLayout-00180" : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00180";
6727         skip |= VerifyImageLayout(cb_node.get(), dst_image_state.get(), pRegions[i].imageSubresource, dstImageLayout,
6728                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, func_name, dst_invalid_layout_vuid, vuid, &hit_error);
6729         vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-imageOffset-01793" : "VUID-vkCmdCopyBufferToImage-imageOffset-01793";
6730         skip |= ValidateCopyBufferImageTransferGranularityRequirements(cb_node.get(), dst_image_state.get(), &pRegions[i], i,
6731                                                                        func_name, vuid);
6732         vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-imageSubresource-01701"
6733                        : "VUID-vkCmdCopyBufferToImage-imageSubresource-01701";
6734         skip |= ValidateImageMipLevel(cb_node.get(), dst_image_state.get(), pRegions[i].imageSubresource.mipLevel, i, func_name,
6735                                       "imageSubresource", vuid);
6736         vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-imageSubresource-01702"
6737                        : "VUID-vkCmdCopyBufferToImage-imageSubresource-01702";
6738         skip |= ValidateImageArrayLayerRange(cb_node.get(), dst_image_state.get(), pRegions[i].imageSubresource.baseArrayLayer,
6739                                              pRegions[i].imageSubresource.layerCount, i, func_name, "imageSubresource", vuid);
6740 
6741         // TODO - Don't use ValidateCmdQueueFlags due to currently not having way to add more descriptive message
6742         const COMMAND_POOL_STATE *command_pool = cb_node->command_pool;
6743         assert(command_pool != nullptr);
6744         const uint32_t queue_family_index = command_pool->queueFamilyIndex;
6745         const VkQueueFlags queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
6746         const VkImageAspectFlags region_aspect_mask = pRegions[i].imageSubresource.aspectMask;
6747         if (((queue_flags & VK_QUEUE_GRAPHICS_BIT) == 0) &&
6748             ((region_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0)) {
6749             LogObjectList objlist(cb_node->commandBuffer());
6750             objlist.add(command_pool->commandPool());
6751             vuid = is_2khr ? "VUID-VkCopyBufferToImageInfo2KHR-commandBuffer-04477"
6752                            : "VUID-vkCmdCopyBufferToImage-commandBuffer-04477";
6753             skip |= LogError(dst_image_state->image(), vuid,
6754                              "%s(): pRegion[%d] subresource aspectMask 0x%x specifies VK_IMAGE_ASPECT_DEPTH_BIT or "
6755                              "VK_IMAGE_ASPECT_STENCIL_BIT but the command buffer %s was allocated from the command pool %s "
6756                              "which was created with queueFamilyIndex %u, which doesn't contain the VK_QUEUE_GRAPHICS_BIT flag.",
6757                              func_name, i, region_aspect_mask, report_data->FormatHandle(cb_node->commandBuffer()).c_str(),
6758                              report_data->FormatHandle(command_pool->commandPool()).c_str(), queue_family_index);
6759         }
6760     }
6761     return skip;
6762 }
6763 
PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkBufferImageCopy * pRegions) const6764 bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
6765                                                      VkImageLayout dstImageLayout, uint32_t regionCount,
6766                                                      const VkBufferImageCopy *pRegions) const {
6767     return ValidateCmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions,
6768                                         COPY_COMMAND_VERSION_1);
6769 }
6770 
PreCallValidateCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer,const VkCopyBufferToImageInfo2KHR * pCopyBufferToImageInfo) const6771 bool CoreChecks::PreCallValidateCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer,
6772                                                          const VkCopyBufferToImageInfo2KHR *pCopyBufferToImageInfo) const {
6773     return ValidateCmdCopyBufferToImage(commandBuffer, pCopyBufferToImageInfo->srcBuffer, pCopyBufferToImageInfo->dstImage,
6774                                         pCopyBufferToImageInfo->dstImageLayout, pCopyBufferToImageInfo->regionCount,
6775                                         pCopyBufferToImageInfo->pRegions, COPY_COMMAND_VERSION_2);
6776 }
6777 
PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkBufferImageCopy * pRegions)6778 void CoreChecks::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
6779                                                    VkImageLayout dstImageLayout, uint32_t regionCount,
6780                                                    const VkBufferImageCopy *pRegions) {
6781     StateTracker::PreCallRecordCmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
6782 
6783     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6784     auto dst_image_state = Get<IMAGE_STATE>(dstImage);
6785     // Make sure that all image slices are record referenced layout
6786     for (uint32_t i = 0; i < regionCount; ++i) {
6787         cb_node->SetImageInitialLayout(*dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
6788     }
6789 }
6790 
PreCallRecordCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer,const VkCopyBufferToImageInfo2KHR * pCopyBufferToImageInfo2KHR)6791 void CoreChecks::PreCallRecordCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer,
6792                                                        const VkCopyBufferToImageInfo2KHR *pCopyBufferToImageInfo2KHR) {
6793     StateTracker::PreCallRecordCmdCopyBufferToImage2KHR(commandBuffer, pCopyBufferToImageInfo2KHR);
6794 
6795     auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
6796     auto dst_image_state = Get<IMAGE_STATE>(pCopyBufferToImageInfo2KHR->dstImage);
6797     // Make sure that all image slices are record referenced layout
6798     for (uint32_t i = 0; i < pCopyBufferToImageInfo2KHR->regionCount; ++i) {
6799         cb_node->SetImageInitialLayout(*dst_image_state, pCopyBufferToImageInfo2KHR->pRegions[i].imageSubresource,
6800                                        pCopyBufferToImageInfo2KHR->dstImageLayout);
6801     }
6802 }
PreCallValidateGetImageSubresourceLayout(VkDevice device,VkImage image,const VkImageSubresource * pSubresource,VkSubresourceLayout * pLayout) const6803 bool CoreChecks::PreCallValidateGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
6804                                                           VkSubresourceLayout *pLayout) const {
6805     bool skip = false;
6806     const VkImageAspectFlags sub_aspect = pSubresource->aspectMask;
6807 
6808     // The aspectMask member of pSubresource must only have a single bit set
6809     const int num_bits = sizeof(sub_aspect) * CHAR_BIT;
6810     std::bitset<num_bits> aspect_mask_bits(sub_aspect);
6811     if (aspect_mask_bits.count() != 1) {
6812         skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-aspectMask-00997",
6813                          "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must have exactly 1 bit set.");
6814     }
6815 
6816     const auto image_entry = Get<IMAGE_STATE>(image);
6817     if (!image_entry) {
6818         return skip;
6819     }
6820 
6821     // Image must have been created with tiling equal to VK_IMAGE_TILING_LINEAR
6822     if (IsExtEnabled(device_extensions.vk_ext_image_drm_format_modifier)) {
6823         if ((image_entry->createInfo.tiling != VK_IMAGE_TILING_LINEAR) &&
6824             (image_entry->createInfo.tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)) {
6825             skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-image-02270",
6826                              "vkGetImageSubresourceLayout(): Image must have tiling of VK_IMAGE_TILING_LINEAR or "
6827                              "VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT.");
6828         }
6829     } else {
6830         if (image_entry->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
6831             skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-image-00996",
6832                              "vkGetImageSubresourceLayout(): Image must have tiling of VK_IMAGE_TILING_LINEAR.");
6833         }
6834     }
6835 
6836     // mipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created
6837     if (pSubresource->mipLevel >= image_entry->createInfo.mipLevels) {
6838         skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-mipLevel-01716",
6839                          "vkGetImageSubresourceLayout(): pSubresource.mipLevel (%d) must be less than %d.", pSubresource->mipLevel,
6840                          image_entry->createInfo.mipLevels);
6841     }
6842 
6843     // arrayLayer must be less than the arrayLayers specified in VkImageCreateInfo when the image was created
6844     if (pSubresource->arrayLayer >= image_entry->createInfo.arrayLayers) {
6845         skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-arrayLayer-01717",
6846                          "vkGetImageSubresourceLayout(): pSubresource.arrayLayer (%d) must be less than %d.",
6847                          pSubresource->arrayLayer, image_entry->createInfo.arrayLayers);
6848     }
6849 
6850     // subresource's aspect must be compatible with image's format.
6851     const VkFormat img_format = image_entry->createInfo.format;
6852     if (image_entry->createInfo.tiling == VK_IMAGE_TILING_LINEAR) {
6853         if (FormatIsMultiplane(img_format)) {
6854             VkImageAspectFlags allowed_flags = (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
6855             const char *vuid = "VUID-vkGetImageSubresourceLayout-format-01581";  // 2-plane version
6856             if (FormatPlaneCount(img_format) > 2u) {
6857                 allowed_flags |= VK_IMAGE_ASPECT_PLANE_2_BIT;
6858                 vuid = "VUID-vkGetImageSubresourceLayout-format-01582";  // 3-plane version
6859             }
6860             if (sub_aspect != (sub_aspect & allowed_flags)) {
6861                 skip |= LogError(image, vuid,
6862                                  "vkGetImageSubresourceLayout(): For multi-planar images, VkImageSubresource.aspectMask (0x%" PRIx32
6863                                  ") must be a single-plane specifier flag.",
6864                                  sub_aspect);
6865             }
6866         } else if (FormatIsColor(img_format)) {
6867             if (sub_aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
6868                 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-format-04461",
6869                                  "vkGetImageSubresourceLayout(): For color formats, VkImageSubresource.aspectMask must be "
6870                                  "VK_IMAGE_ASPECT_COLOR.");
6871             }
6872         } else if (FormatIsDepthOrStencil(img_format)) {
6873             if ((sub_aspect != VK_IMAGE_ASPECT_DEPTH_BIT) && (sub_aspect != VK_IMAGE_ASPECT_STENCIL_BIT)) {
6874             }
6875         }
6876         if (!FormatIsDepthAndStencil(img_format) && !FormatIsDepthOnly(img_format)) {
6877             if (sub_aspect & VK_IMAGE_ASPECT_DEPTH_BIT) {
6878                 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-format-04464",
6879                                  "vkGetImageSubresourceLayout(): Image format (%s) does not contain a depth component, "
6880                                  "but VkImageSubresource.aspectMask contains VK_IMAGE_ASPECT_DEPTH_BIT.",
6881                                  string_VkFormat(img_format));
6882             }
6883         } else {
6884             if ((sub_aspect & VK_IMAGE_ASPECT_DEPTH_BIT) == 0) {
6885                 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-format-04462",
6886                                  "vkGetImageSubresourceLayout(): Image format (%s) contains a depth component, "
6887                                  "but VkImageSubresource.aspectMask does not contain VK_IMAGE_ASPECT_DEPTH_BIT.",
6888                                  string_VkFormat(img_format));
6889             }
6890         }
6891         if (!FormatIsDepthAndStencil(img_format) && !FormatIsStencilOnly(img_format)) {
6892             if (sub_aspect & VK_IMAGE_ASPECT_STENCIL_BIT) {
6893                 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-format-04464",
6894                                  "vkGetImageSubresourceLayout(): Image format (%s) does not contain a stencil component, "
6895                                  "but VkImageSubresource.aspectMask contains VK_IMAGE_ASPECT_STENCIL_BIT.",
6896                                  string_VkFormat(img_format));
6897             }
6898         } else {
6899             if ((sub_aspect & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) {
6900                 skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-format-04463",
6901                                  "vkGetImageSubresourceLayout(): Image format (%s) contains a stencil component, "
6902                                  "but VkImageSubresource.aspectMask does not contain VK_IMAGE_ASPECT_STENCIL_BIT.",
6903                                  string_VkFormat(img_format));
6904             }
6905         }
6906     } else if (image_entry->createInfo.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
6907         if ((sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT) && (sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT) &&
6908             (sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT) && (sub_aspect != VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
6909             // TODO: This VU also needs to ensure that the DRM index is in range and valid.
6910             skip |= LogError(image, "VUID-vkGetImageSubresourceLayout-tiling-02271",
6911                              "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must be "
6912                              "VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT.");
6913         }
6914     }
6915 
6916     if (IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
6917         skip |= ValidateGetImageSubresourceLayoutANDROID(image);
6918     }
6919 
6920     return skip;
6921 }
6922 
6923 // Validates the image is allowed to be protected
ValidateProtectedImage(const CMD_BUFFER_STATE * cb_state,const IMAGE_STATE * image_state,const char * cmd_name,const char * vuid,const char * more_message) const6924 bool CoreChecks::ValidateProtectedImage(const CMD_BUFFER_STATE *cb_state, const IMAGE_STATE *image_state, const char *cmd_name,
6925                                         const char *vuid, const char *more_message) const {
6926     bool skip = false;
6927 
6928     // if driver supports protectedNoFault the operation is valid, just has undefined values
6929     if ((!phys_dev_props_core11.protectedNoFault) && (cb_state->unprotected == true) && (image_state->unprotected == false)) {
6930         LogObjectList objlist(cb_state->commandBuffer());
6931         objlist.add(image_state->image());
6932         skip |= LogError(objlist, vuid, "%s: command buffer %s is unprotected while image %s is a protected image.%s", cmd_name,
6933                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
6934                          report_data->FormatHandle(image_state->image()).c_str(), more_message);
6935     }
6936     return skip;
6937 }
6938 
6939 // Validates the image is allowed to be unprotected
ValidateUnprotectedImage(const CMD_BUFFER_STATE * cb_state,const IMAGE_STATE * image_state,const char * cmd_name,const char * vuid,const char * more_message) const6940 bool CoreChecks::ValidateUnprotectedImage(const CMD_BUFFER_STATE *cb_state, const IMAGE_STATE *image_state, const char *cmd_name,
6941                                           const char *vuid, const char *more_message) const {
6942     bool skip = false;
6943 
6944     // if driver supports protectedNoFault the operation is valid, just has undefined values
6945     if ((!phys_dev_props_core11.protectedNoFault) && (cb_state->unprotected == false) && (image_state->unprotected == true)) {
6946         LogObjectList objlist(cb_state->commandBuffer());
6947         objlist.add(image_state->image());
6948         skip |= LogError(objlist, vuid, "%s: command buffer %s is protected while image %s is an unprotected image.%s", cmd_name,
6949                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
6950                          report_data->FormatHandle(image_state->image()).c_str(), more_message);
6951     }
6952     return skip;
6953 }
6954 
6955 // Validates the buffer is allowed to be protected
ValidateProtectedBuffer(const CMD_BUFFER_STATE * cb_state,const BUFFER_STATE * buffer_state,const char * cmd_name,const char * vuid,const char * more_message) const6956 bool CoreChecks::ValidateProtectedBuffer(const CMD_BUFFER_STATE *cb_state, const BUFFER_STATE *buffer_state, const char *cmd_name,
6957                                          const char *vuid, const char *more_message) const {
6958     bool skip = false;
6959 
6960     // if driver supports protectedNoFault the operation is valid, just has undefined values
6961     if ((!phys_dev_props_core11.protectedNoFault) && (cb_state->unprotected == true) && (buffer_state->unprotected == false)) {
6962         LogObjectList objlist(cb_state->commandBuffer());
6963         objlist.add(buffer_state->buffer());
6964         skip |= LogError(objlist, vuid, "%s: command buffer %s is unprotected while buffer %s is a protected buffer.%s", cmd_name,
6965                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
6966                          report_data->FormatHandle(buffer_state->buffer()).c_str(), more_message);
6967     }
6968     return skip;
6969 }
6970 
6971 // Validates the buffer is allowed to be unprotected
ValidateUnprotectedBuffer(const CMD_BUFFER_STATE * cb_state,const BUFFER_STATE * buffer_state,const char * cmd_name,const char * vuid,const char * more_message) const6972 bool CoreChecks::ValidateUnprotectedBuffer(const CMD_BUFFER_STATE *cb_state, const BUFFER_STATE *buffer_state, const char *cmd_name,
6973                                            const char *vuid, const char *more_message) const {
6974     bool skip = false;
6975 
6976     // if driver supports protectedNoFault the operation is valid, just has undefined values
6977     if ((!phys_dev_props_core11.protectedNoFault) && (cb_state->unprotected == false) && (buffer_state->unprotected == true)) {
6978         LogObjectList objlist(cb_state->commandBuffer());
6979         objlist.add(buffer_state->buffer());
6980         skip |= LogError(objlist, vuid, "%s: command buffer %s is protected while buffer %s is an unprotected buffer.%s", cmd_name,
6981                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
6982                          report_data->FormatHandle(buffer_state->buffer()).c_str(), more_message);
6983     }
6984     return skip;
6985 }
6986