Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2019 The Khronos Group Inc.
      2  * Copyright (c) 2015-2019 Valve Corporation
      3  * Copyright (c) 2015-2019 LunarG, Inc.
      4  * Copyright (C) 2015-2019 Google Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     19  * Author: Dave Houlton <daveh (at) lunarg.com>
     20  * Shannon McPherson <shannon (at) lunarg.com>
     21  */
     22 
     23 // Allow use of STL min and max functions in Windows
     24 #define NOMINMAX
     25 
     26 #include <cmath>
     27 #include <set>
     28 #include <sstream>
     29 #include <string>
     30 
     31 #include "vk_enum_string_helper.h"
     32 #include "vk_layer_data.h"
     33 #include "vk_layer_utils.h"
     34 #include "vk_layer_logging.h"
     35 #include "vk_typemap_helper.h"
     36 
     37 #include "chassis.h"
     38 #include "core_validation.h"
     39 #include "shader_validation.h"
     40 #include "descriptor_sets.h"
     41 #include "buffer_validation.h"
     42 
     43 uint32_t FullMipChainLevels(uint32_t height, uint32_t width, uint32_t depth) {
     44     // uint cast applies floor()
     45     return 1u + (uint32_t)log2(std::max({height, width, depth}));
     46 }
     47 
     48 uint32_t FullMipChainLevels(VkExtent3D extent) { return FullMipChainLevels(extent.height, extent.width, extent.depth); }
     49 
     50 uint32_t FullMipChainLevels(VkExtent2D extent) { return FullMipChainLevels(extent.height, extent.width); }
     51 
     52 void CoreChecks::SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
     53                            const VkImageLayout &layout) {
     54     auto it = pCB->imageLayoutMap.find(imgpair);
     55     if (it != pCB->imageLayoutMap.end()) {
     56         it->second.layout = layout;
     57     } else {
     58         assert(imgpair.hasSubresource);
     59         IMAGE_CMD_BUF_LAYOUT_NODE node;
     60         if (!FindCmdBufLayout(device_data, pCB, imgpair.image, imgpair.subresource, node)) {
     61             node.initialLayout = layout;
     62         }
     63         SetLayout(device_data, pCB, imgpair, {node.initialLayout, layout});
     64     }
     65 }
     66 
     67 template <class OBJECT, class LAYOUT>
     68 void CoreChecks::SetLayout(layer_data *device_data, OBJECT *pObject, VkImage image, VkImageSubresource range,
     69                            const LAYOUT &layout) {
     70     ImageSubresourcePair imgpair = {image, true, range};
     71     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
     72     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
     73     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
     74     SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
     75     if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
     76         SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
     77         SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
     78         SetLayout(device_data, pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
     79     }
     80 }
     81 
     82 template <class OBJECT, class LAYOUT>
     83 void CoreChecks::SetLayout(layer_data *device_data, OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout,
     84                            VkImageAspectFlags aspectMask) {
     85     if (imgpair.subresource.aspectMask & aspectMask) {
     86         imgpair.subresource.aspectMask = aspectMask;
     87         SetLayout(device_data, pObject, imgpair, layout);
     88     }
     89 }
     90 
     91 // Set the layout in supplied map
     92 void CoreChecks::SetLayout(std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
     93                            ImageSubresourcePair imgpair, VkImageLayout layout) {
     94     auto it = imageLayoutMap.find(imgpair);
     95     if (it != imageLayoutMap.end()) {
     96         it->second.layout = layout;  // Update
     97     } else {
     98         imageLayoutMap[imgpair].layout = layout;  // Insert
     99     }
    100 }
    101 
    102 bool CoreChecks::FindLayoutVerifyNode(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, ImageSubresourcePair imgpair,
    103                                       IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
    104     if (!(imgpair.subresource.aspectMask & aspectMask)) {
    105         return false;
    106     }
    107     VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
    108     imgpair.subresource.aspectMask = aspectMask;
    109     auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
    110     if (imgsubIt == pCB->imageLayoutMap.end()) {
    111         return false;
    112     }
    113     if (node.layout != VK_IMAGE_LAYOUT_MAX_ENUM && node.layout != imgsubIt->second.layout) {
    114         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
    115                 kVUID_Core_DrawState_InvalidLayout,
    116                 "Cannot query for VkImage %s layout when combined aspect mask %d has multiple layout types: %s and %s",
    117                 report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(node.layout),
    118                 string_VkImageLayout(imgsubIt->second.layout));
    119     }
    120     if (node.initialLayout != VK_IMAGE_LAYOUT_MAX_ENUM && node.initialLayout != imgsubIt->second.initialLayout) {
    121         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
    122                 kVUID_Core_DrawState_InvalidLayout,
    123                 "Cannot query for VkImage %s"
    124                 " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
    125                 report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(node.initialLayout),
    126                 string_VkImageLayout(imgsubIt->second.initialLayout));
    127     }
    128     node = imgsubIt->second;
    129     return true;
    130 }
    131 
    132 bool CoreChecks::FindLayoutVerifyLayout(layer_data const *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout,
    133                                         const VkImageAspectFlags aspectMask) {
    134     if (!(imgpair.subresource.aspectMask & aspectMask)) {
    135         return false;
    136     }
    137     VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
    138     imgpair.subresource.aspectMask = aspectMask;
    139     auto imgsubIt = (*GetImageLayoutMap()).find(imgpair);
    140     if (imgsubIt == (*GetImageLayoutMap()).end()) {
    141         return false;
    142     }
    143     if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
    144         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
    145                 kVUID_Core_DrawState_InvalidLayout,
    146                 "Cannot query for VkImage %s layout when combined aspect mask %d has multiple layout types: %s and %s",
    147                 report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(layout),
    148                 string_VkImageLayout(imgsubIt->second.layout));
    149     }
    150     layout = imgsubIt->second.layout;
    151     return true;
    152 }
    153 
    154 // Find layout(s) on the command buffer level
    155 bool CoreChecks::FindCmdBufLayout(layer_data const *device_data, GLOBAL_CB_NODE const *pCB, VkImage image, VkImageSubresource range,
    156                                   IMAGE_CMD_BUF_LAYOUT_NODE &node) {
    157     ImageSubresourcePair imgpair = {image, true, range};
    158     node = IMAGE_CMD_BUF_LAYOUT_NODE(VK_IMAGE_LAYOUT_MAX_ENUM, VK_IMAGE_LAYOUT_MAX_ENUM);
    159     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
    160     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
    161     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
    162     FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
    163     if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
    164         FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
    165         FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
    166         FindLayoutVerifyNode(device_data, pCB, imgpair, node, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
    167     }
    168     if (node.layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
    169         imgpair = {image, false, VkImageSubresource()};
    170         auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
    171         if (imgsubIt == pCB->imageLayoutMap.end()) return false;
    172         // TODO: This is ostensibly a find function but it changes state here
    173         node = imgsubIt->second;
    174     }
    175     return true;
    176 }
    177 
    178 // Find layout(s) on the global level
    179 bool CoreChecks::FindGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
    180     layout = VK_IMAGE_LAYOUT_MAX_ENUM;
    181     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
    182     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
    183     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
    184     FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
    185     if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
    186         FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
    187         FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
    188         FindLayoutVerifyLayout(device_data, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
    189     }
    190     if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
    191         imgpair = {imgpair.image, false, VkImageSubresource()};
    192         auto imgsubIt = (*GetImageLayoutMap()).find(imgpair);
    193         if (imgsubIt == (*GetImageLayoutMap()).end()) return false;
    194         layout = imgsubIt->second.layout;
    195     }
    196     return true;
    197 }
    198 
    199 bool CoreChecks::FindLayouts(layer_data *device_data, VkImage image, std::vector<VkImageLayout> &layouts) {
    200     auto sub_data = (*GetImageSubresourceMap()).find(image);
    201     if (sub_data == (*GetImageSubresourceMap()).end()) return false;
    202     auto image_state = GetImageState(image);
    203     if (!image_state) return false;
    204     bool ignoreGlobal = false;
    205     // TODO: Make this robust for >1 aspect mask. Now it will just say ignore potential errors in this case.
    206     if (sub_data->second.size() >= (image_state->createInfo.arrayLayers * image_state->createInfo.mipLevels + 1)) {
    207         ignoreGlobal = true;
    208     }
    209     for (auto imgsubpair : sub_data->second) {
    210         if (ignoreGlobal && !imgsubpair.hasSubresource) continue;
    211         auto img_data = (*GetImageLayoutMap()).find(imgsubpair);
    212         if (img_data != (*GetImageLayoutMap()).end()) {
    213             layouts.push_back(img_data->second.layout);
    214         }
    215     }
    216     return true;
    217 }
    218 
    219 bool CoreChecks::FindLayout(const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
    220                             ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
    221     if (!(imgpair.subresource.aspectMask & aspectMask)) {
    222         return false;
    223     }
    224     imgpair.subresource.aspectMask = aspectMask;
    225     auto imgsubIt = imageLayoutMap.find(imgpair);
    226     if (imgsubIt == imageLayoutMap.end()) {
    227         return false;
    228     }
    229     layout = imgsubIt->second.layout;
    230     return true;
    231 }
    232 
    233 // find layout in supplied map
    234 bool CoreChecks::FindLayout(layer_data *device_data,
    235                             const std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &imageLayoutMap,
    236                             ImageSubresourcePair imgpair, VkImageLayout &layout) {
    237     layout = VK_IMAGE_LAYOUT_MAX_ENUM;
    238     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
    239     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
    240     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
    241     FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
    242     if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
    243         FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
    244         FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
    245         FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
    246     }
    247     // Image+subresource not found, look for image handle w/o subresource
    248     if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
    249         imgpair = {imgpair.image, false, VkImageSubresource()};
    250         auto imgsubIt = imageLayoutMap.find(imgpair);
    251         if (imgsubIt == imageLayoutMap.end()) return false;
    252         layout = imgsubIt->second.layout;
    253     }
    254     return true;
    255 }
    256 
    257 // Set the layout on the global level
    258 void CoreChecks::SetGlobalLayout(layer_data *device_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
    259     VkImage &image = imgpair.image;
    260     auto &lmap = (*GetImageLayoutMap());
    261     auto data = lmap.find(imgpair);
    262     if (data != lmap.end()) {
    263         data->second.layout = layout;  // Update
    264     } else {
    265         lmap[imgpair].layout = layout;  // Insert
    266     }
    267     auto &image_subresources = (*GetImageSubresourceMap())[image];
    268     auto subresource = std::find(image_subresources.begin(), image_subresources.end(), imgpair);
    269     if (subresource == image_subresources.end()) {
    270         image_subresources.push_back(imgpair);
    271     }
    272 }
    273 
    274 // Set the layout on the cmdbuf level
    275 void CoreChecks::SetLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair,
    276                            const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
    277     auto it = pCB->imageLayoutMap.find(imgpair);
    278     if (it != pCB->imageLayoutMap.end()) {
    279         it->second = node;  // Update
    280     } else {
    281         pCB->imageLayoutMap[imgpair] = node;  // Insert
    282     }
    283 }
    284 // Set image layout for given VkImageSubresourceRange struct
    285 void CoreChecks::SetImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
    286                                 VkImageSubresourceRange image_subresource_range, const VkImageLayout &layout) {
    287     assert(image_state);
    288     cb_node->image_layout_change_count++;  // Change the version of this data to force revalidation
    289     for (uint32_t level_index = 0; level_index < image_subresource_range.levelCount; ++level_index) {
    290         uint32_t level = image_subresource_range.baseMipLevel + level_index;
    291         for (uint32_t layer_index = 0; layer_index < image_subresource_range.layerCount; layer_index++) {
    292             uint32_t layer = image_subresource_range.baseArrayLayer + layer_index;
    293             VkImageSubresource sub = {image_subresource_range.aspectMask, level, layer};
    294             // TODO: If ImageView was created with depth or stencil, transition both layouts as the aspectMask is ignored and both
    295             // are used. Verify that the extra implicit layout is OK for descriptor set layout validation
    296             if (image_subresource_range.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
    297                 if (FormatIsDepthAndStencil(image_state->createInfo.format)) {
    298                     sub.aspectMask |= (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
    299                 }
    300             }
    301             // For multiplane images, IMAGE_ASPECT_COLOR is an alias for all of the plane bits
    302             if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
    303                 if (FormatIsMultiplane(image_state->createInfo.format)) {
    304                     if (sub.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
    305                         sub.aspectMask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
    306                         sub.aspectMask |= VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR;
    307                         if (FormatPlaneCount(image_state->createInfo.format) > 2) {
    308                             sub.aspectMask |= VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
    309                         }
    310                     }
    311                 }
    312             }
    313             SetLayout(device_data, cb_node, image_state->image, sub, layout);
    314         }
    315     }
    316 }
    317 // Set image layout for given VkImageSubresourceLayers struct
    318 void CoreChecks::SetImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *image_state,
    319                                 VkImageSubresourceLayers image_subresource_layers, const VkImageLayout &layout) {
    320     // Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
    321     VkImageSubresourceRange image_subresource_range;
    322     image_subresource_range.aspectMask = image_subresource_layers.aspectMask;
    323     image_subresource_range.baseArrayLayer = image_subresource_layers.baseArrayLayer;
    324     image_subresource_range.layerCount = image_subresource_layers.layerCount;
    325     image_subresource_range.baseMipLevel = image_subresource_layers.mipLevel;
    326     image_subresource_range.levelCount = 1;
    327     SetImageLayout(device_data, cb_node, image_state, image_subresource_range, layout);
    328 }
    329 
    330 // Set image layout for all slices of an image view
    331 void CoreChecks::SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_VIEW_STATE *view_state,
    332                                     const VkImageLayout &layout) {
    333     assert(view_state);
    334 
    335     IMAGE_STATE *image_state = GetImageState(view_state->create_info.image);
    336     VkImageSubresourceRange sub_range = view_state->create_info.subresourceRange;
    337 
    338     // When changing the layout of a 3D image subresource via a 2D or 2D_ARRRAY image view, all depth slices of
    339     // the subresource mip level(s) are transitioned, ignoring any layers restriction in the subresource info.
    340     if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) && (view_state->create_info.viewType != VK_IMAGE_VIEW_TYPE_3D)) {
    341         sub_range.baseArrayLayer = 0;
    342         sub_range.layerCount = image_state->createInfo.extent.depth;
    343     }
    344 
    345     SetImageLayout(device_data, cb_node, image_state, sub_range, layout);
    346 }
    347 
    348 void CoreChecks::SetImageViewLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImageView imageView,
    349                                     const VkImageLayout &layout) {
    350     auto view_state = GetImageViewState(imageView);
    351     SetImageViewLayout(device_data, cb_node, view_state, layout);
    352 }
    353 
    354 bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(layer_data *device_data, RenderPassCreateVersion rp_version,
    355                                                                       VkImageLayout layout, VkImage image, VkImageView image_view,
    356                                                                       VkFramebuffer framebuffer, VkRenderPass renderpass,
    357                                                                       uint32_t attachment_index, const char *variable_name) {
    358     bool skip = false;
    359     auto image_state = GetImageState(image);
    360     const char *vuid;
    361     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
    362 
    363     if (!image_state) {
    364         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
    365                         "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
    366                         "Render Pass begin with renderpass %s uses framebuffer %s where pAttachments[%" PRIu32
    367                         "] = image view %s, which refers to an invalid image",
    368                         report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(framebuffer).c_str(),
    369                         attachment_index, report_data->FormatHandle(image_view).c_str());
    370         return skip;
    371     }
    372 
    373     auto image_usage = image_state->createInfo.usage;
    374 
    375     // Check for layouts that mismatch image usages in the framebuffer
    376     if (layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
    377         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094" : "VUID-vkCmdBeginRenderPass-initialLayout-00895";
    378         skip |=
    379             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
    380                     "Layout/usage mismatch for attachment %u in render pass %s"
    381                     " - the %s is %s but the image attached to framebuffer %s via image view %s"
    382                     " was not created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT",
    383                     attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
    384                     report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
    385     }
    386 
    387     if (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
    388         !(image_usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
    389         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097" : "VUID-vkCmdBeginRenderPass-initialLayout-00897";
    390         skip |=
    391             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
    392                     "Layout/usage mismatch for attachment %u in render pass %s"
    393                     " - the %s is %s but the image attached to framebuffer %s via image view %s"
    394                     " was not created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT or VK_IMAGE_USAGE_SAMPLED_BIT",
    395                     attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
    396                     report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
    397     }
    398 
    399     if (layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
    400         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098" : "VUID-vkCmdBeginRenderPass-initialLayout-00898";
    401         skip |=
    402             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
    403                     "Layout/usage mismatch for attachment %u in render pass %s"
    404                     " - the %s is %s but the image attached to framebuffer %s via image view %s"
    405                     " was not created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT",
    406                     attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
    407                     report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
    408     }
    409 
    410     if (layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
    411         vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099" : "VUID-vkCmdBeginRenderPass-initialLayout-00899";
    412         skip |=
    413             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
    414                     "Layout/usage mismatch for attachment %u in render pass %s"
    415                     " - the %s is %s but the image attached to framebuffer %s via image view %s"
    416                     " was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT",
    417                     attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
    418                     report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
    419     }
    420 
    421     if (GetDeviceExtensions()->vk_khr_maintenance2) {
    422         if ((layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
    423              layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
    424              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
    425              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
    426             !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
    427             vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096" : "VUID-vkCmdBeginRenderPass-initialLayout-01758";
    428             skip |= log_msg(
    429                 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
    430                 "Layout/usage mismatch for attachment %u in render pass %s"
    431                 " - the %s is %s but the image attached to framebuffer %s via image view %s"
    432                 " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
    433                 attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name, string_VkImageLayout(layout),
    434                 report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(image_view).c_str());
    435         }
    436     } else {
    437         // The create render pass 2 extension requires maintenance 2 (the previous branch), so no vuid switch needed here.
    438         if ((layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
    439              layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
    440             !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
    441             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    442                             HandleToUint64(image), "VUID-vkCmdBeginRenderPass-initialLayout-00896",
    443                             "Layout/usage mismatch for attachment %u in render pass %s"
    444                             " - the %s is %s but the image attached to framebuffer %s via image view %s"
    445                             " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
    446                             attachment_index, report_data->FormatHandle(framebuffer).c_str(), variable_name,
    447                             string_VkImageLayout(layout), report_data->FormatHandle(renderpass).c_str(),
    448                             report_data->FormatHandle(image_view).c_str());
    449         }
    450     }
    451     return skip;
    452 }
    453 
    454 bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(layer_data *device_data, RenderPassCreateVersion rp_version,
    455                                                        GLOBAL_CB_NODE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
    456                                                        const FRAMEBUFFER_STATE *framebuffer_state) {
    457     bool skip = false;
    458     auto const pRenderPassInfo = GetRenderPassState(pRenderPassBegin->renderPass)->createInfo.ptr();
    459     auto const &framebufferInfo = framebuffer_state->createInfo;
    460 
    461     auto render_pass = GetRenderPassState(pRenderPassBegin->renderPass)->renderPass;
    462     auto framebuffer = framebuffer_state->framebuffer;
    463 
    464     if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
    465         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    466                         HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidRenderpass,
    467                         "You cannot start a render pass using a framebuffer with a different number of attachments.");
    468     }
    469     for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
    470         const VkImageView &image_view = framebufferInfo.pAttachments[i];
    471         auto view_state = GetImageViewState(image_view);
    472 
    473         if (!view_state) {
    474             skip |=
    475                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
    476                         HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
    477                         "vkCmdBeginRenderPass(): framebuffer %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle",
    478                         report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i,
    479                         report_data->FormatHandle(image_view).c_str());
    480             continue;
    481         }
    482 
    483         const VkImage &image = view_state->create_info.image;
    484         const VkImageSubresourceRange &subRange = view_state->create_info.subresourceRange;
    485         auto initial_layout = pRenderPassInfo->pAttachments[i].initialLayout;
    486         auto final_layout = pRenderPassInfo->pAttachments[i].finalLayout;
    487 
    488         // TODO: Do not iterate over every possibility - consolidate where possible
    489         for (uint32_t j = 0; j < subRange.levelCount; j++) {
    490             uint32_t level = subRange.baseMipLevel + j;
    491             for (uint32_t k = 0; k < subRange.layerCount; k++) {
    492                 uint32_t layer = subRange.baseArrayLayer + k;
    493                 VkImageSubresource sub = {subRange.aspectMask, level, layer};
    494                 IMAGE_CMD_BUF_LAYOUT_NODE node;
    495                 if (!FindCmdBufLayout(device_data, pCB, image, sub, node)) {
    496                     // Missing layouts will be added during state update
    497                     continue;
    498                 }
    499                 if (initial_layout != VK_IMAGE_LAYOUT_UNDEFINED && initial_layout != node.layout) {
    500                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
    501                                     kVUID_Core_DrawState_InvalidRenderpass,
    502                                     "You cannot start a render pass using attachment %u where the render pass initial layout is %s "
    503                                     "and the previous known layout of the attachment is %s. The layouts must match, or the render "
    504                                     "pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED",
    505                                     i, string_VkImageLayout(initial_layout), string_VkImageLayout(node.layout));
    506                 }
    507             }
    508         }
    509 
    510         ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, initial_layout, image, image_view,
    511                                                              framebuffer, render_pass, i, "initial layout");
    512 
    513         ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, final_layout, image, image_view, framebuffer,
    514                                                              render_pass, i, "final layout");
    515     }
    516 
    517     for (uint32_t j = 0; j < pRenderPassInfo->subpassCount; ++j) {
    518         auto &subpass = pRenderPassInfo->pSubpasses[j];
    519         for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].inputAttachmentCount; ++k) {
    520             auto &attachment_ref = subpass.pInputAttachments[k];
    521             if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
    522                 auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment];
    523                 auto view_state = GetImageViewState(image_view);
    524 
    525                 if (view_state) {
    526                     auto image = view_state->create_info.image;
    527                     ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, attachment_ref.layout, image,
    528                                                                          image_view, framebuffer, render_pass,
    529                                                                          attachment_ref.attachment, "input attachment layout");
    530                 }
    531             }
    532         }
    533 
    534         for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].colorAttachmentCount; ++k) {
    535             auto &attachment_ref = subpass.pColorAttachments[k];
    536             if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
    537                 auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment];
    538                 auto view_state = GetImageViewState(image_view);
    539 
    540                 if (view_state) {
    541                     auto image = view_state->create_info.image;
    542                     ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, attachment_ref.layout, image,
    543                                                                          image_view, framebuffer, render_pass,
    544                                                                          attachment_ref.attachment, "color attachment layout");
    545                     if (subpass.pResolveAttachments) {
    546                         ValidateRenderPassLayoutAgainstFramebufferImageUsage(
    547                             device_data, rp_version, attachment_ref.layout, image, image_view, framebuffer, render_pass,
    548                             attachment_ref.attachment, "resolve attachment layout");
    549                     }
    550                 }
    551             }
    552         }
    553 
    554         if (pRenderPassInfo->pSubpasses[j].pDepthStencilAttachment) {
    555             auto &attachment_ref = *subpass.pDepthStencilAttachment;
    556             if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
    557                 auto image_view = framebufferInfo.pAttachments[attachment_ref.attachment];
    558                 auto view_state = GetImageViewState(image_view);
    559 
    560                 if (view_state) {
    561                     auto image = view_state->create_info.image;
    562                     ValidateRenderPassLayoutAgainstFramebufferImageUsage(device_data, rp_version, attachment_ref.layout, image,
    563                                                                          image_view, framebuffer, render_pass,
    564                                                                          attachment_ref.attachment, "input attachment layout");
    565                 }
    566             }
    567         }
    568     }
    569     return skip;
    570 }
    571 
    572 void CoreChecks::TransitionAttachmentRefLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
    573                                                const safe_VkAttachmentReference2KHR &ref) {
    574     if (ref.attachment != VK_ATTACHMENT_UNUSED) {
    575         auto image_view = GetAttachmentImageViewState(pFramebuffer, ref.attachment);
    576         if (image_view) {
    577             SetImageViewLayout(device_data, pCB, image_view, ref.layout);
    578         }
    579     }
    580 }
    581 
    582 void CoreChecks::TransitionSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB, const RENDER_PASS_STATE *render_pass_state,
    583                                           const int subpass_index, FRAMEBUFFER_STATE *framebuffer_state) {
    584     assert(render_pass_state);
    585 
    586     if (framebuffer_state) {
    587         auto const &subpass = render_pass_state->createInfo.pSubpasses[subpass_index];
    588         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
    589             TransitionAttachmentRefLayout(device_data, pCB, framebuffer_state, subpass.pInputAttachments[j]);
    590         }
    591         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
    592             TransitionAttachmentRefLayout(device_data, pCB, framebuffer_state, subpass.pColorAttachments[j]);
    593         }
    594         if (subpass.pDepthStencilAttachment) {
    595             TransitionAttachmentRefLayout(device_data, pCB, framebuffer_state, *subpass.pDepthStencilAttachment);
    596         }
    597     }
    598 }
    599 
    600 bool CoreChecks::ValidateImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE const *pCB,
    601                                            const VkImageMemoryBarrier *mem_barrier, uint32_t level, uint32_t layer,
    602                                            VkImageAspectFlags aspect) {
    603     if (!(mem_barrier->subresourceRange.aspectMask & aspect)) {
    604         return false;
    605     }
    606     VkImageSubresource sub = {aspect, level, layer};
    607     IMAGE_CMD_BUF_LAYOUT_NODE node;
    608     if (!FindCmdBufLayout(device_data, pCB, mem_barrier->image, sub, node)) {
    609         return false;
    610     }
    611     bool skip = false;
    612     if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
    613         // TODO: Set memory invalid which is in mem_tracker currently
    614     } else if (node.layout != mem_barrier->oldLayout) {
    615         skip = log_msg(
    616             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    617             HandleToUint64(pCB->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
    618             "For image %s you cannot transition the layout of aspect=%d level=%d layer=%d from %s when current layout is %s.",
    619             report_data->FormatHandle(mem_barrier->image).c_str(), aspect, level, layer,
    620             string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
    621     }
    622     return skip;
    623 }
    624 
    625 // Transition the layout state for renderpass attachments based on the BeginRenderPass() call. This includes:
    626 // 1. Transition into initialLayout state
    627 // 2. Transition from initialLayout to layout used in subpass 0
    628 void CoreChecks::TransitionBeginRenderPassLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
    629                                                   const RENDER_PASS_STATE *render_pass_state,
    630                                                   FRAMEBUFFER_STATE *framebuffer_state) {
    631     // First transition into initialLayout
    632     auto const rpci = render_pass_state->createInfo.ptr();
    633     for (uint32_t i = 0; i < rpci->attachmentCount; ++i) {
    634         auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
    635         if (view_state) {
    636             SetImageViewLayout(device_data, cb_state, view_state, rpci->pAttachments[i].initialLayout);
    637         }
    638     }
    639     // Now transition for first subpass (index 0)
    640     TransitionSubpassLayouts(device_data, cb_state, render_pass_state, 0, framebuffer_state);
    641 }
    642 
    643 void CoreChecks::TransitionImageAspectLayout(layer_data *device_data, GLOBAL_CB_NODE *pCB, const VkImageMemoryBarrier *mem_barrier,
    644                                              uint32_t level, uint32_t layer, VkImageAspectFlags aspect_mask,
    645                                              VkImageAspectFlags aspect) {
    646     if (!(aspect_mask & aspect)) {
    647         return;
    648     }
    649     VkImageSubresource sub = {aspect, level, layer};
    650     IMAGE_CMD_BUF_LAYOUT_NODE node;
    651     if (!FindCmdBufLayout(device_data, pCB, mem_barrier->image, sub, node)) {
    652         pCB->image_layout_change_count++;  // Change the version of this data to force revalidation
    653         SetLayout(device_data, pCB, mem_barrier->image, sub,
    654                   IMAGE_CMD_BUF_LAYOUT_NODE(mem_barrier->oldLayout, mem_barrier->newLayout));
    655         return;
    656     }
    657     if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
    658         // TODO: Set memory invalid
    659     }
    660     SetLayout(device_data, pCB, mem_barrier->image, sub, mem_barrier->newLayout);
    661 }
    662 
    663 bool VerifyAspectsPresent(VkImageAspectFlags aspect_mask, VkFormat format) {
    664     if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
    665         if (!(FormatIsColor(format) || FormatIsMultiplane(format))) return false;
    666     }
    667     if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
    668         if (!FormatHasDepth(format)) return false;
    669     }
    670     if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
    671         if (!FormatHasStencil(format)) return false;
    672     }
    673     if (0 !=
    674         (aspect_mask & (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR))) {
    675         if (FormatPlaneCount(format) == 1) return false;
    676     }
    677     return true;
    678 }
    679 
    680 // Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags.
    681 bool CoreChecks::ValidateBarrierLayoutToImageUsage(layer_data *device_data, const VkImageMemoryBarrier *img_barrier,
    682                                                    bool new_not_old, VkImageUsageFlags usage_flags, const char *func_name) {
    683     bool skip = false;
    684     const VkImageLayout layout = (new_not_old) ? img_barrier->newLayout : img_barrier->oldLayout;
    685     const char *msg_code = kVUIDUndefined;  // sentinel value meaning "no error"
    686 
    687     switch (layout) {
    688         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
    689             if ((usage_flags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0) {
    690                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01208";
    691             }
    692             break;
    693         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
    694             if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
    695                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01209";
    696             }
    697             break;
    698         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
    699             if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
    700                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01210";
    701             }
    702             break;
    703         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
    704             if ((usage_flags & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0) {
    705                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01211";
    706             }
    707             break;
    708         case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
    709             if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0) {
    710                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01212";
    711             }
    712             break;
    713         case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
    714             if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
    715                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01213";
    716             }
    717             break;
    718         case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV:
    719             if ((usage_flags & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) == 0) {
    720                 msg_code = "VUID-VkImageMemoryBarrier-oldLayout-02088";
    721             }
    722             break;
    723         default:
    724             // Other VkImageLayout values do not have VUs defined in this context.
    725             break;
    726     }
    727 
    728     if (msg_code != kVUIDUndefined) {
    729         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    730                         HandleToUint64(img_barrier->image), msg_code,
    731                         "%s: Image barrier 0x%p %sLayout=%s is not compatible with image %s usage flags 0x%" PRIx32 ".", func_name,
    732                         static_cast<const void *>(img_barrier), ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout),
    733                         report_data->FormatHandle(img_barrier->image).c_str(), usage_flags);
    734     }
    735     return skip;
    736 }
    737 
    738 // Scoreboard for checking for duplicate and inconsistent barriers to images
    739 struct ImageBarrierScoreboardEntry {
    740     uint32_t index;
    741     // This is designed for temporary storage within the scope of the API call.  If retained storage of the barriers is
    742     // required, copies should be made and smart or unique pointers used in some other stucture (or this one refactored)
    743     const VkImageMemoryBarrier *barrier;
    744 };
    745 using ImageBarrierScoreboardSubresMap = std::unordered_map<VkImageSubresourceRange, ImageBarrierScoreboardEntry>;
    746 using ImageBarrierScoreboardImageMap = std::unordered_map<VkImage, ImageBarrierScoreboardSubresMap>;
    747 
    748 // Verify image barriers are compatible with the images they reference.
    749 bool CoreChecks::ValidateBarriersToImages(layer_data *device_data, GLOBAL_CB_NODE const *cb_state, uint32_t imageMemoryBarrierCount,
    750                                           const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) {
    751     bool skip = false;
    752 
    753     // Scoreboard for duplicate layout transition barriers within the list
    754     // Pointers retained in the scoreboard only have the lifetime of *this* call (i.e. within the scope of the API call)
    755     ImageBarrierScoreboardImageMap layout_transitions;
    756 
    757     for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
    758         auto img_barrier = &pImageMemoryBarriers[i];
    759         if (!img_barrier) continue;
    760 
    761         // Update the scoreboard of layout transitions and check for barriers affecting the same image and subresource
    762         // TODO: a higher precision could be gained by adapting the command_buffer image_layout_map logic looking for conflicts
    763         // at a per sub-resource level
    764         if (img_barrier->oldLayout != img_barrier->newLayout) {
    765             ImageBarrierScoreboardEntry new_entry{i, img_barrier};
    766             auto image_it = layout_transitions.find(img_barrier->image);
    767             if (image_it != layout_transitions.end()) {
    768                 auto &subres_map = image_it->second;
    769                 auto subres_it = subres_map.find(img_barrier->subresourceRange);
    770                 if (subres_it != subres_map.end()) {
    771                     auto &entry = subres_it->second;
    772                     if ((entry.barrier->newLayout != img_barrier->oldLayout) &&
    773                         (img_barrier->oldLayout != VK_IMAGE_LAYOUT_UNDEFINED)) {
    774                         const VkImageSubresourceRange &range = img_barrier->subresourceRange;
    775                         skip = log_msg(
    776                             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    777                             HandleToUint64(cb_state->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
    778                             "%s: pImageMemoryBarrier[%u] conflicts with earlier entry pImageMemoryBarrier[%u]. Image %s"
    779                             " subresourceRange: aspectMask=%u baseMipLevel=%u levelCount=%u, baseArrayLayer=%u, layerCount=%u; "
    780                             "conflicting barrier transitions image layout from %s when earlier barrier transitioned to layout %s.",
    781                             func_name, i, entry.index, report_data->FormatHandle(img_barrier->image).c_str(), range.aspectMask,
    782                             range.baseMipLevel, range.levelCount, range.baseArrayLayer, range.layerCount,
    783                             string_VkImageLayout(img_barrier->oldLayout), string_VkImageLayout(entry.barrier->newLayout));
    784                     }
    785                     entry = new_entry;
    786                 } else {
    787                     subres_map[img_barrier->subresourceRange] = new_entry;
    788                 }
    789             } else {
    790                 layout_transitions[img_barrier->image][img_barrier->subresourceRange] = new_entry;
    791             }
    792         }
    793 
    794         auto image_state = GetImageState(img_barrier->image);
    795         if (image_state) {
    796             VkImageUsageFlags usage_flags = image_state->createInfo.usage;
    797             skip |= ValidateBarrierLayoutToImageUsage(device_data, img_barrier, false, usage_flags, func_name);
    798             skip |= ValidateBarrierLayoutToImageUsage(device_data, img_barrier, true, usage_flags, func_name);
    799 
    800             // Make sure layout is able to be transitioned, currently only presented shared presentable images are locked
    801             if (image_state->layout_locked) {
    802                 // TODO: Add unique id for error when available
    803                 skip |= log_msg(
    804                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    805                     HandleToUint64(img_barrier->image), 0,
    806                     "Attempting to transition shared presentable image %s"
    807                     " from layout %s to layout %s, but image has already been presented and cannot have its layout transitioned.",
    808                     report_data->FormatHandle(img_barrier->image).c_str(), string_VkImageLayout(img_barrier->oldLayout),
    809                     string_VkImageLayout(img_barrier->newLayout));
    810             }
    811         }
    812 
    813         VkImageCreateInfo *image_create_info = &(GetImageState(img_barrier->image)->createInfo);
    814         // For a Depth/Stencil image both aspects MUST be set
    815         if (FormatIsDepthAndStencil(image_create_info->format)) {
    816             auto const aspect_mask = img_barrier->subresourceRange.aspectMask;
    817             auto const ds_mask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
    818             if ((aspect_mask & ds_mask) != (ds_mask)) {
    819                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    820                                 HandleToUint64(img_barrier->image), "VUID-VkImageMemoryBarrier-image-01207",
    821                                 "%s: Image barrier 0x%p references image %s of format %s that must have the depth and stencil "
    822                                 "aspects set, but its aspectMask is 0x%" PRIx32 ".",
    823                                 func_name, static_cast<const void *>(img_barrier),
    824                                 report_data->FormatHandle(img_barrier->image).c_str(), string_VkFormat(image_create_info->format),
    825                                 aspect_mask);
    826             }
    827         }
    828         uint32_t level_count = ResolveRemainingLevels(&img_barrier->subresourceRange, image_create_info->mipLevels);
    829         uint32_t layer_count = ResolveRemainingLayers(&img_barrier->subresourceRange, image_create_info->arrayLayers);
    830 
    831         for (uint32_t j = 0; j < level_count; j++) {
    832             uint32_t level = img_barrier->subresourceRange.baseMipLevel + j;
    833             for (uint32_t k = 0; k < layer_count; k++) {
    834                 uint32_t layer = img_barrier->subresourceRange.baseArrayLayer + k;
    835                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_COLOR_BIT);
    836                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_DEPTH_BIT);
    837                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_STENCIL_BIT);
    838                 skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer, VK_IMAGE_ASPECT_METADATA_BIT);
    839                 if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
    840                     skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer,
    841                                                       VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
    842                     skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer,
    843                                                       VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
    844                     skip |= ValidateImageAspectLayout(device_data, cb_state, img_barrier, level, layer,
    845                                                       VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
    846                 }
    847             }
    848         }
    849     }
    850     return skip;
    851 }
    852 
    853 bool CoreChecks::IsReleaseOp(GLOBAL_CB_NODE *cb_state, VkImageMemoryBarrier const *barrier) {
    854     if (!IsTransferOp(barrier)) return false;
    855 
    856     auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
    857     return pool && TempIsReleaseOp<VkImageMemoryBarrier, true>(pool, barrier);
    858 }
    859 
    860 template <typename Barrier>
    861 bool CoreChecks::ValidateQFOTransferBarrierUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
    862                                                       uint32_t barrier_count, const Barrier *barriers) {
    863     using BarrierRecord = QFOTransferBarrier<Barrier>;
    864     bool skip = false;
    865     auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
    866     auto &barrier_sets = GetQFOBarrierSets(cb_state, typename BarrierRecord::Tag());
    867     const char *barrier_name = BarrierRecord::BarrierName();
    868     const char *handle_name = BarrierRecord::HandleName();
    869     const char *transfer_type = nullptr;
    870     for (uint32_t b = 0; b < barrier_count; b++) {
    871         if (!IsTransferOp(&barriers[b])) continue;
    872         const BarrierRecord *barrier_record = nullptr;
    873         if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer */>(pool, &barriers[b]) &&
    874             !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
    875             const auto found = barrier_sets.release.find(barriers[b]);
    876             if (found != barrier_sets.release.cend()) {
    877                 barrier_record = &(*found);
    878                 transfer_type = "releasing";
    879             }
    880         } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barriers[b]) &&
    881                    !IsSpecial(barriers[b].srcQueueFamilyIndex)) {
    882             const auto found = barrier_sets.acquire.find(barriers[b]);
    883             if (found != barrier_sets.acquire.cend()) {
    884                 barrier_record = &(*found);
    885                 transfer_type = "acquiring";
    886             }
    887         }
    888         if (barrier_record != nullptr) {
    889             skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    890                             HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInCB(),
    891                             "%s: %s at index %" PRIu32 " %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
    892                             " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier recorded in this command buffer.",
    893                             func_name, barrier_name, b, transfer_type, handle_name,
    894                             report_data->FormatHandle(barrier_record->handle).c_str(), barrier_record->srcQueueFamilyIndex,
    895                             barrier_record->dstQueueFamilyIndex);
    896         }
    897     }
    898     return skip;
    899 }
    900 
    901 template <typename Barrier>
    902 void CoreChecks::RecordQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t barrier_count,
    903                                            const Barrier *barriers) {
    904     auto pool = GetCommandPoolNode(cb_state->createInfo.commandPool);
    905     auto &barrier_sets = GetQFOBarrierSets(cb_state, typename QFOTransferBarrier<Barrier>::Tag());
    906     for (uint32_t b = 0; b < barrier_count; b++) {
    907         if (!IsTransferOp(&barriers[b])) continue;
    908         if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer*/>(pool, &barriers[b]) &&
    909             !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
    910             barrier_sets.release.emplace(barriers[b]);
    911         } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barriers[b]) &&
    912                    !IsSpecial(barriers[b].srcQueueFamilyIndex)) {
    913             barrier_sets.acquire.emplace(barriers[b]);
    914         }
    915     }
    916 }
    917 
    918 bool CoreChecks::ValidateBarriersQFOTransferUniqueness(layer_data *device_data, const char *func_name, GLOBAL_CB_NODE *cb_state,
    919                                                        uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
    920                                                        uint32_t imageMemBarrierCount,
    921                                                        const VkImageMemoryBarrier *pImageMemBarriers) {
    922     bool skip = false;
    923     skip |= ValidateQFOTransferBarrierUniqueness(device_data, func_name, cb_state, bufferBarrierCount, pBufferMemBarriers);
    924     skip |= ValidateQFOTransferBarrierUniqueness(device_data, func_name, cb_state, imageMemBarrierCount, pImageMemBarriers);
    925     return skip;
    926 }
    927 
    928 void CoreChecks::RecordBarriersQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t bufferBarrierCount,
    929                                             const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
    930                                             const VkImageMemoryBarrier *pImageMemBarriers) {
    931     RecordQFOTransferBarriers(device_data, cb_state, bufferBarrierCount, pBufferMemBarriers);
    932     RecordQFOTransferBarriers(device_data, cb_state, imageMemBarrierCount, pImageMemBarriers);
    933 }
    934 
    935 template <typename BarrierRecord, typename Scoreboard>
    936 bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const GLOBAL_CB_NODE *cb_state,
    937                                                 const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) {
    938     // Record to the scoreboard or report that we have a duplication
    939     bool skip = false;
    940     auto inserted = scoreboard->insert(std::make_pair(barrier, cb_state));
    941     if (!inserted.second && inserted.first->second != cb_state) {
    942         // This is a duplication (but don't report duplicates from the same CB, as we do that at record time
    943         skip = log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    944                        HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInSubmit(),
    945                        "%s: %s %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32 " to dstQueueFamilyIndex %" PRIu32
    946                        " duplicates existing barrier submitted in this batch from command buffer %s.",
    947                        "vkQueueSubmit()", BarrierRecord::BarrierName(), operation, BarrierRecord::HandleName(),
    948                        report_data->FormatHandle(barrier.handle).c_str(), barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex,
    949                        report_data->FormatHandle(inserted.first->second).c_str());
    950     }
    951     return skip;
    952 }
    953 
    954 template <typename Barrier>
    955 bool CoreChecks::ValidateQueuedQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
    956                                                    QFOTransferCBScoreboards<Barrier> *scoreboards) {
    957     using BarrierRecord = QFOTransferBarrier<Barrier>;
    958     using TypeTag = typename BarrierRecord::Tag;
    959     bool skip = false;
    960     const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
    961     const GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
    962     const char *barrier_name = BarrierRecord::BarrierName();
    963     const char *handle_name = BarrierRecord::HandleName();
    964     // No release should have an extant duplicate (WARNING)
    965     for (const auto &release : cb_barriers.release) {
    966         // Check the global pending release barriers
    967         const auto set_it = global_release_barriers.find(release.handle);
    968         if (set_it != global_release_barriers.cend()) {
    969             const QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
    970             const auto found = set_for_handle.find(release);
    971             if (found != set_for_handle.cend()) {
    972                 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    973                                 HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOSubmitted(),
    974                                 "%s: %s releasing queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
    975                                 " to dstQueueFamilyIndex %" PRIu32
    976                                 " duplicates existing barrier queued for execution, without intervening acquire operation.",
    977                                 "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(found->handle).c_str(),
    978                                 found->srcQueueFamilyIndex, found->dstQueueFamilyIndex);
    979             }
    980         }
    981         skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "releasing", release, &scoreboards->release);
    982     }
    983     // Each acquire must have a matching release (ERROR)
    984     for (const auto &acquire : cb_barriers.acquire) {
    985         const auto set_it = global_release_barriers.find(acquire.handle);
    986         bool matching_release_found = false;
    987         if (set_it != global_release_barriers.cend()) {
    988             const QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
    989             matching_release_found = set_for_handle.find(acquire) != set_for_handle.cend();
    990         }
    991         if (!matching_release_found) {
    992             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    993                             HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgMissingQFOReleaseInSubmit(),
    994                             "%s: in submitted command buffer %s acquiring ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
    995                             " to dstQueueFamilyIndex %" PRIu32 " has no matching release barrier queued for execution.",
    996                             "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(acquire.handle).c_str(),
    997                             acquire.srcQueueFamilyIndex, acquire.dstQueueFamilyIndex);
    998         }
    999         skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "acquiring", acquire, &scoreboards->acquire);
   1000     }
   1001     return skip;
   1002 }
   1003 
   1004 bool CoreChecks::ValidateQueuedQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state,
   1005                                             QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
   1006                                             QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) {
   1007     bool skip = false;
   1008     skip |= ValidateQueuedQFOTransferBarriers<VkImageMemoryBarrier>(device_data, cb_state, qfo_image_scoreboards);
   1009     skip |= ValidateQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(device_data, cb_state, qfo_buffer_scoreboards);
   1010     return skip;
   1011 }
   1012 
   1013 template <typename Barrier>
   1014 void CoreChecks::RecordQueuedQFOTransferBarriers(layer_data *device_data, GLOBAL_CB_NODE *cb_state) {
   1015     using BarrierRecord = QFOTransferBarrier<Barrier>;
   1016     using TypeTag = typename BarrierRecord::Tag;
   1017     const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
   1018     GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
   1019 
   1020     // Add release barriers from this submit to the global map
   1021     for (const auto &release : cb_barriers.release) {
   1022         // the global barrier list is mapped by resource handle to allow cleanup on resource destruction
   1023         // NOTE: We're using [] because creation of a Set is a needed side effect for new handles
   1024         global_release_barriers[release.handle].insert(release);
   1025     }
   1026 
   1027     // Erase acquired barriers from this submit from the global map -- essentially marking releases as consumed
   1028     for (const auto &acquire : cb_barriers.acquire) {
   1029         // NOTE: We're not using [] because we don't want to create entries for missing releases
   1030         auto set_it = global_release_barriers.find(acquire.handle);
   1031         if (set_it != global_release_barriers.end()) {
   1032             QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
   1033             set_for_handle.erase(acquire);
   1034             if (set_for_handle.size() == 0) {  // Clean up empty sets
   1035                 global_release_barriers.erase(set_it);
   1036             }
   1037         }
   1038     }
   1039 }
   1040 
   1041 void CoreChecks::RecordQueuedQFOTransfers(layer_data *device_data, GLOBAL_CB_NODE *cb_state) {
   1042     RecordQueuedQFOTransferBarriers<VkImageMemoryBarrier>(device_data, cb_state);
   1043     RecordQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(device_data, cb_state);
   1044 }
   1045 
   1046 // Avoid making the template globally visible by exporting the one instance of it we need.
   1047 void CoreChecks::EraseQFOImageRelaseBarriers(layer_data *device_data, const VkImage &image) {
   1048     EraseQFOReleaseBarriers<VkImageMemoryBarrier>(device_data, image);
   1049 }
   1050 
   1051 void CoreChecks::TransitionImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *cb_state, uint32_t memBarrierCount,
   1052                                         const VkImageMemoryBarrier *pImgMemBarriers) {
   1053     for (uint32_t i = 0; i < memBarrierCount; ++i) {
   1054         auto mem_barrier = &pImgMemBarriers[i];
   1055         if (!mem_barrier) continue;
   1056 
   1057         // For ownership transfers, the barrier is specified twice; as a release
   1058         // operation on the yielding queue family, and as an acquire operation
   1059         // on the acquiring queue family. This barrier may also include a layout
   1060         // transition, which occurs 'between' the two operations. For validation
   1061         // purposes it doesn't seem important which side performs the layout
   1062         // transition, but it must not be performed twice. We'll arbitrarily
   1063         // choose to perform it as part of the acquire operation.
   1064         if (IsReleaseOp(cb_state, mem_barrier)) {
   1065             continue;
   1066         }
   1067 
   1068         VkImageCreateInfo *image_create_info = &(GetImageState(mem_barrier->image)->createInfo);
   1069         uint32_t level_count = ResolveRemainingLevels(&mem_barrier->subresourceRange, image_create_info->mipLevels);
   1070         uint32_t layer_count = ResolveRemainingLayers(&mem_barrier->subresourceRange, image_create_info->arrayLayers);
   1071 
   1072         // Special case for 3D images with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR flag bit, where <extent.depth> and
   1073         // <arrayLayers> can potentially alias. When recording layout for the entire image, pre-emptively record layouts
   1074         // for all (potential) layer sub_resources.
   1075         if ((0 != (image_create_info->flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) &&
   1076             (mem_barrier->subresourceRange.baseArrayLayer == 0) && (layer_count == 1)) {
   1077             layer_count = image_create_info->extent.depth;  // Treat each depth slice as a layer subresource
   1078         }
   1079 
   1080         // For multiplanar formats, IMAGE_ASPECT_COLOR is equivalent to adding the aspect of the individual planes
   1081         VkImageAspectFlags aspect_mask = mem_barrier->subresourceRange.aspectMask;
   1082         if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
   1083             if (FormatIsMultiplane(image_create_info->format)) {
   1084                 if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
   1085                     aspect_mask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
   1086                     aspect_mask |= (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
   1087                     if (FormatPlaneCount(image_create_info->format) > 2) {
   1088                         aspect_mask |= VK_IMAGE_ASPECT_PLANE_2_BIT;
   1089                     }
   1090                 }
   1091             }
   1092         }
   1093 
   1094         for (uint32_t j = 0; j < level_count; j++) {
   1095             uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
   1096             for (uint32_t k = 0; k < layer_count; k++) {
   1097                 uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
   1098                 TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1099                                             VK_IMAGE_ASPECT_COLOR_BIT);
   1100                 TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1101                                             VK_IMAGE_ASPECT_DEPTH_BIT);
   1102                 TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1103                                             VK_IMAGE_ASPECT_STENCIL_BIT);
   1104                 TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1105                                             VK_IMAGE_ASPECT_METADATA_BIT);
   1106                 if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
   1107                     TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1108                                                 VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
   1109                     TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1110                                                 VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
   1111                     TransitionImageAspectLayout(device_data, cb_state, mem_barrier, level, layer, aspect_mask,
   1112                                                 VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
   1113                 }
   1114             }
   1115         }
   1116     }
   1117 }
   1118 
   1119 bool CoreChecks::VerifyImageLayout(layer_data const *device_data, GLOBAL_CB_NODE const *cb_node, IMAGE_STATE *image_state,
   1120                                    VkImageSubresourceLayers subLayers, VkImageLayout explicit_layout, VkImageLayout optimal_layout,
   1121                                    const char *caller, const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code,
   1122                                    bool *error) {
   1123     const auto image = image_state->image;
   1124     bool skip = false;
   1125 
   1126     for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
   1127         uint32_t layer = i + subLayers.baseArrayLayer;
   1128         VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
   1129         IMAGE_CMD_BUF_LAYOUT_NODE node;
   1130         if (FindCmdBufLayout(device_data, cb_node, image, sub, node)) {
   1131             if (node.layout != explicit_layout) {
   1132                 *error = true;
   1133                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1134                                 HandleToUint64(cb_node->commandBuffer), layout_mismatch_msg_code,
   1135                                 "%s: Cannot use image %s (layer=%u mip=%u) with specific layout %s that doesn't match the actual "
   1136                                 "current layout %s.",
   1137                                 caller, report_data->FormatHandle(image).c_str(), layer, subLayers.mipLevel,
   1138                                 string_VkImageLayout(explicit_layout), string_VkImageLayout(node.layout));
   1139             }
   1140         }
   1141     }
   1142     // If optimal_layout is not UNDEFINED, check that layout matches optimal for this case
   1143     if ((VK_IMAGE_LAYOUT_UNDEFINED != optimal_layout) && (explicit_layout != optimal_layout)) {
   1144         if (VK_IMAGE_LAYOUT_GENERAL == explicit_layout) {
   1145             if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
   1146                 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
   1147                 skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   1148                                 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cb_node->commandBuffer),
   1149                                 kVUID_Core_DrawState_InvalidImageLayout,
   1150                                 "%s: For optimal performance image %s layout should be %s instead of GENERAL.", caller,
   1151                                 report_data->FormatHandle(image).c_str(), string_VkImageLayout(optimal_layout));
   1152             }
   1153         } else if (GetDeviceExtensions()->vk_khr_shared_presentable_image) {
   1154             if (image_state->shared_presentable) {
   1155                 if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != explicit_layout) {
   1156                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1157                                     layout_invalid_msg_code,
   1158                                     "Layout for shared presentable image is %s but must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.",
   1159                                     string_VkImageLayout(optimal_layout));
   1160                 }
   1161             }
   1162         } else {
   1163             *error = true;
   1164             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1165                             HandleToUint64(cb_node->commandBuffer), layout_invalid_msg_code,
   1166                             "%s: Layout for image %s is %s but can only be %s or VK_IMAGE_LAYOUT_GENERAL.", caller,
   1167                             report_data->FormatHandle(image).c_str(), string_VkImageLayout(explicit_layout),
   1168                             string_VkImageLayout(optimal_layout));
   1169         }
   1170     }
   1171     return skip;
   1172 }
   1173 
   1174 void CoreChecks::TransitionFinalSubpassLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB,
   1175                                                const VkRenderPassBeginInfo *pRenderPassBegin,
   1176                                                FRAMEBUFFER_STATE *framebuffer_state) {
   1177     auto renderPass = GetRenderPassState(pRenderPassBegin->renderPass);
   1178     if (!renderPass) return;
   1179 
   1180     const VkRenderPassCreateInfo2KHR *pRenderPassInfo = renderPass->createInfo.ptr();
   1181     if (framebuffer_state) {
   1182         for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
   1183             auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
   1184             if (view_state) {
   1185                 SetImageViewLayout(device_data, pCB, view_state, pRenderPassInfo->pAttachments[i].finalLayout);
   1186             }
   1187         }
   1188     }
   1189 }
   1190 
   1191 #ifdef VK_USE_PLATFORM_ANDROID_KHR
   1192 // Android-specific validation that uses types defined only with VK_USE_PLATFORM_ANDROID_KHR
   1193 // This could also move into a seperate core_validation_android.cpp file... ?
   1194 
   1195 //
   1196 // AHB-specific validation within non-AHB APIs
   1197 //
   1198 bool CoreChecks::ValidateCreateImageANDROID(layer_data *device_data, const debug_report_data *report_data,
   1199                                             const VkImageCreateInfo *create_info) {
   1200     bool skip = false;
   1201 
   1202     const VkExternalFormatANDROID *ext_fmt_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
   1203     if (ext_fmt_android) {
   1204         if (0 != ext_fmt_android->externalFormat) {
   1205             if (VK_FORMAT_UNDEFINED != create_info->format) {
   1206                 skip |=
   1207                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1208                             "VUID-VkImageCreateInfo-pNext-01974",
   1209                             "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with non-zero "
   1210                             "externalFormat, but the VkImageCreateInfo's format is not VK_FORMAT_UNDEFINED.");
   1211             }
   1212 
   1213             if (0 != (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT & create_info->flags)) {
   1214                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1215                                 "VUID-VkImageCreateInfo-pNext-02396",
   1216                                 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
   1217                                 "non-zero externalFormat, but flags include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
   1218             }
   1219 
   1220             if (0 != (~VK_IMAGE_USAGE_SAMPLED_BIT & create_info->usage)) {
   1221                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1222                                 "VUID-VkImageCreateInfo-pNext-02397",
   1223                                 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
   1224                                 "non-zero externalFormat, but usage includes bits other than VK_IMAGE_USAGE_SAMPLED_BIT.");
   1225             }
   1226 
   1227             if (VK_IMAGE_TILING_OPTIMAL != create_info->tiling) {
   1228                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1229                                 "VUID-VkImageCreateInfo-pNext-02398",
   1230                                 "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
   1231                                 "non-zero externalFormat, but layout is not VK_IMAGE_TILING_OPTIMAL.");
   1232             }
   1233         }
   1234 
   1235         auto ahb_formats = GetAHBExternalFormatsSet();
   1236         if ((0 != ext_fmt_android->externalFormat) && (0 == ahb_formats->count(ext_fmt_android->externalFormat))) {
   1237             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1238                             "VUID-VkExternalFormatANDROID-externalFormat-01894",
   1239                             "vkCreateImage(): Chained VkExternalFormatANDROID struct contains a non-zero externalFormat which has "
   1240                             "not been previously retrieved by vkGetAndroidHardwareBufferPropertiesANDROID().");
   1241         }
   1242     }
   1243 
   1244     if ((nullptr == ext_fmt_android) || (0 == ext_fmt_android->externalFormat)) {
   1245         if (VK_FORMAT_UNDEFINED == create_info->format) {
   1246             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1247                             "VUID-VkImageCreateInfo-pNext-01975",
   1248                             "vkCreateImage(): VkImageCreateInfo struct's format is VK_FORMAT_UNDEFINED, but either does not have a "
   1249                             "chained VkExternalFormatANDROID struct or the struct exists but has an externalFormat of 0.");
   1250         }
   1251     }
   1252 
   1253     const VkExternalMemoryImageCreateInfo *emici = lvl_find_in_chain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
   1254     if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
   1255         if (create_info->imageType != VK_IMAGE_TYPE_2D) {
   1256             skip |=
   1257                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1258                         "VUID-VkImageCreateInfo-pNext-02393",
   1259                         "vkCreateImage(): VkImageCreateInfo struct with imageType %s has chained VkExternalMemoryImageCreateInfo "
   1260                         "struct with handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
   1261                         string_VkImageType(create_info->imageType));
   1262         }
   1263 
   1264         if ((create_info->mipLevels != 1) && (create_info->mipLevels != FullMipChainLevels(create_info->extent))) {
   1265             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1266                             "VUID-VkImageCreateInfo-pNext-02394",
   1267                             "vkCreateImage(): VkImageCreateInfo struct with chained VkExternalMemoryImageCreateInfo struct of "
   1268                             "handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID "
   1269                             "specifies mipLevels = %" PRId32 " (full chain mipLevels are %" PRId32 ").",
   1270                             create_info->mipLevels, FullMipChainLevels(create_info->extent));
   1271         }
   1272     }
   1273 
   1274     return skip;
   1275 }
   1276 
   1277 void CoreChecks::RecordCreateImageANDROID(const VkImageCreateInfo *create_info, IMAGE_STATE *is_node) {
   1278     const VkExternalMemoryImageCreateInfo *emici = lvl_find_in_chain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
   1279     if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
   1280         is_node->imported_ahb = true;
   1281     }
   1282     const VkExternalFormatANDROID *ext_fmt_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
   1283     if (ext_fmt_android && (0 != ext_fmt_android->externalFormat)) {
   1284         is_node->has_ahb_format = true;
   1285         is_node->ahb_format = ext_fmt_android->externalFormat;
   1286     }
   1287 }
   1288 
   1289 bool CoreChecks::ValidateCreateImageViewANDROID(layer_data *device_data, const VkImageViewCreateInfo *create_info) {
   1290     bool skip = false;
   1291     IMAGE_STATE *image_state = GetImageState(create_info->image);
   1292 
   1293     if (image_state->has_ahb_format) {
   1294         if (VK_FORMAT_UNDEFINED != create_info->format) {
   1295             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1296                             HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02399",
   1297                             "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
   1298                             "format member is %s.",
   1299                             string_VkFormat(create_info->format));
   1300         }
   1301 
   1302         // Chain must include a compatible ycbcr conversion
   1303         bool conv_found = false;
   1304         uint64_t external_format = 0;
   1305         const VkSamplerYcbcrConversionInfo *ycbcr_conv_info = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info->pNext);
   1306         if (ycbcr_conv_info != nullptr) {
   1307             VkSamplerYcbcrConversion conv_handle = ycbcr_conv_info->conversion;
   1308             auto fmap = GetYcbcrConversionFormatMap();
   1309             if (fmap->find(conv_handle) != fmap->end()) {
   1310                 conv_found = true;
   1311                 external_format = fmap->at(conv_handle);
   1312             }
   1313         }
   1314         if ((!conv_found) || (external_format != image_state->ahb_format)) {
   1315             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1316                             HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02400",
   1317                             "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
   1318                             "without a chained VkSamplerYcbcrConversionInfo struct with the same external format.");
   1319         }
   1320 
   1321         // Errors in create_info swizzles
   1322         if ((create_info->components.r != VK_COMPONENT_SWIZZLE_IDENTITY) ||
   1323             (create_info->components.g != VK_COMPONENT_SWIZZLE_IDENTITY) ||
   1324             (create_info->components.b != VK_COMPONENT_SWIZZLE_IDENTITY) ||
   1325             (create_info->components.a != VK_COMPONENT_SWIZZLE_IDENTITY)) {
   1326             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1327                             HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02401",
   1328                             "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
   1329                             "includes one or more non-identity component swizzles.");
   1330         }
   1331     }
   1332 
   1333     return skip;
   1334 }
   1335 
   1336 bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(layer_data *device_data, const VkImage image) {
   1337     bool skip = false;
   1338 
   1339     IMAGE_STATE *image_state = GetImageState(image);
   1340     if (image_state->imported_ahb && (0 == image_state->GetBoundMemory().size())) {
   1341         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
   1342                         "VUID-vkGetImageSubresourceLayout-image-01895",
   1343                         "vkGetImageSubresourceLayout(): Attempt to query layout from an image created with "
   1344                         "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType which has not yet been "
   1345                         "bound to memory.");
   1346     }
   1347     return skip;
   1348 }
   1349 
   1350 #else
   1351 
   1352 bool CoreChecks::ValidateCreateImageANDROID(layer_data *device_data, const debug_report_data *report_data,
   1353                                             const VkImageCreateInfo *create_info) {
   1354     return false;
   1355 }
   1356 
   1357 void CoreChecks::RecordCreateImageANDROID(const VkImageCreateInfo *create_info, IMAGE_STATE *is_node) {}
   1358 
   1359 bool CoreChecks::ValidateCreateImageViewANDROID(layer_data *device_data, const VkImageViewCreateInfo *create_info) { return false; }
   1360 
   1361 bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(layer_data *device_data, const VkImage image) { return false; }
   1362 
   1363 #endif  // VK_USE_PLATFORM_ANDROID_KHR
   1364 
   1365 bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
   1366                                             const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
   1367     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   1368     bool skip = false;
   1369 
   1370     if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
   1371         skip |= ValidateCreateImageANDROID(device_data, report_data, pCreateInfo);
   1372     } else {  // These checks are omitted or replaced when Android HW Buffer extension is active
   1373         if (pCreateInfo->format == VK_FORMAT_UNDEFINED) {
   1374             return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1375                            "VUID-VkImageCreateInfo-format-00943",
   1376                            "vkCreateImage(): VkFormat for image must not be VK_FORMAT_UNDEFINED.");
   1377         }
   1378     }
   1379 
   1380     if ((pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && (VK_IMAGE_TYPE_2D != pCreateInfo->imageType)) {
   1381         skip |= log_msg(
   1382             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1383             "VUID-VkImageCreateInfo-flags-00949",
   1384             "vkCreateImage(): Image type must be VK_IMAGE_TYPE_2D when VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT flag bit is set");
   1385     }
   1386 
   1387     const VkPhysicalDeviceLimits *device_limits = &(GetPDProperties()->limits);
   1388     VkImageUsageFlags attach_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
   1389                                      VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
   1390     if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.width > device_limits->maxFramebufferWidth)) {
   1391         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1392                         "VUID-VkImageCreateInfo-usage-00964",
   1393                         "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image width exceeds device "
   1394                         "maxFramebufferWidth.");
   1395     }
   1396 
   1397     if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.height > device_limits->maxFramebufferHeight)) {
   1398         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1399                         "VUID-VkImageCreateInfo-usage-00965",
   1400                         "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image height exceeds device "
   1401                         "maxFramebufferHeight");
   1402     }
   1403 
   1404     VkImageFormatProperties format_limits = {};
   1405     VkResult res = GetPDImageFormatProperties(pCreateInfo, &format_limits);
   1406     if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
   1407         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
   1408                         "vkCreateImage(): Format %s is not supported for this combination of parameters.",
   1409                         string_VkFormat(pCreateInfo->format));
   1410     } else {
   1411         if (pCreateInfo->mipLevels > format_limits.maxMipLevels) {
   1412             const char *format_string = string_VkFormat(pCreateInfo->format);
   1413             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1414                             "VUID-VkImageCreateInfo-mipLevels-02255",
   1415                             "vkCreateImage(): Image mip levels=%d exceed image format maxMipLevels=%d for format %s.",
   1416                             pCreateInfo->mipLevels, format_limits.maxMipLevels, format_string);
   1417         }
   1418 
   1419         uint64_t texel_count = (uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height *
   1420                                (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers *
   1421                                (uint64_t)pCreateInfo->samples;
   1422         uint64_t total_size = (uint64_t)std::ceil(FormatTexelSize(pCreateInfo->format) * texel_count);
   1423 
   1424         // Round up to imageGranularity boundary
   1425         VkDeviceSize imageGranularity = GetPDProperties()->limits.bufferImageGranularity;
   1426         uint64_t ig_mask = imageGranularity - 1;
   1427         total_size = (total_size + ig_mask) & ~ig_mask;
   1428 
   1429         if (total_size > format_limits.maxResourceSize) {
   1430             skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
   1431                             kVUID_Core_Image_InvalidFormatLimitsViolation,
   1432                             "vkCreateImage(): resource size exceeds allowable maximum Image resource size = 0x%" PRIxLEAST64
   1433                             ", maximum resource size = 0x%" PRIxLEAST64 " ",
   1434                             total_size, format_limits.maxResourceSize);
   1435         }
   1436 
   1437         if (pCreateInfo->arrayLayers > format_limits.maxArrayLayers) {
   1438             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
   1439                             "VUID-VkImageCreateInfo-arrayLayers-02256",
   1440                             "vkCreateImage(): arrayLayers=%d exceeds allowable maximum supported by format of %d.",
   1441                             pCreateInfo->arrayLayers, format_limits.maxArrayLayers);
   1442         }
   1443 
   1444         if ((pCreateInfo->samples & format_limits.sampleCounts) == 0) {
   1445             skip |=
   1446                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
   1447                         "VUID-VkImageCreateInfo-samples-02258", "vkCreateImage(): samples %s is not supported by format 0x%.8X.",
   1448                         string_VkSampleCountFlagBits(pCreateInfo->samples), format_limits.sampleCounts);
   1449         }
   1450     }
   1451 
   1452     if ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) && (!GetEnabledFeatures()->core.sparseResidencyAliased)) {
   1453         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   1454                         "VUID-VkImageCreateInfo-flags-01924",
   1455                         "vkCreateImage(): the sparseResidencyAliased device feature is disabled: Images cannot be created with the "
   1456                         "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT set.");
   1457     }
   1458 
   1459     if (GetDeviceExtensions()->vk_khr_maintenance2) {
   1460         if (pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR) {
   1461             if (!(FormatIsCompressed_BC(pCreateInfo->format) || FormatIsCompressed_ASTC_LDR(pCreateInfo->format) ||
   1462                   FormatIsCompressed_ETC2_EAC(pCreateInfo->format))) {
   1463                 // TODO: Add Maintenance2 VUID
   1464                 skip |=
   1465                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
   1466                             "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR, "
   1467                             "format must be block, ETC or ASTC compressed, but is %s",
   1468                             string_VkFormat(pCreateInfo->format));
   1469             }
   1470             if (!(pCreateInfo->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) {
   1471                 // TODO: Add Maintenance2 VUID
   1472                 skip |=
   1473                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
   1474                             "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR, "
   1475                             "flags must also contain VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
   1476             }
   1477         }
   1478     }
   1479 
   1480     if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
   1481         skip |=
   1482             ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
   1483                                   "vkCreateImage", "pCreateInfo->pQueueFamilyIndices", "VUID-VkImageCreateInfo-sharingMode-01420",
   1484                                   "VUID-VkImageCreateInfo-sharingMode-01420", false);
   1485     }
   1486 
   1487     return skip;
   1488 }
   1489 
   1490 void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
   1491                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) {
   1492     if (VK_SUCCESS != result) return;
   1493     IMAGE_LAYOUT_NODE image_state;
   1494     image_state.layout = pCreateInfo->initialLayout;
   1495     image_state.format = pCreateInfo->format;
   1496     IMAGE_STATE *is_node = new IMAGE_STATE(*pImage, pCreateInfo);
   1497     if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
   1498         RecordCreateImageANDROID(pCreateInfo, is_node);
   1499     }
   1500     GetImageMap()->insert(std::make_pair(*pImage, std::unique_ptr<IMAGE_STATE>(is_node)));
   1501     ImageSubresourcePair subpair{*pImage, false, VkImageSubresource()};
   1502     (*GetImageSubresourceMap())[*pImage].push_back(subpair);
   1503     (*GetImageLayoutMap())[subpair] = image_state;
   1504 }
   1505 
   1506 bool CoreChecks::PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
   1507     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   1508     IMAGE_STATE *image_state = GetImageState(image);
   1509     const VK_OBJECT obj_struct = {HandleToUint64(image), kVulkanObjectTypeImage};
   1510     bool skip = false;
   1511     if (image_state) {
   1512         skip |= ValidateObjectNotInUse(device_data, image_state, obj_struct, "vkDestroyImage", "VUID-vkDestroyImage-image-01000");
   1513     }
   1514     return skip;
   1515 }
   1516 
   1517 void CoreChecks::PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
   1518     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   1519     if (!image) return;
   1520     IMAGE_STATE *image_state = GetImageState(image);
   1521     VK_OBJECT obj_struct = {HandleToUint64(image), kVulkanObjectTypeImage};
   1522     InvalidateCommandBuffers(device_data, image_state->cb_bindings, obj_struct);
   1523     // Clean up memory mapping, bindings and range references for image
   1524     for (auto mem_binding : image_state->GetBoundMemory()) {
   1525         auto mem_info = GetMemObjInfo(mem_binding);
   1526         if (mem_info) {
   1527             RemoveImageMemoryRange(obj_struct.handle, mem_info);
   1528         }
   1529     }
   1530     ClearMemoryObjectBindings(obj_struct.handle, kVulkanObjectTypeImage);
   1531     EraseQFOReleaseBarriers<VkImageMemoryBarrier>(device_data, image);
   1532     // Remove image from imageMap
   1533     GetImageMap()->erase(image);
   1534     std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> *imageSubresourceMap = GetImageSubresourceMap();
   1535 
   1536     const auto &sub_entry = imageSubresourceMap->find(image);
   1537     if (sub_entry != imageSubresourceMap->end()) {
   1538         for (const auto &pair : sub_entry->second) {
   1539             GetImageLayoutMap()->erase(pair);
   1540         }
   1541         imageSubresourceMap->erase(sub_entry);
   1542     }
   1543 }
   1544 
   1545 bool CoreChecks::ValidateImageAttributes(layer_data *device_data, IMAGE_STATE *image_state, VkImageSubresourceRange range) {
   1546     bool skip = false;
   1547 
   1548     if (range.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
   1549         char const str[] = "vkCmdClearColorImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_COLOR_BIT";
   1550         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1551                         HandleToUint64(image_state->image), kVUID_Core_DrawState_InvalidImageAspect, str);
   1552     }
   1553 
   1554     if (FormatIsDepthOrStencil(image_state->createInfo.format)) {
   1555         char const str[] = "vkCmdClearColorImage called with depth/stencil image.";
   1556         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1557                         HandleToUint64(image_state->image), "VUID-vkCmdClearColorImage-image-00007", "%s.", str);
   1558     } else if (FormatIsCompressed(image_state->createInfo.format)) {
   1559         char const str[] = "vkCmdClearColorImage called with compressed image.";
   1560         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1561                         HandleToUint64(image_state->image), "VUID-vkCmdClearColorImage-image-00007", "%s.", str);
   1562     }
   1563 
   1564     if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
   1565         char const str[] = "vkCmdClearColorImage called with image created without VK_IMAGE_USAGE_TRANSFER_DST_BIT.";
   1566         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1567                         HandleToUint64(image_state->image), "VUID-vkCmdClearColorImage-image-00002", "%s.", str);
   1568     }
   1569     return skip;
   1570 }
   1571 
   1572 uint32_t ResolveRemainingLevels(const VkImageSubresourceRange *range, uint32_t mip_levels) {
   1573     // Return correct number of mip levels taking into account VK_REMAINING_MIP_LEVELS
   1574     uint32_t mip_level_count = range->levelCount;
   1575     if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
   1576         mip_level_count = mip_levels - range->baseMipLevel;
   1577     }
   1578     return mip_level_count;
   1579 }
   1580 
   1581 uint32_t ResolveRemainingLayers(const VkImageSubresourceRange *range, uint32_t layers) {
   1582     // Return correct number of layers taking into account VK_REMAINING_ARRAY_LAYERS
   1583     uint32_t array_layer_count = range->layerCount;
   1584     if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
   1585         array_layer_count = layers - range->baseArrayLayer;
   1586     }
   1587     return array_layer_count;
   1588 }
   1589 
   1590 bool CoreChecks::VerifyClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, IMAGE_STATE *image_state,
   1591                                         VkImageSubresourceRange range, VkImageLayout dest_image_layout, const char *func_name) {
   1592     bool skip = false;
   1593 
   1594     uint32_t level_count = ResolveRemainingLevels(&range, image_state->createInfo.mipLevels);
   1595     uint32_t layer_count = ResolveRemainingLayers(&range, image_state->createInfo.arrayLayers);
   1596 
   1597     if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
   1598         if (dest_image_layout == VK_IMAGE_LAYOUT_GENERAL) {
   1599             if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
   1600                 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
   1601                 skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1602                                 HandleToUint64(image_state->image), kVUID_Core_DrawState_InvalidImageLayout,
   1603                                 "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name);
   1604             }
   1605         } else if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR == dest_image_layout) {
   1606             if (!GetDeviceExtensions()->vk_khr_shared_presentable_image) {
   1607                 // TODO: Add unique error id when available.
   1608                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1609                                 HandleToUint64(image_state->image), 0,
   1610                                 "Must enable VK_KHR_shared_presentable_image extension before creating images with a layout type "
   1611                                 "of VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.");
   1612 
   1613             } else {
   1614                 if (image_state->shared_presentable) {
   1615                     skip |= log_msg(
   1616                         report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1617                         HandleToUint64(image_state->image), 0,
   1618                         "Layout for shared presentable cleared image is %s but can only be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.",
   1619                         string_VkImageLayout(dest_image_layout));
   1620                 }
   1621             }
   1622         } else {
   1623             const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00005";
   1624             if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
   1625                 error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00012";
   1626             } else {
   1627                 assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
   1628             }
   1629             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1630                             HandleToUint64(image_state->image), error_code,
   1631                             "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL.", func_name,
   1632                             string_VkImageLayout(dest_image_layout));
   1633         }
   1634     }
   1635 
   1636     for (uint32_t level_index = 0; level_index < level_count; ++level_index) {
   1637         uint32_t level = level_index + range.baseMipLevel;
   1638         for (uint32_t layer_index = 0; layer_index < layer_count; ++layer_index) {
   1639             uint32_t layer = layer_index + range.baseArrayLayer;
   1640             VkImageSubresource sub = {range.aspectMask, level, layer};
   1641             IMAGE_CMD_BUF_LAYOUT_NODE node;
   1642             if (FindCmdBufLayout(device_data, cb_node, image_state->image, sub, node)) {
   1643                 if (node.layout != dest_image_layout) {
   1644                     const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
   1645                     if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
   1646                         error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
   1647                     } else {
   1648                         assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
   1649                     }
   1650                     skip |=
   1651                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
   1652                                 error_code, "%s: Cannot clear an image whose layout is %s and doesn't match the current layout %s.",
   1653                                 func_name, string_VkImageLayout(dest_image_layout), string_VkImageLayout(node.layout));
   1654                 }
   1655             }
   1656         }
   1657     }
   1658 
   1659     return skip;
   1660 }
   1661 
   1662 void CoreChecks::RecordClearImageLayout(layer_data *device_data, GLOBAL_CB_NODE *cb_node, VkImage image,
   1663                                         VkImageSubresourceRange range, VkImageLayout dest_image_layout) {
   1664     VkImageCreateInfo *image_create_info = &(GetImageState(image)->createInfo);
   1665     uint32_t level_count = ResolveRemainingLevels(&range, image_create_info->mipLevels);
   1666     uint32_t layer_count = ResolveRemainingLayers(&range, image_create_info->arrayLayers);
   1667 
   1668     for (uint32_t level_index = 0; level_index < level_count; ++level_index) {
   1669         uint32_t level = level_index + range.baseMipLevel;
   1670         for (uint32_t layer_index = 0; layer_index < layer_count; ++layer_index) {
   1671             uint32_t layer = layer_index + range.baseArrayLayer;
   1672             VkImageSubresource sub = {range.aspectMask, level, layer};
   1673             IMAGE_CMD_BUF_LAYOUT_NODE node;
   1674             if (!FindCmdBufLayout(device_data, cb_node, image, sub, node)) {
   1675                 SetLayout(device_data, cb_node, image, sub, IMAGE_CMD_BUF_LAYOUT_NODE(dest_image_layout, dest_image_layout));
   1676             }
   1677         }
   1678     }
   1679 }
   1680 
   1681 bool CoreChecks::PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
   1682                                                    const VkClearColorValue *pColor, uint32_t rangeCount,
   1683                                                    const VkImageSubresourceRange *pRanges) {
   1684     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   1685 
   1686     bool skip = false;
   1687     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
   1688     auto cb_node = GetCBNode(commandBuffer);
   1689     auto image_state = GetImageState(image);
   1690     if (cb_node && image_state) {
   1691         skip |= ValidateMemoryIsBoundToImage(device_data, image_state, "vkCmdClearColorImage()",
   1692                                              "VUID-vkCmdClearColorImage-image-00003");
   1693         skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdClearColorImage()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
   1694                                       "VUID-vkCmdClearColorImage-commandBuffer-cmdpool");
   1695         skip |= ValidateCmd(device_data, cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
   1696         if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
   1697             skip |= ValidateImageFormatFeatureFlags(device_data, image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
   1698                                                     "vkCmdClearColorImage", "VUID-vkCmdClearColorImage-image-01993",
   1699                                                     "VUID-vkCmdClearColorImage-image-01993");
   1700         }
   1701         skip |= InsideRenderPass(device_data, cb_node, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-renderpass");
   1702         for (uint32_t i = 0; i < rangeCount; ++i) {
   1703             std::string param_name = "pRanges[" + std::to_string(i) + "]";
   1704             skip |= ValidateCmdClearColorSubresourceRange(device_data, image_state, pRanges[i], param_name.c_str());
   1705             skip |= ValidateImageAttributes(device_data, image_state, pRanges[i]);
   1706             skip |= VerifyClearImageLayout(device_data, cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearColorImage()");
   1707         }
   1708     }
   1709     return skip;
   1710 }
   1711 
   1712 void CoreChecks::PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
   1713                                                  const VkClearColorValue *pColor, uint32_t rangeCount,
   1714                                                  const VkImageSubresourceRange *pRanges) {
   1715     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   1716 
   1717     auto cb_node = GetCBNode(commandBuffer);
   1718     auto image_state = GetImageState(image);
   1719     if (cb_node && image_state) {
   1720         AddCommandBufferBindingImage(device_data, cb_node, image_state);
   1721         for (uint32_t i = 0; i < rangeCount; ++i) {
   1722             RecordClearImageLayout(device_data, cb_node, image, pRanges[i], imageLayout);
   1723         }
   1724     }
   1725 }
   1726 
   1727 bool CoreChecks::PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
   1728                                                           const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
   1729                                                           const VkImageSubresourceRange *pRanges) {
   1730     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   1731     bool skip = false;
   1732 
   1733     // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
   1734     auto cb_node = GetCBNode(commandBuffer);
   1735     auto image_state = GetImageState(image);
   1736     if (cb_node && image_state) {
   1737         skip |= ValidateMemoryIsBoundToImage(device_data, image_state, "vkCmdClearDepthStencilImage()",
   1738                                              "VUID-vkCmdClearDepthStencilImage-image-00010");
   1739         skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdClearDepthStencilImage()", VK_QUEUE_GRAPHICS_BIT,
   1740                                       "VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool");
   1741         skip |= ValidateCmd(device_data, cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
   1742         if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
   1743             skip |= ValidateImageFormatFeatureFlags(device_data, image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
   1744                                                     "vkCmdClearDepthStencilImage", "VUID-vkCmdClearDepthStencilImage-image-01994",
   1745                                                     "VUID-vkCmdClearDepthStencilImage-image-01994");
   1746         }
   1747         skip |=
   1748             InsideRenderPass(device_data, cb_node, "vkCmdClearDepthStencilImage()", "VUID-vkCmdClearDepthStencilImage-renderpass");
   1749         for (uint32_t i = 0; i < rangeCount; ++i) {
   1750             std::string param_name = "pRanges[" + std::to_string(i) + "]";
   1751             skip |= ValidateCmdClearDepthSubresourceRange(device_data, image_state, pRanges[i], param_name.c_str());
   1752             skip |=
   1753                 VerifyClearImageLayout(device_data, cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
   1754             // Image aspect must be depth or stencil or both
   1755             VkImageAspectFlags valid_aspects = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
   1756             if (((pRanges[i].aspectMask & valid_aspects) == 0) || ((pRanges[i].aspectMask & ~valid_aspects) != 0)) {
   1757                 char const str[] =
   1758                     "vkCmdClearDepthStencilImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_DEPTH_BIT "
   1759                     "and/or VK_IMAGE_ASPECT_STENCIL_BIT";
   1760                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1761                                 HandleToUint64(commandBuffer), kVUID_Core_DrawState_InvalidImageAspect, str);
   1762             }
   1763         }
   1764         if (image_state && !FormatIsDepthOrStencil(image_state->createInfo.format)) {
   1765             char const str[] = "vkCmdClearDepthStencilImage called without a depth/stencil image.";
   1766             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1767                             HandleToUint64(image), "VUID-vkCmdClearDepthStencilImage-image-00014", "%s.", str);
   1768         }
   1769         if (VK_IMAGE_USAGE_TRANSFER_DST_BIT != (VK_IMAGE_USAGE_TRANSFER_DST_BIT & image_state->createInfo.usage)) {
   1770             char const str[] =
   1771                 "vkCmdClearDepthStencilImage() called with an image that was not created with the VK_IMAGE_USAGE_TRANSFER_DST_BIT "
   1772                 "set.";
   1773             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1774                             HandleToUint64(image), "VUID-vkCmdClearDepthStencilImage-image-00009", "%s.", str);
   1775         }
   1776     }
   1777     return skip;
   1778 }
   1779 
   1780 void CoreChecks::PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
   1781                                                         const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
   1782                                                         const VkImageSubresourceRange *pRanges) {
   1783     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   1784 
   1785     auto cb_node = GetCBNode(commandBuffer);
   1786     auto image_state = GetImageState(image);
   1787     if (cb_node && image_state) {
   1788         AddCommandBufferBindingImage(device_data, cb_node, image_state);
   1789         for (uint32_t i = 0; i < rangeCount; ++i) {
   1790             RecordClearImageLayout(device_data, cb_node, image, pRanges[i], imageLayout);
   1791         }
   1792     }
   1793 }
   1794 
   1795 // Returns true if [x, xoffset] and [y, yoffset] overlap
   1796 static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) {
   1797     bool result = false;
   1798     uint32_t intersection_min = std::max(static_cast<uint32_t>(start), static_cast<uint32_t>(end));
   1799     uint32_t intersection_max = std::min(static_cast<uint32_t>(start) + start_offset, static_cast<uint32_t>(end) + end_offset);
   1800 
   1801     if (intersection_max > intersection_min) {
   1802         result = true;
   1803     }
   1804     return result;
   1805 }
   1806 
   1807 // Returns true if source area of first copy region intersects dest area of second region
   1808 // It is assumed that these are copy regions within a single image (otherwise no possibility of collision)
   1809 static bool RegionIntersects(const VkImageCopy *rgn0, const VkImageCopy *rgn1, VkImageType type, bool is_multiplane) {
   1810     bool result = false;
   1811 
   1812     // Separate planes within a multiplane image cannot intersect
   1813     if (is_multiplane && (rgn0->srcSubresource.aspectMask != rgn1->dstSubresource.aspectMask)) {
   1814         return result;
   1815     }
   1816 
   1817     if ((rgn0->srcSubresource.mipLevel == rgn1->dstSubresource.mipLevel) &&
   1818         (RangesIntersect(rgn0->srcSubresource.baseArrayLayer, rgn0->srcSubresource.layerCount, rgn1->dstSubresource.baseArrayLayer,
   1819                          rgn1->dstSubresource.layerCount))) {
   1820         result = true;
   1821         switch (type) {
   1822             case VK_IMAGE_TYPE_3D:
   1823                 result &= RangesIntersect(rgn0->srcOffset.z, rgn0->extent.depth, rgn1->dstOffset.z, rgn1->extent.depth);
   1824                 // fall through
   1825             case VK_IMAGE_TYPE_2D:
   1826                 result &= RangesIntersect(rgn0->srcOffset.y, rgn0->extent.height, rgn1->dstOffset.y, rgn1->extent.height);
   1827                 // fall through
   1828             case VK_IMAGE_TYPE_1D:
   1829                 result &= RangesIntersect(rgn0->srcOffset.x, rgn0->extent.width, rgn1->dstOffset.x, rgn1->extent.width);
   1830                 break;
   1831             default:
   1832                 // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
   1833                 assert(false);
   1834         }
   1835     }
   1836     return result;
   1837 }
   1838 
   1839 // Returns non-zero if offset and extent exceed image extents
   1840 static const uint32_t x_bit = 1;
   1841 static const uint32_t y_bit = 2;
   1842 static const uint32_t z_bit = 4;
   1843 static uint32_t ExceedsBounds(const VkOffset3D *offset, const VkExtent3D *extent, const VkExtent3D *image_extent) {
   1844     uint32_t result = 0;
   1845     // Extents/depths cannot be negative but checks left in for clarity
   1846     if ((offset->z + extent->depth > image_extent->depth) || (offset->z < 0) ||
   1847         ((offset->z + static_cast<int32_t>(extent->depth)) < 0)) {
   1848         result |= z_bit;
   1849     }
   1850     if ((offset->y + extent->height > image_extent->height) || (offset->y < 0) ||
   1851         ((offset->y + static_cast<int32_t>(extent->height)) < 0)) {
   1852         result |= y_bit;
   1853     }
   1854     if ((offset->x + extent->width > image_extent->width) || (offset->x < 0) ||
   1855         ((offset->x + static_cast<int32_t>(extent->width)) < 0)) {
   1856         result |= x_bit;
   1857     }
   1858     return result;
   1859 }
   1860 
   1861 // Test if two VkExtent3D structs are equivalent
   1862 static inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
   1863     bool result = true;
   1864     if ((extent->width != other_extent->width) || (extent->height != other_extent->height) ||
   1865         (extent->depth != other_extent->depth)) {
   1866         result = false;
   1867     }
   1868     return result;
   1869 }
   1870 
   1871 // For image copies between compressed/uncompressed formats, the extent is provided in source image texels
   1872 // Destination image texel extents must be adjusted by block size for the dest validation checks
   1873 VkExtent3D GetAdjustedDestImageExtent(VkFormat src_format, VkFormat dst_format, VkExtent3D extent) {
   1874     VkExtent3D adjusted_extent = extent;
   1875     if ((FormatIsCompressed(src_format) && (!FormatIsCompressed(dst_format)))) {
   1876         VkExtent3D block_size = FormatTexelBlockExtent(src_format);
   1877         adjusted_extent.width /= block_size.width;
   1878         adjusted_extent.height /= block_size.height;
   1879         adjusted_extent.depth /= block_size.depth;
   1880     } else if ((!FormatIsCompressed(src_format) && (FormatIsCompressed(dst_format)))) {
   1881         VkExtent3D block_size = FormatTexelBlockExtent(dst_format);
   1882         adjusted_extent.width *= block_size.width;
   1883         adjusted_extent.height *= block_size.height;
   1884         adjusted_extent.depth *= block_size.depth;
   1885     }
   1886     return adjusted_extent;
   1887 }
   1888 
   1889 // Returns the effective extent of an image subresource, adjusted for mip level and array depth.
   1890 static inline VkExtent3D GetImageSubresourceExtent(const IMAGE_STATE *img, const VkImageSubresourceLayers *subresource) {
   1891     const uint32_t mip = subresource->mipLevel;
   1892 
   1893     // Return zero extent if mip level doesn't exist
   1894     if (mip >= img->createInfo.mipLevels) {
   1895         return VkExtent3D{0, 0, 0};
   1896     }
   1897 
   1898     // Don't allow mip adjustment to create 0 dim, but pass along a 0 if that's what subresource specified
   1899     VkExtent3D extent = img->createInfo.extent;
   1900 
   1901     // If multi-plane, adjust per-plane extent
   1902     if (FormatIsMultiplane(img->createInfo.format)) {
   1903         VkExtent2D divisors = FindMultiplaneExtentDivisors(img->createInfo.format, subresource->aspectMask);
   1904         extent.width /= divisors.width;
   1905         extent.height /= divisors.height;
   1906     }
   1907 
   1908     if (img->createInfo.flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) {
   1909         extent.width = (0 == extent.width ? 0 : std::max(2U, 1 + ((extent.width - 1) >> mip)));
   1910         extent.height = (0 == extent.height ? 0 : std::max(2U, 1 + ((extent.height - 1) >> mip)));
   1911         extent.depth = (0 == extent.depth ? 0 : std::max(2U, 1 + ((extent.depth - 1) >> mip)));
   1912     } else {
   1913         extent.width = (0 == extent.width ? 0 : std::max(1U, extent.width >> mip));
   1914         extent.height = (0 == extent.height ? 0 : std::max(1U, extent.height >> mip));
   1915         extent.depth = (0 == extent.depth ? 0 : std::max(1U, extent.depth >> mip));
   1916     }
   1917 
   1918     // Image arrays have an effective z extent that isn't diminished by mip level
   1919     if (VK_IMAGE_TYPE_3D != img->createInfo.imageType) {
   1920         extent.depth = img->createInfo.arrayLayers;
   1921     }
   1922 
   1923     return extent;
   1924 }
   1925 
   1926 // Test if the extent argument has all dimensions set to 0.
   1927 static inline bool IsExtentAllZeroes(const VkExtent3D *extent) {
   1928     return ((extent->width == 0) && (extent->height == 0) && (extent->depth == 0));
   1929 }
   1930 
   1931 // Test if the extent argument has any dimensions set to 0.
   1932 static inline bool IsExtentSizeZero(const VkExtent3D *extent) {
   1933     return ((extent->width == 0) || (extent->height == 0) || (extent->depth == 0));
   1934 }
   1935 
   1936 // Returns the image transfer granularity for a specific image scaled by compressed block size if necessary.
   1937 VkExtent3D CoreChecks::GetScaledItg(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img) {
   1938     // Default to (0, 0, 0) granularity in case we can't find the real granularity for the physical device.
   1939     VkExtent3D granularity = {0, 0, 0};
   1940     auto pPool = GetCommandPoolNode(cb_node->createInfo.commandPool);
   1941     if (pPool) {
   1942         granularity = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].minImageTransferGranularity;
   1943         if (FormatIsCompressed(img->createInfo.format)) {
   1944             auto block_size = FormatTexelBlockExtent(img->createInfo.format);
   1945             granularity.width *= block_size.width;
   1946             granularity.height *= block_size.height;
   1947         }
   1948     }
   1949     return granularity;
   1950 }
   1951 
   1952 // Test elements of a VkExtent3D structure against alignment constraints contained in another VkExtent3D structure
   1953 static inline bool IsExtentAligned(const VkExtent3D *extent, const VkExtent3D *granularity) {
   1954     bool valid = true;
   1955     if ((SafeModulo(extent->depth, granularity->depth) != 0) || (SafeModulo(extent->width, granularity->width) != 0) ||
   1956         (SafeModulo(extent->height, granularity->height) != 0)) {
   1957         valid = false;
   1958     }
   1959     return valid;
   1960 }
   1961 
   1962 // Check elements of a VkOffset3D structure against a queue family's Image Transfer Granularity values
   1963 bool CoreChecks::CheckItgOffset(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const VkOffset3D *offset,
   1964                                 const VkExtent3D *granularity, const uint32_t i, const char *function, const char *member,
   1965                                 const char *vuid) {
   1966     bool skip = false;
   1967     VkExtent3D offset_extent = {};
   1968     offset_extent.width = static_cast<uint32_t>(abs(offset->x));
   1969     offset_extent.height = static_cast<uint32_t>(abs(offset->y));
   1970     offset_extent.depth = static_cast<uint32_t>(abs(offset->z));
   1971     if (IsExtentAllZeroes(granularity)) {
   1972         // If the queue family image transfer granularity is (0, 0, 0), then the offset must always be (0, 0, 0)
   1973         if (IsExtentAllZeroes(&offset_extent) == false) {
   1974             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1975                             HandleToUint64(cb_node->commandBuffer), vuid,
   1976                             "%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 "
   1977                             "image transfer granularity is (w=0, h=0, d=0).",
   1978                             function, i, member, offset->x, offset->y, offset->z);
   1979         }
   1980     } else {
   1981         // If the queue family image transfer granularity is not (0, 0, 0), then the offset dimensions must always be even
   1982         // integer multiples of the image transfer granularity.
   1983         if (IsExtentAligned(&offset_extent, granularity) == false) {
   1984             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1985                             HandleToUint64(cb_node->commandBuffer), vuid,
   1986                             "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) dimensions must be even integer multiples of this command "
   1987                             "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d).",
   1988                             function, i, member, offset->x, offset->y, offset->z, granularity->width, granularity->height,
   1989                             granularity->depth);
   1990         }
   1991     }
   1992     return skip;
   1993 }
   1994 
   1995 // Check elements of a VkExtent3D structure against a queue family's Image Transfer Granularity values
   1996 bool CoreChecks::CheckItgExtent(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const VkExtent3D *extent,
   1997                                 const VkOffset3D *offset, const VkExtent3D *granularity, const VkExtent3D *subresource_extent,
   1998                                 const VkImageType image_type, const uint32_t i, const char *function, const char *member,
   1999                                 const char *vuid) {
   2000     bool skip = false;
   2001     if (IsExtentAllZeroes(granularity)) {
   2002         // If the queue family image transfer granularity is (0, 0, 0), then the extent must always match the image
   2003         // subresource extent.
   2004         if (IsExtentEqual(extent, subresource_extent) == false) {
   2005             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2006                             HandleToUint64(cb_node->commandBuffer), vuid,
   2007                             "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d) "
   2008                             "when the command buffer's queue family image transfer granularity is (w=0, h=0, d=0).",
   2009                             function, i, member, extent->width, extent->height, extent->depth, subresource_extent->width,
   2010                             subresource_extent->height, subresource_extent->depth);
   2011         }
   2012     } else {
   2013         // If the queue family image transfer granularity is not (0, 0, 0), then the extent dimensions must always be even
   2014         // integer multiples of the image transfer granularity or the offset + extent dimensions must always match the image
   2015         // subresource extent dimensions.
   2016         VkExtent3D offset_extent_sum = {};
   2017         offset_extent_sum.width = static_cast<uint32_t>(abs(offset->x)) + extent->width;
   2018         offset_extent_sum.height = static_cast<uint32_t>(abs(offset->y)) + extent->height;
   2019         offset_extent_sum.depth = static_cast<uint32_t>(abs(offset->z)) + extent->depth;
   2020         bool x_ok = true;
   2021         bool y_ok = true;
   2022         bool z_ok = true;
   2023         switch (image_type) {
   2024             case VK_IMAGE_TYPE_3D:
   2025                 z_ok = ((0 == SafeModulo(extent->depth, granularity->depth)) ||
   2026                         (subresource_extent->depth == offset_extent_sum.depth));
   2027                 // fall through
   2028             case VK_IMAGE_TYPE_2D:
   2029                 y_ok = ((0 == SafeModulo(extent->height, granularity->height)) ||
   2030                         (subresource_extent->height == offset_extent_sum.height));
   2031                 // fall through
   2032             case VK_IMAGE_TYPE_1D:
   2033                 x_ok = ((0 == SafeModulo(extent->width, granularity->width)) ||
   2034                         (subresource_extent->width == offset_extent_sum.width));
   2035                 break;
   2036             default:
   2037                 // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
   2038                 assert(false);
   2039         }
   2040         if (!(x_ok && y_ok && z_ok)) {
   2041             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2042                             HandleToUint64(cb_node->commandBuffer), vuid,
   2043                             "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) dimensions must be even integer multiples of this command "
   2044                             "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d) or offset (x=%d, y=%d, z=%d) + "
   2045                             "extent (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d).",
   2046                             function, i, member, extent->width, extent->height, extent->depth, granularity->width,
   2047                             granularity->height, granularity->depth, offset->x, offset->y, offset->z, extent->width, extent->height,
   2048                             extent->depth, subresource_extent->width, subresource_extent->height, subresource_extent->depth);
   2049         }
   2050     }
   2051     return skip;
   2052 }
   2053 
   2054 bool CoreChecks::ValidateImageMipLevel(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img,
   2055                                        uint32_t mip_level, const uint32_t i, const char *function, const char *member,
   2056                                        const char *vuid) {
   2057     bool skip = false;
   2058     if (mip_level >= img->createInfo.mipLevels) {
   2059         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2060                         HandleToUint64(cb_node->commandBuffer), vuid,
   2061                         "In %s, pRegions[%u].%s.mipLevel is %u, but provided image %s has %u mip levels.", function, i, member,
   2062                         mip_level, report_data->FormatHandle(img->image).c_str(), img->createInfo.mipLevels);
   2063     }
   2064     return skip;
   2065 }
   2066 
   2067 bool CoreChecks::ValidateImageArrayLayerRange(layer_data *device_data, const GLOBAL_CB_NODE *cb_node, const IMAGE_STATE *img,
   2068                                               const uint32_t base_layer, const uint32_t layer_count, const uint32_t i,
   2069                                               const char *function, const char *member, const char *vuid) {
   2070     bool skip = false;
   2071     if (base_layer >= img->createInfo.arrayLayers || layer_count > img->createInfo.arrayLayers ||
   2072         (base_layer + layer_count) > img->createInfo.arrayLayers) {
   2073         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2074                         HandleToUint64(cb_node->commandBuffer), vuid,
   2075                         "In %s, pRegions[%u].%s.baseArrayLayer is %u and .layerCount is "
   2076                         "%u, but provided image %s has %u array layers.",
   2077                         function, i, member, base_layer, layer_count, report_data->FormatHandle(img->image).c_str(),
   2078                         img->createInfo.arrayLayers);
   2079     }
   2080     return skip;
   2081 }
   2082 
   2083 // Check valid usage Image Transfer Granularity requirements for elements of a VkBufferImageCopy structure
   2084 bool CoreChecks::ValidateCopyBufferImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
   2085                                                                         const IMAGE_STATE *img, const VkBufferImageCopy *region,
   2086                                                                         const uint32_t i, const char *function, const char *vuid) {
   2087     bool skip = false;
   2088     VkExtent3D granularity = GetScaledItg(device_data, cb_node, img);
   2089     skip |= CheckItgOffset(device_data, cb_node, &region->imageOffset, &granularity, i, function, "imageOffset", vuid);
   2090     VkExtent3D subresource_extent = GetImageSubresourceExtent(img, &region->imageSubresource);
   2091     skip |= CheckItgExtent(device_data, cb_node, &region->imageExtent, &region->imageOffset, &granularity, &subresource_extent,
   2092                            img->createInfo.imageType, i, function, "imageExtent", vuid);
   2093     return skip;
   2094 }
   2095 
   2096 // Check valid usage Image Transfer Granularity requirements for elements of a VkImageCopy structure
   2097 bool CoreChecks::ValidateCopyImageTransferGranularityRequirements(layer_data *device_data, const GLOBAL_CB_NODE *cb_node,
   2098                                                                   const IMAGE_STATE *src_img, const IMAGE_STATE *dst_img,
   2099                                                                   const VkImageCopy *region, const uint32_t i,
   2100                                                                   const char *function) {
   2101     bool skip = false;
   2102     // Source image checks
   2103     VkExtent3D granularity = GetScaledItg(device_data, cb_node, src_img);
   2104     skip |= CheckItgOffset(device_data, cb_node, &region->srcOffset, &granularity, i, function, "srcOffset",
   2105                            "VUID-vkCmdCopyImage-srcOffset-01783");
   2106     VkExtent3D subresource_extent = GetImageSubresourceExtent(src_img, &region->srcSubresource);
   2107     const VkExtent3D extent = region->extent;
   2108     skip |= CheckItgExtent(device_data, cb_node, &extent, &region->srcOffset, &granularity, &subresource_extent,
   2109                            src_img->createInfo.imageType, i, function, "extent", "VUID-vkCmdCopyImage-srcOffset-01783");
   2110 
   2111     // Destination image checks
   2112     granularity = GetScaledItg(device_data, cb_node, dst_img);
   2113     skip |= CheckItgOffset(device_data, cb_node, &region->dstOffset, &granularity, i, function, "dstOffset",
   2114                            "VUID-vkCmdCopyImage-dstOffset-01784");
   2115     // Adjust dest extent, if necessary
   2116     const VkExtent3D dest_effective_extent =
   2117         GetAdjustedDestImageExtent(src_img->createInfo.format, dst_img->createInfo.format, extent);
   2118     subresource_extent = GetImageSubresourceExtent(dst_img, &region->dstSubresource);
   2119     skip |= CheckItgExtent(device_data, cb_node, &dest_effective_extent, &region->dstOffset, &granularity, &subresource_extent,
   2120                            dst_img->createInfo.imageType, i, function, "extent", "VUID-vkCmdCopyImage-dstOffset-01784");
   2121     return skip;
   2122 }
   2123 
   2124 // Validate contents of a VkImageCopy struct
   2125 bool CoreChecks::ValidateImageCopyData(const layer_data *device_data, const debug_report_data *report_data,
   2126                                        const uint32_t regionCount, const VkImageCopy *ic_regions, const IMAGE_STATE *src_state,
   2127                                        const IMAGE_STATE *dst_state) {
   2128     bool skip = false;
   2129 
   2130     for (uint32_t i = 0; i < regionCount; i++) {
   2131         const VkImageCopy region = ic_regions[i];
   2132 
   2133         // For comp<->uncomp copies, the copy extent for the dest image must be adjusted
   2134         const VkExtent3D src_copy_extent = region.extent;
   2135         const VkExtent3D dst_copy_extent =
   2136             GetAdjustedDestImageExtent(src_state->createInfo.format, dst_state->createInfo.format, region.extent);
   2137 
   2138         bool slice_override = false;
   2139         uint32_t depth_slices = 0;
   2140 
   2141         // Special case for copying between a 1D/2D array and a 3D image
   2142         // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
   2143         if ((VK_IMAGE_TYPE_3D == src_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != dst_state->createInfo.imageType)) {
   2144             depth_slices = region.dstSubresource.layerCount;  // Slice count from 2D subresource
   2145             slice_override = (depth_slices != 1);
   2146         } else if ((VK_IMAGE_TYPE_3D == dst_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != src_state->createInfo.imageType)) {
   2147             depth_slices = region.srcSubresource.layerCount;  // Slice count from 2D subresource
   2148             slice_override = (depth_slices != 1);
   2149         }
   2150 
   2151         // Do all checks on source image
   2152         //
   2153         if (src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
   2154             if ((0 != region.srcOffset.y) || (1 != src_copy_extent.height)) {
   2155                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2156                                 HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-00146",
   2157                                 "vkCmdCopyImage(): pRegion[%d] srcOffset.y is %d and extent.height is %d. For 1D images these must "
   2158                                 "be 0 and 1, respectively.",
   2159                                 i, region.srcOffset.y, src_copy_extent.height);
   2160             }
   2161         }
   2162 
   2163         // VUID-VkImageCopy-srcImage-01785
   2164         if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.srcOffset.z) || (1 != src_copy_extent.depth))) {
   2165             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2166                             HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-01785",
   2167                             "vkCmdCopyImage(): pRegion[%d] srcOffset.z is %d and extent.depth is %d. For 1D images "
   2168                             "these must be 0 and 1, respectively.",
   2169                             i, region.srcOffset.z, src_copy_extent.depth);
   2170         }
   2171 
   2172         // VUID-VkImageCopy-srcImage-01787
   2173         if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.srcOffset.z)) {
   2174             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2175                             HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-01787",
   2176                             "vkCmdCopyImage(): pRegion[%d] srcOffset.z is %d. For 2D images the z-offset must be 0.", i,
   2177                             region.srcOffset.z);
   2178         }
   2179 
   2180         if (GetDeviceExtensions()->vk_khr_maintenance1) {
   2181             if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
   2182                 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
   2183                     skip |=
   2184                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2185                                 HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-00141",
   2186                                 "vkCmdCopyImage(): pRegion[%d] srcSubresource.baseArrayLayer is %d and srcSubresource.layerCount "
   2187                                 "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
   2188                                 i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
   2189                 }
   2190             }
   2191         } else {  // Pre maint 1
   2192             if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D || dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
   2193                 if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
   2194                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2195                                     HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-00141",
   2196                                     "vkCmdCopyImage(): pRegion[%d] srcSubresource.baseArrayLayer is %d and "
   2197                                     "srcSubresource.layerCount is %d. For copies with either source or dest of type "
   2198                                     "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
   2199                                     i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
   2200                 }
   2201             }
   2202         }
   2203 
   2204         // Source checks that apply only to compressed images (or to _422 images if ycbcr enabled)
   2205         bool ext_ycbcr = GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion;
   2206         if (FormatIsCompressed(src_state->createInfo.format) ||
   2207             (ext_ycbcr && FormatIsSinglePlane_422(src_state->createInfo.format))) {
   2208             const VkExtent3D block_size = FormatTexelBlockExtent(src_state->createInfo.format);
   2209             //  image offsets must be multiples of block dimensions
   2210             if ((SafeModulo(region.srcOffset.x, block_size.width) != 0) ||
   2211                 (SafeModulo(region.srcOffset.y, block_size.height) != 0) ||
   2212                 (SafeModulo(region.srcOffset.z, block_size.depth) != 0)) {
   2213                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01727" : "VUID-VkImageCopy-srcOffset-00157";
   2214                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2215                                 HandleToUint64(src_state->image), vuid,
   2216                                 "vkCmdCopyImage(): pRegion[%d] srcOffset (%d, %d) must be multiples of the compressed image's "
   2217                                 "texel width & height (%d, %d).",
   2218                                 i, region.srcOffset.x, region.srcOffset.y, block_size.width, block_size.height);
   2219             }
   2220 
   2221             const VkExtent3D mip_extent = GetImageSubresourceExtent(src_state, &(region.srcSubresource));
   2222             if ((SafeModulo(src_copy_extent.width, block_size.width) != 0) &&
   2223                 (src_copy_extent.width + region.srcOffset.x != mip_extent.width)) {
   2224                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01728" : "VUID-VkImageCopy-extent-00158";
   2225                 skip |=
   2226                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2227                             HandleToUint64(src_state->image), vuid,
   2228                             "vkCmdCopyImage(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
   2229                             "width (%d), or when added to srcOffset.x (%d) must equal the image subresource width (%d).",
   2230                             i, src_copy_extent.width, block_size.width, region.srcOffset.x, mip_extent.width);
   2231             }
   2232 
   2233             // Extent height must be a multiple of block height, or extent+offset height must equal subresource height
   2234             if ((SafeModulo(src_copy_extent.height, block_size.height) != 0) &&
   2235                 (src_copy_extent.height + region.srcOffset.y != mip_extent.height)) {
   2236                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01729" : "VUID-VkImageCopy-extent-00159";
   2237                 skip |=
   2238                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2239                             HandleToUint64(src_state->image), vuid,
   2240                             "vkCmdCopyImage(): pRegion[%d] extent height (%d) must be a multiple of the compressed texture block "
   2241                             "height (%d), or when added to srcOffset.y (%d) must equal the image subresource height (%d).",
   2242                             i, src_copy_extent.height, block_size.height, region.srcOffset.y, mip_extent.height);
   2243             }
   2244 
   2245             // Extent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
   2246             uint32_t copy_depth = (slice_override ? depth_slices : src_copy_extent.depth);
   2247             if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.srcOffset.z != mip_extent.depth)) {
   2248                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01730" : "VUID-VkImageCopy-extent-00160";
   2249                 skip |=
   2250                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2251                             HandleToUint64(src_state->image), vuid,
   2252                             "vkCmdCopyImage(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
   2253                             "depth (%d), or when added to srcOffset.z (%d) must equal the image subresource depth (%d).",
   2254                             i, src_copy_extent.depth, block_size.depth, region.srcOffset.z, mip_extent.depth);
   2255             }
   2256         }  // Compressed
   2257 
   2258         // Do all checks on dest image
   2259         //
   2260         if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
   2261             if ((0 != region.dstOffset.y) || (1 != dst_copy_extent.height)) {
   2262                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2263                                 HandleToUint64(dst_state->image), "VUID-VkImageCopy-dstImage-00152",
   2264                                 "vkCmdCopyImage(): pRegion[%d] dstOffset.y is %d and dst_copy_extent.height is %d. For 1D images "
   2265                                 "these must be 0 and 1, respectively.",
   2266                                 i, region.dstOffset.y, dst_copy_extent.height);
   2267             }
   2268         }
   2269 
   2270         // VUID-VkImageCopy-dstImage-01786
   2271         if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.dstOffset.z) || (1 != dst_copy_extent.depth))) {
   2272             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2273                             HandleToUint64(dst_state->image), "VUID-VkImageCopy-dstImage-01786",
   2274                             "vkCmdCopyImage(): pRegion[%d] dstOffset.z is %d and extent.depth is %d. For 1D images these must be 0 "
   2275                             "and 1, respectively.",
   2276                             i, region.dstOffset.z, dst_copy_extent.depth);
   2277         }
   2278 
   2279         // VUID-VkImageCopy-dstImage-01788
   2280         if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.dstOffset.z)) {
   2281             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2282                             HandleToUint64(dst_state->image), "VUID-VkImageCopy-dstImage-01788",
   2283                             "vkCmdCopyImage(): pRegion[%d] dstOffset.z is %d. For 2D images the z-offset must be 0.", i,
   2284                             region.dstOffset.z);
   2285         }
   2286 
   2287         if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
   2288             if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
   2289                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2290                                 HandleToUint64(dst_state->image), "VUID-VkImageCopy-srcImage-00141",
   2291                                 "vkCmdCopyImage(): pRegion[%d] dstSubresource.baseArrayLayer is %d and dstSubresource.layerCount "
   2292                                 "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
   2293                                 i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
   2294             }
   2295         }
   2296         // VU01199 changed with mnt1
   2297         if (GetDeviceExtensions()->vk_khr_maintenance1) {
   2298             if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
   2299                 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
   2300                     skip |=
   2301                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2302                                 HandleToUint64(dst_state->image), "VUID-VkImageCopy-srcImage-00141",
   2303                                 "vkCmdCopyImage(): pRegion[%d] dstSubresource.baseArrayLayer is %d and dstSubresource.layerCount "
   2304                                 "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
   2305                                 i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
   2306                 }
   2307             }
   2308         } else {  // Pre maint 1
   2309             if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D || dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
   2310                 if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
   2311                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2312                                     HandleToUint64(dst_state->image), "VUID-VkImageCopy-srcImage-00141",
   2313                                     "vkCmdCopyImage(): pRegion[%d] dstSubresource.baseArrayLayer is %d and "
   2314                                     "dstSubresource.layerCount is %d. For copies with either source or dest of type "
   2315                                     "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
   2316                                     i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
   2317                 }
   2318             }
   2319         }
   2320 
   2321         // Dest checks that apply only to compressed images (or to _422 images if ycbcr enabled)
   2322         if (FormatIsCompressed(dst_state->createInfo.format) ||
   2323             (ext_ycbcr && FormatIsSinglePlane_422(dst_state->createInfo.format))) {
   2324             const VkExtent3D block_size = FormatTexelBlockExtent(dst_state->createInfo.format);
   2325 
   2326             //  image offsets must be multiples of block dimensions
   2327             if ((SafeModulo(region.dstOffset.x, block_size.width) != 0) ||
   2328                 (SafeModulo(region.dstOffset.y, block_size.height) != 0) ||
   2329                 (SafeModulo(region.dstOffset.z, block_size.depth) != 0)) {
   2330                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01731" : "VUID-VkImageCopy-dstOffset-00162";
   2331                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2332                                 HandleToUint64(dst_state->image), vuid,
   2333                                 "vkCmdCopyImage(): pRegion[%d] dstOffset (%d, %d) must be multiples of the compressed image's "
   2334                                 "texel width & height (%d, %d).",
   2335                                 i, region.dstOffset.x, region.dstOffset.y, block_size.width, block_size.height);
   2336             }
   2337 
   2338             const VkExtent3D mip_extent = GetImageSubresourceExtent(dst_state, &(region.dstSubresource));
   2339             if ((SafeModulo(dst_copy_extent.width, block_size.width) != 0) &&
   2340                 (dst_copy_extent.width + region.dstOffset.x != mip_extent.width)) {
   2341                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01732" : "VUID-VkImageCopy-extent-00163";
   2342                 skip |=
   2343                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2344                             HandleToUint64(dst_state->image), vuid,
   2345                             "vkCmdCopyImage(): pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
   2346                             "block width (%d), or when added to dstOffset.x (%d) must equal the image subresource width (%d).",
   2347                             i, dst_copy_extent.width, block_size.width, region.dstOffset.x, mip_extent.width);
   2348             }
   2349 
   2350             // Extent height must be a multiple of block height, or dst_copy_extent+offset height must equal subresource height
   2351             if ((SafeModulo(dst_copy_extent.height, block_size.height) != 0) &&
   2352                 (dst_copy_extent.height + region.dstOffset.y != mip_extent.height)) {
   2353                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01733" : "VUID-VkImageCopy-extent-00164";
   2354                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2355                                 HandleToUint64(dst_state->image), vuid,
   2356                                 "vkCmdCopyImage(): pRegion[%d] dst_copy_extent height (%d) must be a multiple of the compressed "
   2357                                 "texture block height (%d), or when added to dstOffset.y (%d) must equal the image subresource "
   2358                                 "height (%d).",
   2359                                 i, dst_copy_extent.height, block_size.height, region.dstOffset.y, mip_extent.height);
   2360             }
   2361 
   2362             // Extent depth must be a multiple of block depth, or dst_copy_extent+offset depth must equal subresource depth
   2363             uint32_t copy_depth = (slice_override ? depth_slices : dst_copy_extent.depth);
   2364             if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.dstOffset.z != mip_extent.depth)) {
   2365                 const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01734" : "VUID-VkImageCopy-extent-00165";
   2366                 skip |=
   2367                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   2368                             HandleToUint64(dst_state->image), vuid,
   2369                             "vkCmdCopyImage(): pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
   2370                             "block depth (%d), or when added to dstOffset.z (%d) must equal the image subresource depth (%d).",
   2371                             i, dst_copy_extent.depth, block_size.depth, region.dstOffset.z, mip_extent.depth);
   2372             }
   2373         }  // Compressed
   2374     }
   2375     return skip;
   2376 }
   2377 
   2378 // vkCmdCopyImage checks that only apply if the multiplane extension is enabled
   2379 bool CoreChecks::CopyImageMultiplaneValidation(const layer_data *dev_data, VkCommandBuffer command_buffer,
   2380                                                const IMAGE_STATE *src_image_state, const IMAGE_STATE *dst_image_state,
   2381                                                const VkImageCopy region) {
   2382     bool skip = false;
   2383 
   2384     // Neither image is multiplane
   2385     if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format))) {
   2386         // If neither image is multi-plane the aspectMask member of src and dst must match
   2387         if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
   2388             std::stringstream ss;
   2389             ss << "vkCmdCopyImage(): Copy between non-multiplane images with differing aspectMasks ( 0x" << std::hex
   2390                << region.srcSubresource.aspectMask << " and 0x" << region.dstSubresource.aspectMask << " )";
   2391             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2392                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01551", "%s.", ss.str().c_str());
   2393         }
   2394     } else {
   2395         // Source image multiplane checks
   2396         uint32_t planes = FormatPlaneCount(src_image_state->createInfo.format);
   2397         VkImageAspectFlags aspect = region.srcSubresource.aspectMask;
   2398         if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) {
   2399             std::stringstream ss;
   2400             ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
   2401             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2402                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01552", "%s.", ss.str().c_str());
   2403         }
   2404         if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) &&
   2405             (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) {
   2406             std::stringstream ss;
   2407             ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
   2408             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2409                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01553", "%s.", ss.str().c_str());
   2410         }
   2411         // Single-plane to multi-plane
   2412         if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (FormatIsMultiplane(dst_image_state->createInfo.format)) &&
   2413             (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
   2414             std::stringstream ss;
   2415             ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
   2416             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2417                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01557", "%s.", ss.str().c_str());
   2418         }
   2419 
   2420         // Dest image multiplane checks
   2421         planes = FormatPlaneCount(dst_image_state->createInfo.format);
   2422         aspect = region.dstSubresource.aspectMask;
   2423         if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) {
   2424             std::stringstream ss;
   2425             ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
   2426             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2427                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01554", "%s.", ss.str().c_str());
   2428         }
   2429         if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) &&
   2430             (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) {
   2431             std::stringstream ss;
   2432             ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
   2433             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2434                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01555", "%s.", ss.str().c_str());
   2435         }
   2436         // Multi-plane to single-plane
   2437         if ((FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format)) &&
   2438             (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
   2439             std::stringstream ss;
   2440             ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
   2441             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2442                             HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01556", "%s.", ss.str().c_str());
   2443         }
   2444     }
   2445 
   2446     return skip;
   2447 }
   2448 
   2449 bool CoreChecks::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   2450                                              VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
   2451                                              const VkImageCopy *pRegions) {
   2452     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   2453     auto cb_node = GetCBNode(commandBuffer);
   2454     auto src_image_state = GetImageState(srcImage);
   2455     auto dst_image_state = GetImageState(dstImage);
   2456     bool skip = false;
   2457 
   2458     skip = ValidateImageCopyData(device_data, report_data, regionCount, pRegions, src_image_state, dst_image_state);
   2459 
   2460     VkCommandBuffer command_buffer = cb_node->commandBuffer;
   2461 
   2462     for (uint32_t i = 0; i < regionCount; i++) {
   2463         const VkImageCopy region = pRegions[i];
   2464 
   2465         // For comp/uncomp copies, the copy extent for the dest image must be adjusted
   2466         VkExtent3D src_copy_extent = region.extent;
   2467         VkExtent3D dst_copy_extent =
   2468             GetAdjustedDestImageExtent(src_image_state->createInfo.format, dst_image_state->createInfo.format, region.extent);
   2469 
   2470         bool slice_override = false;
   2471         uint32_t depth_slices = 0;
   2472 
   2473         // Special case for copying between a 1D/2D array and a 3D image
   2474         // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
   2475         if ((VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType) &&
   2476             (VK_IMAGE_TYPE_3D != dst_image_state->createInfo.imageType)) {
   2477             depth_slices = region.dstSubresource.layerCount;  // Slice count from 2D subresource
   2478             slice_override = (depth_slices != 1);
   2479         } else if ((VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType) &&
   2480                    (VK_IMAGE_TYPE_3D != src_image_state->createInfo.imageType)) {
   2481             depth_slices = region.srcSubresource.layerCount;  // Slice count from 2D subresource
   2482             slice_override = (depth_slices != 1);
   2483         }
   2484 
   2485         skip |= ValidateImageSubresourceLayers(device_data, cb_node, &region.srcSubresource, "vkCmdCopyImage", "srcSubresource", i);
   2486         skip |= ValidateImageSubresourceLayers(device_data, cb_node, &region.dstSubresource, "vkCmdCopyImage", "dstSubresource", i);
   2487         skip |= ValidateImageMipLevel(device_data, cb_node, src_image_state, region.srcSubresource.mipLevel, i, "vkCmdCopyImage",
   2488                                       "srcSubresource", "VUID-vkCmdCopyImage-srcSubresource-01696");
   2489         skip |= ValidateImageMipLevel(device_data, cb_node, dst_image_state, region.dstSubresource.mipLevel, i, "vkCmdCopyImage",
   2490                                       "dstSubresource", "VUID-vkCmdCopyImage-dstSubresource-01697");
   2491         skip |= ValidateImageArrayLayerRange(device_data, cb_node, src_image_state, region.srcSubresource.baseArrayLayer,
   2492                                              region.srcSubresource.layerCount, i, "vkCmdCopyImage", "srcSubresource",
   2493                                              "VUID-vkCmdCopyImage-srcSubresource-01698");
   2494         skip |= ValidateImageArrayLayerRange(device_data, cb_node, dst_image_state, region.dstSubresource.baseArrayLayer,
   2495                                              region.dstSubresource.layerCount, i, "vkCmdCopyImage", "dstSubresource",
   2496                                              "VUID-vkCmdCopyImage-dstSubresource-01699");
   2497 
   2498         if (GetDeviceExtensions()->vk_khr_maintenance1) {
   2499             // No chance of mismatch if we're overriding depth slice count
   2500             if (!slice_override) {
   2501                 // The number of depth slices in srcSubresource and dstSubresource must match
   2502                 // Depth comes from layerCount for 1D,2D resources, from extent.depth for 3D
   2503                 uint32_t src_slices =
   2504                     (VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType ? src_copy_extent.depth
   2505                                                                                : region.srcSubresource.layerCount);
   2506                 uint32_t dst_slices =
   2507                     (VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType ? dst_copy_extent.depth
   2508                                                                                : region.dstSubresource.layerCount);
   2509                 if (src_slices != dst_slices) {
   2510                     std::stringstream ss;
   2511                     ss << "vkCmdCopyImage(): number of depth slices in source and destination subresources for pRegions[" << i
   2512                        << "] do not match";
   2513                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2514                                     HandleToUint64(command_buffer), "VUID-VkImageCopy-extent-00140", "%s.", ss.str().c_str());
   2515                 }
   2516             }
   2517         } else {
   2518             // For each region the layerCount member of srcSubresource and dstSubresource must match
   2519             if (region.srcSubresource.layerCount != region.dstSubresource.layerCount) {
   2520                 std::stringstream ss;
   2521                 ss << "vkCmdCopyImage(): number of layers in source and destination subresources for pRegions[" << i
   2522                    << "] do not match";
   2523                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2524                                 HandleToUint64(command_buffer), "VUID-VkImageCopy-extent-00140", "%s.", ss.str().c_str());
   2525             }
   2526         }
   2527 
   2528         // Do multiplane-specific checks, if extension enabled
   2529         if (GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
   2530             skip |= CopyImageMultiplaneValidation(device_data, command_buffer, src_image_state, dst_image_state, region);
   2531         }
   2532 
   2533         if (!GetDeviceExtensions()->vk_khr_sampler_ycbcr_conversion) {
   2534             // not multi-plane, the aspectMask member of srcSubresource and dstSubresource must match
   2535             if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
   2536                 char const str[] = "vkCmdCopyImage(): Src and dest aspectMasks for each region must match";
   2537                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2538                                 HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00137", "%s.", str);
   2539             }
   2540         }
   2541 
   2542         // For each region, the aspectMask member of srcSubresource must be present in the source image
   2543         if (!VerifyAspectsPresent(region.srcSubresource.aspectMask, src_image_state->createInfo.format)) {
   2544             std::stringstream ss;
   2545             ss << "vkCmdCopyImage(): pRegion[" << i
   2546                << "] srcSubresource.aspectMask cannot specify aspects not present in source image";
   2547             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2548                             HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00142", "%s.", ss.str().c_str());
   2549         }
   2550 
   2551         // For each region, the aspectMask member of dstSubresource must be present in the destination image
   2552         if (!VerifyAspectsPresent(region.dstSubresource.aspectMask, dst_image_state->createInfo.format)) {
   2553             std::stringstream ss;
   2554             ss << "vkCmdCopyImage(): pRegion[" << i
   2555                << "] dstSubresource.aspectMask cannot specify aspects not present in dest image";
   2556             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2557                             HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00143", "%s.", ss.str().c_str());
   2558         }
   2559 
   2560         // Check region extents for 1D-1D, 2D-2D, and 3D-3D copies
   2561         if (src_image_state->createInfo.imageType == dst_image_state->createInfo.imageType) {
   2562             // The source region specified by a given element of regions must be a region that is contained within srcImage
   2563             VkExtent3D img_extent = GetImageSubresourceExtent(src_image_state, &(region.srcSubresource));
   2564             if (0 != ExceedsBounds(&region.srcOffset, &src_copy_extent, &img_extent)) {
   2565                 std::stringstream ss;
   2566                 ss << "vkCmdCopyImage(): Source pRegion[" << i << "] with mipLevel [ " << region.srcSubresource.mipLevel
   2567                    << " ], offset [ " << region.srcOffset.x << ", " << region.srcOffset.y << ", " << region.srcOffset.z
   2568                    << " ], extent [ " << src_copy_extent.width << ", " << src_copy_extent.height << ", " << src_copy_extent.depth
   2569                    << " ] exceeds the source image dimensions";
   2570                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2571                                 HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00122", "%s.", ss.str().c_str());
   2572             }
   2573 
   2574             // The destination region specified by a given element of regions must be a region that is contained within dst_image
   2575             img_extent = GetImageSubresourceExtent(dst_image_state, &(region.dstSubresource));
   2576             if (0 != ExceedsBounds(&region.dstOffset, &dst_copy_extent, &img_extent)) {
   2577                 std::stringstream ss;
   2578                 ss << "vkCmdCopyImage(): Dest pRegion[" << i << "] with mipLevel [ " << region.dstSubresource.mipLevel
   2579                    << " ], offset [ " << region.dstOffset.x << ", " << region.dstOffset.y << ", " << region.dstOffset.z
   2580                    << " ], extent [ " << dst_copy_extent.width << ", " << dst_copy_extent.height << ", " << dst_copy_extent.depth
   2581                    << " ] exceeds the destination image dimensions";
   2582                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2583                                 HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00123", "%s.", ss.str().c_str());
   2584             }
   2585         }
   2586 
   2587         // Each dimension offset + extent limits must fall with image subresource extent
   2588         VkExtent3D subresource_extent = GetImageSubresourceExtent(src_image_state, &(region.srcSubresource));
   2589         if (slice_override) src_copy_extent.depth = depth_slices;
   2590         uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &src_copy_extent, &subresource_extent);
   2591         if (extent_check & x_bit) {
   2592             skip |=
   2593                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2594                         HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00144",
   2595                         "vkCmdCopyImage(): Source image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
   2596                         "width [%1d].",
   2597                         i, region.srcOffset.x, src_copy_extent.width, subresource_extent.width);
   2598         }
   2599 
   2600         if (extent_check & y_bit) {
   2601             skip |=
   2602                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2603                         HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00145",
   2604                         "vkCmdCopyImage(): Source image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
   2605                         "height [%1d].",
   2606                         i, region.srcOffset.y, src_copy_extent.height, subresource_extent.height);
   2607         }
   2608         if (extent_check & z_bit) {
   2609             skip |=
   2610                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2611                         HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00147",
   2612                         "vkCmdCopyImage(): Source image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
   2613                         "depth [%1d].",
   2614                         i, region.srcOffset.z, src_copy_extent.depth, subresource_extent.depth);
   2615         }
   2616 
   2617         // Adjust dest extent if necessary
   2618         subresource_extent = GetImageSubresourceExtent(dst_image_state, &(region.dstSubresource));
   2619         if (slice_override) dst_copy_extent.depth = depth_slices;
   2620 
   2621         extent_check = ExceedsBounds(&(region.dstOffset), &dst_copy_extent, &subresource_extent);
   2622         if (extent_check & x_bit) {
   2623             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2624                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00150",
   2625                             "vkCmdCopyImage(): Dest image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
   2626                             "width [%1d].",
   2627                             i, region.dstOffset.x, dst_copy_extent.width, subresource_extent.width);
   2628         }
   2629         if (extent_check & y_bit) {
   2630             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2631                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00151",
   2632                             "vkCmdCopyImage(): Dest image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
   2633                             "height [%1d].",
   2634                             i, region.dstOffset.y, dst_copy_extent.height, subresource_extent.height);
   2635         }
   2636         if (extent_check & z_bit) {
   2637             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2638                             HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00153",
   2639                             "vkCmdCopyImage(): Dest image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
   2640                             "depth [%1d].",
   2641                             i, region.dstOffset.z, dst_copy_extent.depth, subresource_extent.depth);
   2642         }
   2643 
   2644         // The union of all source regions, and the union of all destination regions, specified by the elements of regions,
   2645         // must not overlap in memory
   2646         if (src_image_state->image == dst_image_state->image) {
   2647             for (uint32_t j = 0; j < regionCount; j++) {
   2648                 if (RegionIntersects(&region, &pRegions[j], src_image_state->createInfo.imageType,
   2649                                      FormatIsMultiplane(src_image_state->createInfo.format))) {
   2650                     std::stringstream ss;
   2651                     ss << "vkCmdCopyImage(): pRegions[" << i << "] src overlaps with pRegions[" << j << "].";
   2652                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2653                                     HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00124", "%s.", ss.str().c_str());
   2654                 }
   2655             }
   2656         }
   2657     }
   2658 
   2659     // The formats of src_image and dst_image must be compatible. Formats are considered compatible if their texel size in bytes
   2660     // is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT because
   2661     // because both texels are 4 bytes in size. Depth/stencil formats must match exactly.
   2662     if (FormatIsDepthOrStencil(src_image_state->createInfo.format) || FormatIsDepthOrStencil(dst_image_state->createInfo.format)) {
   2663         if (src_image_state->createInfo.format != dst_image_state->createInfo.format) {
   2664             char const str[] = "vkCmdCopyImage called with unmatched source and dest image depth/stencil formats.";
   2665             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2666                             HandleToUint64(command_buffer), kVUID_Core_DrawState_MismatchedImageFormat, str);
   2667         }
   2668     } else {
   2669         if (!FormatSizesAreEqual(src_image_state->createInfo.format, dst_image_state->createInfo.format, regionCount, pRegions)) {
   2670             char const str[] = "vkCmdCopyImage called with unmatched source and dest image format sizes.";
   2671             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2672                             HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-srcImage-00135", "%s.", str);
   2673         }
   2674     }
   2675 
   2676     // Source and dest image sample counts must match
   2677     if (src_image_state->createInfo.samples != dst_image_state->createInfo.samples) {
   2678         char const str[] = "vkCmdCopyImage() called on image pair with non-identical sample counts.";
   2679         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2680                         HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-srcImage-00136", "%s", str);
   2681     }
   2682 
   2683     skip |= ValidateMemoryIsBoundToImage(device_data, src_image_state, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-srcImage-00127");
   2684     skip |= ValidateMemoryIsBoundToImage(device_data, dst_image_state, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-dstImage-00132");
   2685     // Validate that SRC & DST images have correct usage flags set
   2686     skip |= ValidateImageUsageFlags(device_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
   2687                                     "VUID-vkCmdCopyImage-srcImage-00126", "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
   2688     skip |= ValidateImageUsageFlags(device_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
   2689                                     "VUID-vkCmdCopyImage-dstImage-00131", "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
   2690     if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
   2691         skip |=
   2692             ValidateImageFormatFeatureFlags(device_data, src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, "vkCmdCopyImage()",
   2693                                             "VUID-vkCmdCopyImage-srcImage-01995", "VUID-vkCmdCopyImage-srcImage-01995");
   2694         skip |=
   2695             ValidateImageFormatFeatureFlags(device_data, dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdCopyImage()",
   2696                                             "VUID-vkCmdCopyImage-dstImage-01996", "VUID-vkCmdCopyImage-dstImage-01996");
   2697     }
   2698     skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdCopyImage()",
   2699                                   VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
   2700                                   "VUID-vkCmdCopyImage-commandBuffer-cmdpool");
   2701     skip |= ValidateCmd(device_data, cb_node, CMD_COPYIMAGE, "vkCmdCopyImage()");
   2702     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-renderpass");
   2703     bool hit_error = false;
   2704     const char *invalid_src_layout_vuid =
   2705         (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   2706             ? "VUID-vkCmdCopyImage-srcImageLayout-01917"
   2707             : "VUID-vkCmdCopyImage-srcImageLayout-00129";
   2708     const char *invalid_dst_layout_vuid =
   2709         (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   2710             ? "VUID-vkCmdCopyImage-dstImageLayout-01395"
   2711             : "VUID-vkCmdCopyImage-dstImageLayout-00134";
   2712     for (uint32_t i = 0; i < regionCount; ++i) {
   2713         skip |= VerifyImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
   2714                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdCopyImage()", invalid_src_layout_vuid,
   2715                                   "VUID-vkCmdCopyImage-srcImageLayout-00128", &hit_error);
   2716         skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
   2717                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdCopyImage()", invalid_dst_layout_vuid,
   2718                                   "VUID-vkCmdCopyImage-dstImageLayout-00133", &hit_error);
   2719         skip |= ValidateCopyImageTransferGranularityRequirements(device_data, cb_node, src_image_state, dst_image_state,
   2720                                                                  &pRegions[i], i, "vkCmdCopyImage()");
   2721     }
   2722 
   2723     return skip;
   2724 }
   2725 
   2726 void CoreChecks::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   2727                                            VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
   2728                                            const VkImageCopy *pRegions) {
   2729     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   2730     auto cb_node = GetCBNode(commandBuffer);
   2731     auto src_image_state = GetImageState(srcImage);
   2732     auto dst_image_state = GetImageState(dstImage);
   2733 
   2734     // Make sure that all image slices are updated to correct layout
   2735     for (uint32_t i = 0; i < regionCount; ++i) {
   2736         SetImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout);
   2737         SetImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
   2738     }
   2739     // Update bindings between images and cmd buffer
   2740     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
   2741     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
   2742 }
   2743 
   2744 // Returns true if sub_rect is entirely contained within rect
   2745 static inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
   2746     if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
   2747         (sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height))
   2748         return false;
   2749     return true;
   2750 }
   2751 
   2752 bool CoreChecks::ValidateClearAttachmentExtent(layer_data *device_data, VkCommandBuffer command_buffer, uint32_t attachment_index,
   2753                                                FRAMEBUFFER_STATE *framebuffer, uint32_t fb_attachment, const VkRect2D &render_area,
   2754                                                uint32_t rect_count, const VkClearRect *clear_rects) {
   2755     bool skip = false;
   2756     const IMAGE_VIEW_STATE *image_view_state = nullptr;
   2757     if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) && (fb_attachment < framebuffer->createInfo.attachmentCount)) {
   2758         image_view_state = GetImageViewState(framebuffer->createInfo.pAttachments[fb_attachment]);
   2759     }
   2760 
   2761     for (uint32_t j = 0; j < rect_count; j++) {
   2762         if (!ContainsRect(render_area, clear_rects[j].rect)) {
   2763             skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2764                             HandleToUint64(command_buffer), "VUID-vkCmdClearAttachments-pRects-00016",
   2765                             "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
   2766                             "the current render pass instance.",
   2767                             j);
   2768         }
   2769 
   2770         if (image_view_state) {
   2771             // The layers specified by a given element of pRects must be contained within every attachment that
   2772             // pAttachments refers to
   2773             const auto attachment_layer_count = image_view_state->create_info.subresourceRange.layerCount;
   2774             if ((clear_rects[j].baseArrayLayer >= attachment_layer_count) ||
   2775                 (clear_rects[j].baseArrayLayer + clear_rects[j].layerCount > attachment_layer_count)) {
   2776                 skip |=
   2777                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2778                             HandleToUint64(command_buffer), "VUID-vkCmdClearAttachments-pRects-00017",
   2779                             "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers "
   2780                             "of pAttachment[%d].",
   2781                             j, attachment_index);
   2782             }
   2783         }
   2784     }
   2785     return skip;
   2786 }
   2787 
   2788 bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
   2789                                                     const VkClearAttachment *pAttachments, uint32_t rectCount,
   2790                                                     const VkClearRect *pRects) {
   2791     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   2792 
   2793     GLOBAL_CB_NODE *cb_node = GetCBNode(commandBuffer);
   2794 
   2795     bool skip = false;
   2796     if (cb_node) {
   2797         skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdClearAttachments()", VK_QUEUE_GRAPHICS_BIT,
   2798                                       "VUID-vkCmdClearAttachments-commandBuffer-cmdpool");
   2799         skip |= ValidateCmd(device_data, cb_node, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
   2800         // Warn if this is issued prior to Draw Cmd and clearing the entire attachment
   2801         if (!cb_node->hasDrawCmd && (cb_node->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) &&
   2802             (cb_node->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) {
   2803             // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
   2804             // This warning should be made more specific. It'd be best to avoid triggering this test if it's a use that must call
   2805             // CmdClearAttachments.
   2806             skip |=
   2807                 log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2808                         HandleToUint64(commandBuffer), kVUID_Core_DrawState_ClearCmdBeforeDraw,
   2809                         "vkCmdClearAttachments() issued on command buffer object %s prior to any Draw Cmds. It is recommended you "
   2810                         "use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
   2811                         report_data->FormatHandle(commandBuffer).c_str());
   2812         }
   2813         skip |= OutsideRenderPass(device_data, cb_node, "vkCmdClearAttachments()", "VUID-vkCmdClearAttachments-renderpass");
   2814     }
   2815 
   2816     // Validate that attachment is in reference list of active subpass
   2817     if (cb_node->activeRenderPass) {
   2818         const VkRenderPassCreateInfo2KHR *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
   2819         const uint32_t renderpass_attachment_count = renderpass_create_info->attachmentCount;
   2820         const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
   2821         auto framebuffer = GetFramebufferState(cb_node->activeFramebuffer);
   2822         const auto &render_area = cb_node->activeRenderPassBeginInfo.renderArea;
   2823         std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy;
   2824 
   2825         for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
   2826             auto clear_desc = &pAttachments[attachment_index];
   2827             uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
   2828 
   2829             if (0 == clear_desc->aspectMask) {
   2830                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2831                                 HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-requiredbitmask", " ");
   2832             } else if (clear_desc->aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
   2833                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2834                                 HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00020", " ");
   2835             } else if (clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
   2836                 uint32_t color_attachment = VK_ATTACHMENT_UNUSED;
   2837                 if (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount) {
   2838                     color_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
   2839                     if ((color_attachment != VK_ATTACHMENT_UNUSED) && (color_attachment >= renderpass_attachment_count)) {
   2840                         skip |= log_msg(
   2841                             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2842                             HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-02501",
   2843                             "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u is not VK_ATTACHMENT_UNUSED "
   2844                             "and not a valid attachment for render pass %s attachmentCount=%u. Subpass %u pColorAttachment[%u]=%u.",
   2845                             attachment_index, clear_desc->colorAttachment,
   2846                             report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(), cb_node->activeSubpass,
   2847                             clear_desc->colorAttachment, color_attachment, renderpass_attachment_count);
   2848 
   2849                         color_attachment = VK_ATTACHMENT_UNUSED;  // Defensive, prevent lookup past end of renderpass attachment
   2850                     }
   2851                 } else {
   2852                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2853                                     HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-02501",
   2854                                     "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u out of range for render pass %s"
   2855                                     " subpass %u. colorAttachmentCount=%u",
   2856                                     attachment_index, clear_desc->colorAttachment,
   2857                                     report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(),
   2858                                     cb_node->activeSubpass, subpass_desc->colorAttachmentCount);
   2859                 }
   2860                 fb_attachment = color_attachment;
   2861 
   2862                 if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
   2863                     (clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
   2864                     char const str[] =
   2865                         "vkCmdClearAttachments() aspectMask [%d] must set only VK_IMAGE_ASPECT_COLOR_BIT of a color attachment.";
   2866                     skip |=
   2867                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2868                                 HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00019", str, attachment_index);
   2869                 }
   2870             } else {  // Must be depth and/or stencil
   2871                 if (((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
   2872                     ((clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT)) {
   2873                     char const str[] = "vkCmdClearAttachments() aspectMask [%d] is not a valid combination of bits.";
   2874                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2875                                     HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-parameter", str,
   2876                                     attachment_index);
   2877                 }
   2878                 if (!subpass_desc->pDepthStencilAttachment ||
   2879                     (subpass_desc->pDepthStencilAttachment->attachment == VK_ATTACHMENT_UNUSED)) {
   2880                     skip |= log_msg(
   2881                         report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2882                         HandleToUint64(commandBuffer), kVUID_Core_DrawState_MissingAttachmentReference,
   2883                         "vkCmdClearAttachments() depth/stencil clear with no depth/stencil attachment in subpass; ignored");
   2884                 } else {
   2885                     fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
   2886                 }
   2887             }
   2888             if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
   2889                 skip |= ValidateClearAttachmentExtent(device_data, commandBuffer, attachment_index, framebuffer, fb_attachment,
   2890                                                       render_area, rectCount, pRects);
   2891             } else {
   2892                 // if a secondary level command buffer inherits the framebuffer from the primary command buffer
   2893                 // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time
   2894                 if (!clear_rect_copy) {
   2895                     // We need a copy of the clear rectangles that will persist until the last lambda executes
   2896                     // but we want to create it as lazily as possible
   2897                     clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount));
   2898                 }
   2899 
   2900                 auto val_fn = [device_data, commandBuffer, attachment_index, fb_attachment, rectCount, clear_rect_copy](
   2901                                   GLOBAL_CB_NODE *prim_cb, VkFramebuffer fb) {
   2902                     assert(rectCount == clear_rect_copy->size());
   2903                     FRAMEBUFFER_STATE *framebuffer = device_data->GetFramebufferState(fb);
   2904                     const auto &render_area = prim_cb->activeRenderPassBeginInfo.renderArea;
   2905                     bool skip = false;
   2906                     skip =
   2907                         device_data->ValidateClearAttachmentExtent(device_data, commandBuffer, attachment_index, framebuffer,
   2908                                                                    fb_attachment, render_area, rectCount, clear_rect_copy->data());
   2909                     return skip;
   2910                 };
   2911                 cb_node->cmd_execute_commands_functions.emplace_back(val_fn);
   2912             }
   2913         }
   2914     }
   2915     return skip;
   2916 }
   2917 
   2918 bool CoreChecks::PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   2919                                                 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
   2920                                                 const VkImageResolve *pRegions) {
   2921     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   2922     auto cb_node = GetCBNode(commandBuffer);
   2923     auto src_image_state = GetImageState(srcImage);
   2924     auto dst_image_state = GetImageState(dstImage);
   2925 
   2926     bool skip = false;
   2927     if (cb_node && src_image_state && dst_image_state) {
   2928         skip |= ValidateMemoryIsBoundToImage(device_data, src_image_state, "vkCmdResolveImage()",
   2929                                              "VUID-vkCmdResolveImage-srcImage-00256");
   2930         skip |= ValidateMemoryIsBoundToImage(device_data, dst_image_state, "vkCmdResolveImage()",
   2931                                              "VUID-vkCmdResolveImage-dstImage-00258");
   2932         skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdResolveImage()", VK_QUEUE_GRAPHICS_BIT,
   2933                                       "VUID-vkCmdResolveImage-commandBuffer-cmdpool");
   2934         skip |= ValidateCmd(device_data, cb_node, CMD_RESOLVEIMAGE, "vkCmdResolveImage()");
   2935         skip |= InsideRenderPass(device_data, cb_node, "vkCmdResolveImage()", "VUID-vkCmdResolveImage-renderpass");
   2936         skip |= ValidateImageFormatFeatureFlags(device_data, dst_image_state, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
   2937                                                 "vkCmdResolveImage()", "VUID-vkCmdResolveImage-dstImage-02003",
   2938                                                 "VUID-vkCmdResolveImage-dstImage-02003");
   2939 
   2940         bool hit_error = false;
   2941         const char *invalid_src_layout_vuid =
   2942             (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   2943                 ? "VUID-vkCmdResolveImage-srcImageLayout-01400"
   2944                 : "VUID-vkCmdResolveImage-srcImageLayout-00261";
   2945         const char *invalid_dst_layout_vuid =
   2946             (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   2947                 ? "VUID-vkCmdResolveImage-dstImageLayout-01401"
   2948                 : "VUID-vkCmdResolveImage-dstImageLayout-00263";
   2949         // For each region, the number of layers in the image subresource should not be zero
   2950         // For each region, src and dest image aspect must be color only
   2951         for (uint32_t i = 0; i < regionCount; i++) {
   2952             skip |= ValidateImageSubresourceLayers(device_data, cb_node, &pRegions[i].srcSubresource, "vkCmdResolveImage()",
   2953                                                    "srcSubresource", i);
   2954             skip |= ValidateImageSubresourceLayers(device_data, cb_node, &pRegions[i].dstSubresource, "vkCmdResolveImage()",
   2955                                                    "dstSubresource", i);
   2956             skip |= VerifyImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
   2957                                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdResolveImage()", invalid_src_layout_vuid,
   2958                                       "VUID-vkCmdResolveImage-srcImageLayout-00260", &hit_error);
   2959             skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
   2960                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdResolveImage()", invalid_dst_layout_vuid,
   2961                                       "VUID-vkCmdResolveImage-dstImageLayout-00262", &hit_error);
   2962             skip |= ValidateImageMipLevel(device_data, cb_node, src_image_state, pRegions[i].srcSubresource.mipLevel, i,
   2963                                           "vkCmdResolveImage()", "srcSubresource", "VUID-vkCmdResolveImage-srcSubresource-01709");
   2964             skip |= ValidateImageMipLevel(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource.mipLevel, i,
   2965                                           "vkCmdResolveImage()", "dstSubresource", "VUID-vkCmdResolveImage-dstSubresource-01710");
   2966             skip |= ValidateImageArrayLayerRange(device_data, cb_node, src_image_state, pRegions[i].srcSubresource.baseArrayLayer,
   2967                                                  pRegions[i].srcSubresource.layerCount, i, "vkCmdResolveImage()", "srcSubresource",
   2968                                                  "VUID-vkCmdResolveImage-srcSubresource-01711");
   2969             skip |= ValidateImageArrayLayerRange(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource.baseArrayLayer,
   2970                                                  pRegions[i].dstSubresource.layerCount, i, "vkCmdResolveImage()", "srcSubresource",
   2971                                                  "VUID-vkCmdResolveImage-dstSubresource-01712");
   2972 
   2973             // layer counts must match
   2974             if (pRegions[i].srcSubresource.layerCount != pRegions[i].dstSubresource.layerCount) {
   2975                 skip |= log_msg(
   2976                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2977                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageResolve-layerCount-00267",
   2978                     "vkCmdResolveImage(): layerCount in source and destination subresource of pRegions[%d] does not match.", i);
   2979             }
   2980             // For each region, src and dest image aspect must be color only
   2981             if ((pRegions[i].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
   2982                 (pRegions[i].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)) {
   2983                 char const str[] =
   2984                     "vkCmdResolveImage(): src and dest aspectMasks for each region must specify only VK_IMAGE_ASPECT_COLOR_BIT";
   2985                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2986                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageResolve-aspectMask-00266", "%s.", str);
   2987             }
   2988         }
   2989 
   2990         if (src_image_state->createInfo.format != dst_image_state->createInfo.format) {
   2991             char const str[] = "vkCmdResolveImage called with unmatched source and dest formats.";
   2992             skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2993                             HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_MismatchedImageFormat, str);
   2994         }
   2995         if (src_image_state->createInfo.imageType != dst_image_state->createInfo.imageType) {
   2996             char const str[] = "vkCmdResolveImage called with unmatched source and dest image types.";
   2997             skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   2998                             HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_MismatchedImageType, str);
   2999         }
   3000         if (src_image_state->createInfo.samples == VK_SAMPLE_COUNT_1_BIT) {
   3001             char const str[] = "vkCmdResolveImage called with source sample count less than 2.";
   3002             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3003                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdResolveImage-srcImage-00257", "%s.", str);
   3004         }
   3005         if (dst_image_state->createInfo.samples != VK_SAMPLE_COUNT_1_BIT) {
   3006             char const str[] = "vkCmdResolveImage called with dest sample count greater than 1.";
   3007             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3008                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdResolveImage-dstImage-00259", "%s.", str);
   3009         }
   3010     } else {
   3011         assert(0);
   3012     }
   3013     return skip;
   3014 }
   3015 
   3016 void CoreChecks::PreCallRecordCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   3017                                               VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
   3018                                               const VkImageResolve *pRegions) {
   3019     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   3020     auto cb_node = GetCBNode(commandBuffer);
   3021     auto src_image_state = GetImageState(srcImage);
   3022     auto dst_image_state = GetImageState(dstImage);
   3023 
   3024     // Update bindings between images and cmd buffer
   3025     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
   3026     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
   3027 }
   3028 
   3029 bool CoreChecks::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   3030                                              VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
   3031                                              const VkImageBlit *pRegions, VkFilter filter) {
   3032     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   3033     auto cb_node = GetCBNode(commandBuffer);
   3034     auto src_image_state = GetImageState(srcImage);
   3035     auto dst_image_state = GetImageState(dstImage);
   3036 
   3037     bool skip = false;
   3038     if (cb_node) {
   3039         skip |= ValidateCmd(device_data, cb_node, CMD_BLITIMAGE, "vkCmdBlitImage()");
   3040     }
   3041     if (cb_node && src_image_state && dst_image_state) {
   3042         skip |= ValidateImageSampleCount(device_data, src_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdBlitImage(): srcImage",
   3043                                          "VUID-vkCmdBlitImage-srcImage-00233");
   3044         skip |= ValidateImageSampleCount(device_data, dst_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdBlitImage(): dstImage",
   3045                                          "VUID-vkCmdBlitImage-dstImage-00234");
   3046         skip |=
   3047             ValidateMemoryIsBoundToImage(device_data, src_image_state, "vkCmdBlitImage()", "VUID-vkCmdBlitImage-srcImage-00220");
   3048         skip |=
   3049             ValidateMemoryIsBoundToImage(device_data, dst_image_state, "vkCmdBlitImage()", "VUID-vkCmdBlitImage-dstImage-00225");
   3050         skip |=
   3051             ValidateImageUsageFlags(device_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
   3052                                     "VUID-vkCmdBlitImage-srcImage-00219", "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
   3053         skip |=
   3054             ValidateImageUsageFlags(device_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
   3055                                     "VUID-vkCmdBlitImage-dstImage-00224", "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
   3056         skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdBlitImage()", VK_QUEUE_GRAPHICS_BIT,
   3057                                       "VUID-vkCmdBlitImage-commandBuffer-cmdpool");
   3058         skip |= ValidateCmd(device_data, cb_node, CMD_BLITIMAGE, "vkCmdBlitImage()");
   3059         skip |= InsideRenderPass(device_data, cb_node, "vkCmdBlitImage()", "VUID-vkCmdBlitImage-renderpass");
   3060         skip |= ValidateImageFormatFeatureFlags(device_data, src_image_state, VK_FORMAT_FEATURE_BLIT_SRC_BIT, "vkCmdBlitImage()",
   3061                                                 "VUID-vkCmdBlitImage-srcImage-01999", "VUID-vkCmdBlitImage-srcImage-01999");
   3062         skip |= ValidateImageFormatFeatureFlags(device_data, dst_image_state, VK_FORMAT_FEATURE_BLIT_DST_BIT, "vkCmdBlitImage()",
   3063                                                 "VUID-vkCmdBlitImage-dstImage-02000", "VUID-vkCmdBlitImage-dstImage-02000");
   3064 
   3065         // TODO: Need to validate image layouts, which will include layout validation for shared presentable images
   3066 
   3067         VkFormat src_format = src_image_state->createInfo.format;
   3068         VkFormat dst_format = dst_image_state->createInfo.format;
   3069         VkImageType src_type = src_image_state->createInfo.imageType;
   3070         VkImageType dst_type = dst_image_state->createInfo.imageType;
   3071 
   3072         if (VK_FILTER_LINEAR == filter) {
   3073             skip |= ValidateImageFormatFeatureFlags(device_data, src_image_state, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT,
   3074                                                     "vkCmdBlitImage()", "VUID-vkCmdBlitImage-filter-02001",
   3075                                                     "VUID-vkCmdBlitImage-filter-02001");
   3076         } else if (VK_FILTER_CUBIC_IMG == filter) {
   3077             skip |= ValidateImageFormatFeatureFlags(device_data, src_image_state,
   3078                                                     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG, "vkCmdBlitImage()",
   3079                                                     "VUID-vkCmdBlitImage-filter-02002", "VUID-vkCmdBlitImage-filter-02002");
   3080         }
   3081 
   3082         if ((VK_FILTER_CUBIC_IMG == filter) && (VK_IMAGE_TYPE_3D != src_type)) {
   3083             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3084                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-filter-00237",
   3085                             "vkCmdBlitImage(): source image type must be VK_IMAGE_TYPE_3D when cubic filtering is specified.");
   3086         }
   3087 
   3088         if ((VK_SAMPLE_COUNT_1_BIT != src_image_state->createInfo.samples) ||
   3089             (VK_SAMPLE_COUNT_1_BIT != dst_image_state->createInfo.samples)) {
   3090             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3091                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00228",
   3092                             "vkCmdBlitImage(): source or dest image has sample count other than VK_SAMPLE_COUNT_1_BIT.");
   3093         }
   3094 
   3095         // Validate consistency for unsigned formats
   3096         if (FormatIsUInt(src_format) != FormatIsUInt(dst_format)) {
   3097             std::stringstream ss;
   3098             ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has unsigned integer format, "
   3099                << "the other one must also have unsigned integer format.  "
   3100                << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
   3101             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3102                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00230", "%s.", ss.str().c_str());
   3103         }
   3104 
   3105         // Validate consistency for signed formats
   3106         if (FormatIsSInt(src_format) != FormatIsSInt(dst_format)) {
   3107             std::stringstream ss;
   3108             ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has signed integer format, "
   3109                << "the other one must also have signed integer format.  "
   3110                << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
   3111             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3112                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00229", "%s.", ss.str().c_str());
   3113         }
   3114 
   3115         // Validate filter for Depth/Stencil formats
   3116         if (FormatIsDepthOrStencil(src_format) && (filter != VK_FILTER_NEAREST)) {
   3117             std::stringstream ss;
   3118             ss << "vkCmdBlitImage(): If the format of srcImage is a depth, stencil, or depth stencil "
   3119                << "then filter must be VK_FILTER_NEAREST.";
   3120             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3121                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00232", "%s.", ss.str().c_str());
   3122         }
   3123 
   3124         // Validate aspect bits and formats for depth/stencil images
   3125         if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
   3126             if (src_format != dst_format) {
   3127                 std::stringstream ss;
   3128                 ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has a format of depth, stencil or depth "
   3129                    << "stencil, the other one must have exactly the same format.  "
   3130                    << "Source format is " << string_VkFormat(src_format) << " Destination format is "
   3131                    << string_VkFormat(dst_format);
   3132                 skip |=
   3133                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3134                             HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00231", "%s.", ss.str().c_str());
   3135             }
   3136         }  // Depth or Stencil
   3137 
   3138         // Do per-region checks
   3139         const char *invalid_src_layout_vuid =
   3140             (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   3141                 ? "VUID-vkCmdBlitImage-srcImageLayout-01398"
   3142                 : "VUID-vkCmdBlitImage-srcImageLayout-00222";
   3143         const char *invalid_dst_layout_vuid =
   3144             (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   3145                 ? "VUID-vkCmdBlitImage-dstImageLayout-01399"
   3146                 : "VUID-vkCmdBlitImage-dstImageLayout-00227";
   3147         for (uint32_t i = 0; i < regionCount; i++) {
   3148             const VkImageBlit rgn = pRegions[i];
   3149             bool hit_error = false;
   3150             skip |= VerifyImageLayout(device_data, cb_node, src_image_state, rgn.srcSubresource, srcImageLayout,
   3151                                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdBlitImage()", invalid_src_layout_vuid,
   3152                                       "VUID-vkCmdBlitImage-srcImageLayout-00221", &hit_error);
   3153             skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, rgn.dstSubresource, dstImageLayout,
   3154                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdBlitImage()", invalid_dst_layout_vuid,
   3155                                       "VUID-vkCmdBlitImage-dstImageLayout-00226", &hit_error);
   3156             skip |=
   3157                 ValidateImageSubresourceLayers(device_data, cb_node, &rgn.srcSubresource, "vkCmdBlitImage()", "srcSubresource", i);
   3158             skip |=
   3159                 ValidateImageSubresourceLayers(device_data, cb_node, &rgn.dstSubresource, "vkCmdBlitImage()", "dstSubresource", i);
   3160             skip |= ValidateImageMipLevel(device_data, cb_node, src_image_state, rgn.srcSubresource.mipLevel, i, "vkCmdBlitImage()",
   3161                                           "srcSubresource", "VUID-vkCmdBlitImage-srcSubresource-01705");
   3162             skip |= ValidateImageMipLevel(device_data, cb_node, dst_image_state, rgn.dstSubresource.mipLevel, i, "vkCmdBlitImage()",
   3163                                           "dstSubresource", "VUID-vkCmdBlitImage-dstSubresource-01706");
   3164             skip |= ValidateImageArrayLayerRange(device_data, cb_node, src_image_state, rgn.srcSubresource.baseArrayLayer,
   3165                                                  rgn.srcSubresource.layerCount, i, "vkCmdBlitImage()", "srcSubresource",
   3166                                                  "VUID-vkCmdBlitImage-srcSubresource-01707");
   3167             skip |= ValidateImageArrayLayerRange(device_data, cb_node, dst_image_state, rgn.dstSubresource.baseArrayLayer,
   3168                                                  rgn.dstSubresource.layerCount, i, "vkCmdBlitImage()", "dstSubresource",
   3169                                                  "VUID-vkCmdBlitImage-dstSubresource-01708");
   3170             // Warn for zero-sized regions
   3171             if ((rgn.srcOffsets[0].x == rgn.srcOffsets[1].x) || (rgn.srcOffsets[0].y == rgn.srcOffsets[1].y) ||
   3172                 (rgn.srcOffsets[0].z == rgn.srcOffsets[1].z)) {
   3173                 std::stringstream ss;
   3174                 ss << "vkCmdBlitImage(): pRegions[" << i << "].srcOffsets specify a zero-volume area.";
   3175                 skip |=
   3176                     log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3177                             HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
   3178             }
   3179             if ((rgn.dstOffsets[0].x == rgn.dstOffsets[1].x) || (rgn.dstOffsets[0].y == rgn.dstOffsets[1].y) ||
   3180                 (rgn.dstOffsets[0].z == rgn.dstOffsets[1].z)) {
   3181                 std::stringstream ss;
   3182                 ss << "vkCmdBlitImage(): pRegions[" << i << "].dstOffsets specify a zero-volume area.";
   3183                 skip |=
   3184                     log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3185                             HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
   3186             }
   3187 
   3188             // Check that src/dst layercounts match
   3189             if (rgn.srcSubresource.layerCount != rgn.dstSubresource.layerCount) {
   3190                 skip |= log_msg(
   3191                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3192                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-layerCount-00239",
   3193                     "vkCmdBlitImage(): layerCount in source and destination subresource of pRegions[%d] does not match.", i);
   3194             }
   3195 
   3196             if (rgn.srcSubresource.aspectMask != rgn.dstSubresource.aspectMask) {
   3197                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3198                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00238",
   3199                                 "vkCmdBlitImage(): aspectMask members for pRegion[%d] do not match.", i);
   3200             }
   3201 
   3202             if (!VerifyAspectsPresent(rgn.srcSubresource.aspectMask, src_format)) {
   3203                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3204                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00241",
   3205                                 "vkCmdBlitImage(): region [%d] source aspectMask (0x%x) specifies aspects not present in source "
   3206                                 "image format %s.",
   3207                                 i, rgn.srcSubresource.aspectMask, string_VkFormat(src_format));
   3208             }
   3209 
   3210             if (!VerifyAspectsPresent(rgn.dstSubresource.aspectMask, dst_format)) {
   3211                 skip |= log_msg(
   3212                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3213                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00242",
   3214                     "vkCmdBlitImage(): region [%d] dest aspectMask (0x%x) specifies aspects not present in dest image format %s.",
   3215                     i, rgn.dstSubresource.aspectMask, string_VkFormat(dst_format));
   3216             }
   3217 
   3218             // Validate source image offsets
   3219             VkExtent3D src_extent = GetImageSubresourceExtent(src_image_state, &(rgn.srcSubresource));
   3220             if (VK_IMAGE_TYPE_1D == src_type) {
   3221                 if ((0 != rgn.srcOffsets[0].y) || (1 != rgn.srcOffsets[1].y)) {
   3222                     skip |=
   3223                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3224                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00245",
   3225                                 "vkCmdBlitImage(): region [%d], source image of type VK_IMAGE_TYPE_1D with srcOffset[].y values "
   3226                                 "of (%1d, %1d). These must be (0, 1).",
   3227                                 i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y);
   3228                 }
   3229             }
   3230 
   3231             if ((VK_IMAGE_TYPE_1D == src_type) || (VK_IMAGE_TYPE_2D == src_type)) {
   3232                 if ((0 != rgn.srcOffsets[0].z) || (1 != rgn.srcOffsets[1].z)) {
   3233                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3234                                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00247",
   3235                                     "vkCmdBlitImage(): region [%d], source image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
   3236                                     "srcOffset[].z values of (%1d, %1d). These must be (0, 1).",
   3237                                     i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z);
   3238                 }
   3239             }
   3240 
   3241             bool oob = false;
   3242             if ((rgn.srcOffsets[0].x < 0) || (rgn.srcOffsets[0].x > static_cast<int32_t>(src_extent.width)) ||
   3243                 (rgn.srcOffsets[1].x < 0) || (rgn.srcOffsets[1].x > static_cast<int32_t>(src_extent.width))) {
   3244                 oob = true;
   3245                 skip |= log_msg(
   3246                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3247                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00243",
   3248                     "vkCmdBlitImage(): region [%d] srcOffset[].x values (%1d, %1d) exceed srcSubresource width extent (%1d).", i,
   3249                     rgn.srcOffsets[0].x, rgn.srcOffsets[1].x, src_extent.width);
   3250             }
   3251             if ((rgn.srcOffsets[0].y < 0) || (rgn.srcOffsets[0].y > static_cast<int32_t>(src_extent.height)) ||
   3252                 (rgn.srcOffsets[1].y < 0) || (rgn.srcOffsets[1].y > static_cast<int32_t>(src_extent.height))) {
   3253                 oob = true;
   3254                 skip |= log_msg(
   3255                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3256                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00244",
   3257                     "vkCmdBlitImage(): region [%d] srcOffset[].y values (%1d, %1d) exceed srcSubresource height extent (%1d).", i,
   3258                     rgn.srcOffsets[0].y, rgn.srcOffsets[1].y, src_extent.height);
   3259             }
   3260             if ((rgn.srcOffsets[0].z < 0) || (rgn.srcOffsets[0].z > static_cast<int32_t>(src_extent.depth)) ||
   3261                 (rgn.srcOffsets[1].z < 0) || (rgn.srcOffsets[1].z > static_cast<int32_t>(src_extent.depth))) {
   3262                 oob = true;
   3263                 skip |= log_msg(
   3264                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3265                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00246",
   3266                     "vkCmdBlitImage(): region [%d] srcOffset[].z values (%1d, %1d) exceed srcSubresource depth extent (%1d).", i,
   3267                     rgn.srcOffsets[0].z, rgn.srcOffsets[1].z, src_extent.depth);
   3268             }
   3269             if (oob) {
   3270                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3271                                 HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-pRegions-00215",
   3272                                 "vkCmdBlitImage(): region [%d] source image blit region exceeds image dimensions.", i);
   3273             }
   3274 
   3275             // Validate dest image offsets
   3276             VkExtent3D dst_extent = GetImageSubresourceExtent(dst_image_state, &(rgn.dstSubresource));
   3277             if (VK_IMAGE_TYPE_1D == dst_type) {
   3278                 if ((0 != rgn.dstOffsets[0].y) || (1 != rgn.dstOffsets[1].y)) {
   3279                     skip |=
   3280                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3281                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00250",
   3282                                 "vkCmdBlitImage(): region [%d], dest image of type VK_IMAGE_TYPE_1D with dstOffset[].y values of "
   3283                                 "(%1d, %1d). These must be (0, 1).",
   3284                                 i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y);
   3285                 }
   3286             }
   3287 
   3288             if ((VK_IMAGE_TYPE_1D == dst_type) || (VK_IMAGE_TYPE_2D == dst_type)) {
   3289                 if ((0 != rgn.dstOffsets[0].z) || (1 != rgn.dstOffsets[1].z)) {
   3290                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3291                                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00252",
   3292                                     "vkCmdBlitImage(): region [%d], dest image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
   3293                                     "dstOffset[].z values of (%1d, %1d). These must be (0, 1).",
   3294                                     i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z);
   3295                 }
   3296             }
   3297 
   3298             oob = false;
   3299             if ((rgn.dstOffsets[0].x < 0) || (rgn.dstOffsets[0].x > static_cast<int32_t>(dst_extent.width)) ||
   3300                 (rgn.dstOffsets[1].x < 0) || (rgn.dstOffsets[1].x > static_cast<int32_t>(dst_extent.width))) {
   3301                 oob = true;
   3302                 skip |= log_msg(
   3303                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3304                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00248",
   3305                     "vkCmdBlitImage(): region [%d] dstOffset[].x values (%1d, %1d) exceed dstSubresource width extent (%1d).", i,
   3306                     rgn.dstOffsets[0].x, rgn.dstOffsets[1].x, dst_extent.width);
   3307             }
   3308             if ((rgn.dstOffsets[0].y < 0) || (rgn.dstOffsets[0].y > static_cast<int32_t>(dst_extent.height)) ||
   3309                 (rgn.dstOffsets[1].y < 0) || (rgn.dstOffsets[1].y > static_cast<int32_t>(dst_extent.height))) {
   3310                 oob = true;
   3311                 skip |= log_msg(
   3312                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3313                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00249",
   3314                     "vkCmdBlitImage(): region [%d] dstOffset[].y values (%1d, %1d) exceed dstSubresource height extent (%1d).", i,
   3315                     rgn.dstOffsets[0].y, rgn.dstOffsets[1].y, dst_extent.height);
   3316             }
   3317             if ((rgn.dstOffsets[0].z < 0) || (rgn.dstOffsets[0].z > static_cast<int32_t>(dst_extent.depth)) ||
   3318                 (rgn.dstOffsets[1].z < 0) || (rgn.dstOffsets[1].z > static_cast<int32_t>(dst_extent.depth))) {
   3319                 oob = true;
   3320                 skip |= log_msg(
   3321                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3322                     HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00251",
   3323                     "vkCmdBlitImage(): region [%d] dstOffset[].z values (%1d, %1d) exceed dstSubresource depth extent (%1d).", i,
   3324                     rgn.dstOffsets[0].z, rgn.dstOffsets[1].z, dst_extent.depth);
   3325             }
   3326             if (oob) {
   3327                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3328                                 HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-pRegions-00216",
   3329                                 "vkCmdBlitImage(): region [%d] destination image blit region exceeds image dimensions.", i);
   3330             }
   3331 
   3332             if ((VK_IMAGE_TYPE_3D == src_type) || (VK_IMAGE_TYPE_3D == dst_type)) {
   3333                 if ((0 != rgn.srcSubresource.baseArrayLayer) || (1 != rgn.srcSubresource.layerCount) ||
   3334                     (0 != rgn.dstSubresource.baseArrayLayer) || (1 != rgn.dstSubresource.layerCount)) {
   3335                     skip |=
   3336                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3337                                 HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00240",
   3338                                 "vkCmdBlitImage(): region [%d] blit to/from a 3D image type with a non-zero baseArrayLayer, or a "
   3339                                 "layerCount other than 1.",
   3340                                 i);
   3341                 }
   3342             }
   3343         }  // per-region checks
   3344     } else {
   3345         assert(0);
   3346     }
   3347     return skip;
   3348 }
   3349 
   3350 void CoreChecks::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   3351                                            VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
   3352                                            const VkImageBlit *pRegions, VkFilter filter) {
   3353     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   3354     auto cb_node = GetCBNode(commandBuffer);
   3355     auto src_image_state = GetImageState(srcImage);
   3356     auto dst_image_state = GetImageState(dstImage);
   3357 
   3358     // Make sure that all image slices are updated to correct layout
   3359     for (uint32_t i = 0; i < regionCount; ++i) {
   3360         SetImageLayout(device_data, cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout);
   3361         SetImageLayout(device_data, cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
   3362     }
   3363     // Update bindings between images and cmd buffer
   3364     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
   3365     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
   3366 }
   3367 
   3368 // This validates that the initial layout specified in the command buffer for the IMAGE is the same as the global IMAGE layout
   3369 bool CoreChecks::ValidateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB,
   3370                                             std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> const &globalImageLayoutMap,
   3371                                             std::unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> &overlayLayoutMap) {
   3372     bool skip = false;
   3373     for (auto cb_image_data : pCB->imageLayoutMap) {
   3374         VkImageLayout imageLayout;
   3375 
   3376         if (FindLayout(device_data, overlayLayoutMap, cb_image_data.first, imageLayout) ||
   3377             FindLayout(device_data, globalImageLayoutMap, cb_image_data.first, imageLayout)) {
   3378             if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
   3379                 // TODO: Set memory invalid which is in mem_tracker currently
   3380             } else if (imageLayout != cb_image_data.second.initialLayout) {
   3381                 if (cb_image_data.first.hasSubresource) {
   3382                     skip |=
   3383                         log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3384                                 HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
   3385                                 "Submitted command buffer expects image %s (subresource: aspectMask 0x%X array layer %u, mip level "
   3386                                 "%u) to be in layout %s--instead, image %s's current layout is %s.",
   3387                                 report_data->FormatHandle(cb_image_data.first.image).c_str(),
   3388                                 cb_image_data.first.subresource.aspectMask, cb_image_data.first.subresource.arrayLayer,
   3389                                 cb_image_data.first.subresource.mipLevel, string_VkImageLayout(cb_image_data.second.initialLayout),
   3390                                 report_data->FormatHandle(cb_image_data.first.image).c_str(), string_VkImageLayout(imageLayout));
   3391                 } else {
   3392                     skip |= log_msg(
   3393                         report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3394                         HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
   3395                         "Submitted command buffer expects image %s to be in layout %s--instead, image %s's current layout is %s.",
   3396                         report_data->FormatHandle(cb_image_data.first.image).c_str(),
   3397                         string_VkImageLayout(cb_image_data.second.initialLayout),
   3398                         report_data->FormatHandle(cb_image_data.first.image).c_str(), string_VkImageLayout(imageLayout));
   3399                 }
   3400             }
   3401             SetLayout(overlayLayoutMap, cb_image_data.first, cb_image_data.second.layout);
   3402         }
   3403     }
   3404     return skip;
   3405 }
   3406 
   3407 void CoreChecks::UpdateCmdBufImageLayouts(layer_data *device_data, GLOBAL_CB_NODE *pCB) {
   3408     for (auto cb_image_data : pCB->imageLayoutMap) {
   3409         VkImageLayout imageLayout;
   3410         FindGlobalLayout(device_data, cb_image_data.first, imageLayout);
   3411         SetGlobalLayout(device_data, cb_image_data.first, cb_image_data.second.layout);
   3412     }
   3413 }
   3414 
   3415 // ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
   3416 // VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that READ_ONLY
   3417 // layout attachments don't have CLEAR as their loadOp.
   3418 bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
   3419                                                        const VkImageLayout first_layout, const uint32_t attachment,
   3420                                                        const VkAttachmentDescription2KHR &attachment_description) {
   3421     bool skip = false;
   3422     const char *vuid;
   3423     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
   3424 
   3425     // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
   3426     if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
   3427         if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
   3428                         (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
   3429                         (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL))) {
   3430             skip |=
   3431                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3432                         "VUID-VkRenderPassCreateInfo2KHR-pAttachments-02522",
   3433                         "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
   3434         } else if (!use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
   3435                                 (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
   3436             skip |=
   3437                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3438                         "VUID-VkRenderPassCreateInfo-pAttachments-00836",
   3439                         "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
   3440         }
   3441     }
   3442     if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
   3443         if (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) {
   3444             vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pAttachments-01566";
   3445             skip |=
   3446                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3447                         "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
   3448         }
   3449     }
   3450 
   3451     if (attachment_description.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
   3452         if (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) {
   3453             vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pAttachments-01567";
   3454             skip |=
   3455                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3456                         "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
   3457         }
   3458     }
   3459     return skip;
   3460 }
   3461 
   3462 bool CoreChecks::ValidateLayouts(layer_data *device_data, RenderPassCreateVersion rp_version, VkDevice device,
   3463                                  const VkRenderPassCreateInfo2KHR *pCreateInfo) {
   3464     bool skip = false;
   3465     const char *vuid;
   3466     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
   3467     const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()";
   3468 
   3469     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
   3470         VkFormat format = pCreateInfo->pAttachments[i].format;
   3471         if (pCreateInfo->pAttachments[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
   3472             if ((FormatIsColor(format) || FormatHasDepth(format)) &&
   3473                 pCreateInfo->pAttachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) {
   3474                 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3475                                 kVUID_Core_DrawState_InvalidRenderpass,
   3476                                 "Render pass has an attachment with loadOp == VK_ATTACHMENT_LOAD_OP_LOAD and initialLayout == "
   3477                                 "VK_IMAGE_LAYOUT_UNDEFINED.  This is probably not what you intended.  Consider using "
   3478                                 "VK_ATTACHMENT_LOAD_OP_DONT_CARE instead if the image truely is undefined at the start of the "
   3479                                 "render pass.");
   3480             }
   3481             if (FormatHasStencil(format) && pCreateInfo->pAttachments[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) {
   3482                 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3483                                 kVUID_Core_DrawState_InvalidRenderpass,
   3484                                 "Render pass has an attachment with stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD and initialLayout "
   3485                                 "== VK_IMAGE_LAYOUT_UNDEFINED.  This is probably not what you intended.  Consider using "
   3486                                 "VK_ATTACHMENT_LOAD_OP_DONT_CARE instead if the image truely is undefined at the start of the "
   3487                                 "render pass.");
   3488             }
   3489         }
   3490     }
   3491 
   3492     // Track when we're observing the first use of an attachment
   3493     std::vector<bool> attach_first_use(pCreateInfo->attachmentCount, true);
   3494     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
   3495         const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i];
   3496 
   3497         // Check input attachments first, so we can detect first-use-as-input for VU #00349
   3498         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
   3499             auto attach_index = subpass.pInputAttachments[j].attachment;
   3500             if (attach_index == VK_ATTACHMENT_UNUSED) continue;
   3501             switch (subpass.pInputAttachments[j].layout) {
   3502                 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
   3503                 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
   3504                     // These are ideal.
   3505                     break;
   3506 
   3507                 case VK_IMAGE_LAYOUT_GENERAL:
   3508                     // May not be optimal. TODO: reconsider this warning based on other constraints.
   3509                     skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   3510                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout,
   3511                                     "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL.");
   3512                     break;
   3513 
   3514                 case VK_IMAGE_LAYOUT_UNDEFINED:
   3515                 case VK_IMAGE_LAYOUT_PREINITIALIZED:
   3516                     vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
   3517                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3518                                     "Layout for input attachment reference %u in subpass %u is %s but must be "
   3519                                     "DEPTH_STENCIL_READ_ONLY, SHADER_READ_ONLY_OPTIMAL, or GENERAL.",
   3520                                     j, i, string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
   3521                     break;
   3522 
   3523                 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
   3524                 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
   3525                     if (GetDeviceExtensions()->vk_khr_maintenance2) {
   3526                         break;
   3527                     } else {
   3528                         // Intentionally fall through to generic error message
   3529                     }
   3530                     // fall through
   3531 
   3532                 default:
   3533                     // No other layouts are acceptable
   3534                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3535                                     kVUID_Core_DrawState_InvalidImageLayout,
   3536                                     "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.",
   3537                                     string_VkImageLayout(subpass.pInputAttachments[j].layout));
   3538             }
   3539 
   3540             if (attach_first_use[attach_index]) {
   3541                 skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pInputAttachments[j].layout,
   3542                                                               attach_index, pCreateInfo->pAttachments[attach_index]);
   3543 
   3544                 bool used_as_depth =
   3545                     (subpass.pDepthStencilAttachment != NULL && subpass.pDepthStencilAttachment->attachment == attach_index);
   3546                 bool used_as_color = false;
   3547                 for (uint32_t k = 0; !used_as_depth && !used_as_color && k < subpass.colorAttachmentCount; ++k) {
   3548                     used_as_color = (subpass.pColorAttachments[k].attachment == attach_index);
   3549                 }
   3550                 if (!used_as_depth && !used_as_color &&
   3551                     pCreateInfo->pAttachments[attach_index].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
   3552                     vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-loadOp-03064" : "VUID-VkSubpassDescription-loadOp-00846";
   3553                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3554                                     "%s: attachment %u is first used as an input attachment in subpass %u with loadOp=CLEAR.",
   3555                                     function_name, attach_index, attach_index);
   3556                 }
   3557             }
   3558             attach_first_use[attach_index] = false;
   3559         }
   3560 
   3561         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
   3562             auto attach_index = subpass.pColorAttachments[j].attachment;
   3563             if (attach_index == VK_ATTACHMENT_UNUSED) continue;
   3564 
   3565             // TODO: Need a way to validate shared presentable images here, currently just allowing
   3566             // VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
   3567             //  as an acceptable layout, but need to make sure shared presentable images ONLY use that layout
   3568             switch (subpass.pColorAttachments[j].layout) {
   3569                 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
   3570                 // This is ideal.
   3571                 case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
   3572                     // TODO: See note above, just assuming that attachment is shared presentable and allowing this for now.
   3573                     break;
   3574 
   3575                 case VK_IMAGE_LAYOUT_GENERAL:
   3576                     // May not be optimal; TODO: reconsider this warning based on other constraints?
   3577                     skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   3578                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout,
   3579                                     "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL.");
   3580                     break;
   3581 
   3582                 case VK_IMAGE_LAYOUT_UNDEFINED:
   3583                 case VK_IMAGE_LAYOUT_PREINITIALIZED:
   3584                     vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
   3585                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3586                                     "Layout for color attachment reference %u in subpass %u is %s but should be "
   3587                                     "COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
   3588                                     j, i, string_VkImageLayout(subpass.pColorAttachments[j].layout));
   3589                     break;
   3590 
   3591                 default:
   3592                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3593                                     kVUID_Core_DrawState_InvalidImageLayout,
   3594                                     "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
   3595                                     string_VkImageLayout(subpass.pColorAttachments[j].layout));
   3596             }
   3597 
   3598             if (subpass.pResolveAttachments && (subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) &&
   3599                 (subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_UNDEFINED ||
   3600                  subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_PREINITIALIZED)) {
   3601                 vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
   3602                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3603                                 "Layout for resolve attachment reference %u in subpass %u is %s but should be "
   3604                                 "COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
   3605                                 j, i, string_VkImageLayout(subpass.pResolveAttachments[j].layout));
   3606             }
   3607 
   3608             if (attach_first_use[attach_index]) {
   3609                 skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pColorAttachments[j].layout,
   3610                                                               attach_index, pCreateInfo->pAttachments[attach_index]);
   3611             }
   3612             attach_first_use[attach_index] = false;
   3613         }
   3614 
   3615         if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
   3616             switch (subpass.pDepthStencilAttachment->layout) {
   3617                 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
   3618                 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
   3619                     // These are ideal.
   3620                     break;
   3621 
   3622                 case VK_IMAGE_LAYOUT_GENERAL:
   3623                     // May not be optimal; TODO: reconsider this warning based on other constraints? GENERAL can be better than
   3624                     // doing a bunch of transitions.
   3625                     skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
   3626                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout,
   3627                                     "GENERAL layout for depth attachment may not give optimal performance.");
   3628                     break;
   3629 
   3630                 case VK_IMAGE_LAYOUT_UNDEFINED:
   3631                 case VK_IMAGE_LAYOUT_PREINITIALIZED:
   3632                     vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
   3633                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
   3634                                     "Layout for depth attachment reference in subpass %u is %s but must be a valid depth/stencil "
   3635                                     "layout or GENERAL.",
   3636                                     i, string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
   3637                     break;
   3638 
   3639                 case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
   3640                 case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
   3641                     if (GetDeviceExtensions()->vk_khr_maintenance2) {
   3642                         break;
   3643                     } else {
   3644                         // Intentionally fall through to generic error message
   3645                     }
   3646                     // fall through
   3647 
   3648                 default:
   3649                     // No other layouts are acceptable
   3650                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3651                                     kVUID_Core_DrawState_InvalidImageLayout,
   3652                                     "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "
   3653                                     "DEPTH_STENCIL_READ_ONLY_OPTIMAL or GENERAL.",
   3654                                     string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
   3655             }
   3656 
   3657             auto attach_index = subpass.pDepthStencilAttachment->attachment;
   3658             if (attach_first_use[attach_index]) {
   3659                 skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pDepthStencilAttachment->layout,
   3660                                                               attach_index, pCreateInfo->pAttachments[attach_index]);
   3661             }
   3662             attach_first_use[attach_index] = false;
   3663         }
   3664     }
   3665     return skip;
   3666 }
   3667 
   3668 // For any image objects that overlap mapped memory, verify that their layouts are PREINIT or GENERAL
   3669 bool CoreChecks::ValidateMapImageLayouts(layer_data *device_data, VkDevice device, DEVICE_MEM_INFO const *mem_info,
   3670                                          VkDeviceSize offset, VkDeviceSize end_offset) {
   3671     bool skip = false;
   3672     // Iterate over all bound image ranges and verify that for any that overlap the map ranges, the layouts are
   3673     // VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL
   3674     // TODO : This can be optimized if we store ranges based on starting address and early exit when we pass our range
   3675     for (auto image_handle : mem_info->bound_images) {
   3676         auto img_it = mem_info->bound_ranges.find(image_handle);
   3677         if (img_it != mem_info->bound_ranges.end()) {
   3678             if (RangesIntersect(device_data, &img_it->second, offset, end_offset)) {
   3679                 std::vector<VkImageLayout> layouts;
   3680                 if (FindLayouts(device_data, VkImage(image_handle), layouts)) {
   3681                     for (auto layout : layouts) {
   3682                         if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) {
   3683                             skip |=
   3684                                 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
   3685                                         HandleToUint64(mem_info->mem), kVUID_Core_DrawState_InvalidImageLayout,
   3686                                         "Mapping an image with layout %s can result in undefined behavior if this memory is used "
   3687                                         "by the device. Only GENERAL or PREINITIALIZED should be used.",
   3688                                         string_VkImageLayout(layout));
   3689                         }
   3690                     }
   3691                 }
   3692             }
   3693         }
   3694     }
   3695     return skip;
   3696 }
   3697 
   3698 // Helper function to validate correct usage bits set for buffers or images. Verify that (actual & desired) flags != 0 or, if strict
   3699 // is true, verify that (actual & desired) flags == desired
   3700 bool CoreChecks::ValidateUsageFlags(const layer_data *device_data, VkFlags actual, VkFlags desired, VkBool32 strict,
   3701                                     uint64_t obj_handle, VulkanObjectType obj_type, const char *msgCode, char const *func_name,
   3702                                     char const *usage_str) {
   3703     bool correct_usage = false;
   3704     bool skip = false;
   3705     const char *type_str = object_string[obj_type];
   3706     if (strict) {
   3707         correct_usage = ((actual & desired) == desired);
   3708     } else {
   3709         correct_usage = ((actual & desired) != 0);
   3710     }
   3711     if (!correct_usage) {
   3712         if (msgCode == kVUIDUndefined) {
   3713             // TODO: Fix callers with kVUIDUndefined to use correct validation checks.
   3714             skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_type], obj_handle,
   3715                            kVUID_Core_MemTrack_InvalidUsageFlag,
   3716                            "Invalid usage flag for %s %s used by %s. In this case, %s should have %s set during creation.",
   3717                            type_str, report_data->FormatHandle(obj_handle).c_str(), func_name, type_str, usage_str);
   3718         } else {
   3719             skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[obj_type], obj_handle, msgCode,
   3720                            "Invalid usage flag for %s %s used by %s. In this case, %s should have %s set during creation.",
   3721                            type_str, report_data->FormatHandle(obj_handle).c_str(), func_name, type_str, usage_str);
   3722         }
   3723     }
   3724     return skip;
   3725 }
   3726 
   3727 // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
   3728 // where an error will be flagged if usage is not correct
   3729 bool CoreChecks::ValidateImageUsageFlags(layer_data *device_data, IMAGE_STATE const *image_state, VkFlags desired, bool strict,
   3730                                          const char *msgCode, char const *func_name, char const *usage_string) {
   3731     return ValidateUsageFlags(device_data, image_state->createInfo.usage, desired, strict, HandleToUint64(image_state->image),
   3732                               kVulkanObjectTypeImage, msgCode, func_name, usage_string);
   3733 }
   3734 
   3735 bool CoreChecks::ValidateImageFormatFeatureFlags(layer_data *dev_data, IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
   3736                                                  char const *func_name, const char *linear_vuid, const char *optimal_vuid) {
   3737     VkFormatProperties format_properties = GetPDFormatProperties(image_state->createInfo.format);
   3738     bool skip = false;
   3739     if (image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR) {
   3740         if ((format_properties.linearTilingFeatures & desired) != desired) {
   3741             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   3742                             HandleToUint64(image_state->image), linear_vuid,
   3743                             "In %s, invalid linearTilingFeatures (0x%08X) for format %u used by image %s.", func_name,
   3744                             format_properties.linearTilingFeatures, image_state->createInfo.format,
   3745                             report_data->FormatHandle(image_state->image).c_str());
   3746         }
   3747     } else if (image_state->createInfo.tiling == VK_IMAGE_TILING_OPTIMAL) {
   3748         if ((format_properties.optimalTilingFeatures & desired) != desired) {
   3749             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   3750                             HandleToUint64(image_state->image), optimal_vuid,
   3751                             "In %s, invalid optimalTilingFeatures (0x%08X) for format %u used by image %s.", func_name,
   3752                             format_properties.optimalTilingFeatures, image_state->createInfo.format,
   3753                             report_data->FormatHandle(image_state->image).c_str());
   3754         }
   3755     }
   3756     return skip;
   3757 }
   3758 
   3759 bool CoreChecks::ValidateImageSubresourceLayers(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node,
   3760                                                 const VkImageSubresourceLayers *subresource_layers, char const *func_name,
   3761                                                 char const *member, uint32_t i) {
   3762     bool skip = false;
   3763     // layerCount must not be zero
   3764     if (subresource_layers->layerCount == 0) {
   3765         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3766                         HandleToUint64(cb_node->commandBuffer), "VUID-VkImageSubresourceLayers-layerCount-01700",
   3767                         "In %s, pRegions[%u].%s.layerCount must not be zero.", func_name, i, member);
   3768     }
   3769     // aspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT
   3770     if (subresource_layers->aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
   3771         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3772                         HandleToUint64(cb_node->commandBuffer), "VUID-VkImageSubresourceLayers-aspectMask-00168",
   3773                         "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_METADATA_BIT set.", func_name, i, member);
   3774     }
   3775     // if aspectMask contains COLOR, it must not contain either DEPTH or STENCIL
   3776     if ((subresource_layers->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
   3777         (subresource_layers->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
   3778         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   3779                         HandleToUint64(cb_node->commandBuffer), "VUID-VkImageSubresourceLayers-aspectMask-00167",
   3780                         "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_COLOR_BIT and either VK_IMAGE_ASPECT_DEPTH_BIT or "
   3781                         "VK_IMAGE_ASPECT_STENCIL_BIT set.",
   3782                         func_name, i, member);
   3783     }
   3784     return skip;
   3785 }
   3786 
   3787 // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
   3788 // where an error will be flagged if usage is not correct
   3789 bool CoreChecks::ValidateBufferUsageFlags(const layer_data *device_data, BUFFER_STATE const *buffer_state, VkFlags desired,
   3790                                           bool strict, const char *msgCode, char const *func_name, char const *usage_string) {
   3791     return ValidateUsageFlags(device_data, buffer_state->createInfo.usage, desired, strict, HandleToUint64(buffer_state->buffer),
   3792                               kVulkanObjectTypeBuffer, msgCode, func_name, usage_string);
   3793 }
   3794 
   3795 bool CoreChecks::ValidateBufferViewRange(const layer_data *device_data, const BUFFER_STATE *buffer_state,
   3796                                          const VkBufferViewCreateInfo *pCreateInfo, const VkPhysicalDeviceLimits *device_limits) {
   3797     bool skip = false;
   3798 
   3799     const VkDeviceSize &range = pCreateInfo->range;
   3800     if (range != VK_WHOLE_SIZE) {
   3801         // Range must be greater than 0
   3802         if (range <= 0) {
   3803             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3804                             HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00928",
   3805                             "If VkBufferViewCreateInfo range (%" PRIuLEAST64
   3806                             ") does not equal VK_WHOLE_SIZE, range must be greater than 0.",
   3807                             range);
   3808         }
   3809         // Range must be a multiple of the element size of format
   3810         const size_t format_size = FormatElementSize(pCreateInfo->format);
   3811         if (range % format_size != 0) {
   3812             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3813                             HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00929",
   3814                             "If VkBufferViewCreateInfo range (%" PRIuLEAST64
   3815                             ") does not equal VK_WHOLE_SIZE, range must be a multiple of the element size of the format "
   3816                             "(" PRINTF_SIZE_T_SPECIFIER ").",
   3817                             range, format_size);
   3818         }
   3819         // Range divided by the element size of format must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements
   3820         if (range / format_size > device_limits->maxTexelBufferElements) {
   3821             skip |=
   3822                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3823                         HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00930",
   3824                         "If VkBufferViewCreateInfo range (%" PRIuLEAST64
   3825                         ") does not equal VK_WHOLE_SIZE, range divided by the element size of the format (" PRINTF_SIZE_T_SPECIFIER
   3826                         ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").",
   3827                         range, format_size, device_limits->maxTexelBufferElements);
   3828         }
   3829         // The sum of range and offset must be less than or equal to the size of buffer
   3830         if (range + pCreateInfo->offset > buffer_state->createInfo.size) {
   3831             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3832                             HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-00931",
   3833                             "If VkBufferViewCreateInfo range (%" PRIuLEAST64
   3834                             ") does not equal VK_WHOLE_SIZE, the sum of offset (%" PRIuLEAST64
   3835                             ") and range must be less than or equal to the size of the buffer (%" PRIuLEAST64 ").",
   3836                             range, pCreateInfo->offset, buffer_state->createInfo.size);
   3837         }
   3838     }
   3839     return skip;
   3840 }
   3841 
   3842 bool CoreChecks::ValidateBufferViewBuffer(const layer_data *device_data, const BUFFER_STATE *buffer_state,
   3843                                           const VkBufferViewCreateInfo *pCreateInfo) {
   3844     bool skip = false;
   3845     const VkFormatProperties format_properties = GetPDFormatProperties(pCreateInfo->format);
   3846     if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) &&
   3847         !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
   3848         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3849                         HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-00933",
   3850                         "If buffer was created with `usage` containing VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, format must "
   3851                         "be supported for uniform texel buffers");
   3852     }
   3853     if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) &&
   3854         !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
   3855         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3856                         HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-00934",
   3857                         "If buffer was created with `usage` containing VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, format must "
   3858                         "be supported for storage texel buffers");
   3859     }
   3860     return skip;
   3861 }
   3862 
   3863 bool CoreChecks::PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
   3864                                              const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
   3865     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   3866 
   3867     bool skip = false;
   3868 
   3869     // TODO: Add check for "VUID-vkCreateBuffer-flags-00911"        (sparse address space accounting)
   3870 
   3871     if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && (!GetEnabledFeatures()->core.sparseBinding)) {
   3872         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3873                         "VUID-VkBufferCreateInfo-flags-00915",
   3874                         "vkCreateBuffer(): the sparseBinding device feature is disabled: Buffers cannot be created with the "
   3875                         "VK_BUFFER_CREATE_SPARSE_BINDING_BIT set.");
   3876     }
   3877 
   3878     if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && (!GetEnabledFeatures()->core.sparseResidencyBuffer)) {
   3879         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3880                         "VUID-VkBufferCreateInfo-flags-00916",
   3881                         "vkCreateBuffer(): the sparseResidencyBuffer device feature is disabled: Buffers cannot be created with "
   3882                         "the VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT set.");
   3883     }
   3884 
   3885     if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && (!GetEnabledFeatures()->core.sparseResidencyAliased)) {
   3886         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3887                         "VUID-VkBufferCreateInfo-flags-00917",
   3888                         "vkCreateBuffer(): the sparseResidencyAliased device feature is disabled: Buffers cannot be created with "
   3889                         "the VK_BUFFER_CREATE_SPARSE_ALIASED_BIT set.");
   3890     }
   3891 
   3892     auto chained_devaddr_struct = lvl_find_in_chain<VkBufferDeviceAddressCreateInfoEXT>(pCreateInfo->pNext);
   3893     if (chained_devaddr_struct) {
   3894         if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
   3895             chained_devaddr_struct->deviceAddress != 0) {
   3896             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3897                             "VUID-VkBufferCreateInfo-deviceAddress-02604",
   3898                             "vkCreateBuffer(): Non-zero VkBufferDeviceAddressCreateInfoEXT::deviceAddress "
   3899                             "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT.");
   3900         }
   3901     }
   3902 
   3903     if ((pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
   3904         !GetEnabledFeatures()->buffer_address.bufferDeviceAddressCaptureReplay) {
   3905         skip |= log_msg(
   3906             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3907             "VUID-VkBufferCreateInfo-flags-02605",
   3908             "vkCreateBuffer(): the bufferDeviceAddressCaptureReplay device feature is disabled: Buffers cannot be created with "
   3909             "the VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT set.");
   3910     }
   3911 
   3912     if ((pCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) &&
   3913         !GetEnabledFeatures()->buffer_address.bufferDeviceAddress) {
   3914         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
   3915                         "VUID-VkBufferCreateInfo-usage-02606",
   3916                         "vkCreateBuffer(): the bufferDeviceAddress device feature is disabled: Buffers cannot be created with "
   3917                         "the VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT set.");
   3918     }
   3919 
   3920     if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
   3921         skip |=
   3922             ValidateQueueFamilies(device_data, pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
   3923                                   "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices", "VUID-VkBufferCreateInfo-sharingMode-01419",
   3924                                   "VUID-VkBufferCreateInfo-sharingMode-01419", false);
   3925     }
   3926 
   3927     return skip;
   3928 }
   3929 
   3930 void CoreChecks::PostCallRecordCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
   3931                                             const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer, VkResult result) {
   3932     if (result != VK_SUCCESS) return;
   3933     // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
   3934     GetBufferMap()->insert(std::make_pair(*pBuffer, std::unique_ptr<BUFFER_STATE>(new BUFFER_STATE(*pBuffer, pCreateInfo))));
   3935 }
   3936 
   3937 bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
   3938                                                  const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
   3939     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   3940 
   3941     bool skip = false;
   3942     BUFFER_STATE *buffer_state = GetBufferState(pCreateInfo->buffer);
   3943     // If this isn't a sparse buffer, it needs to have memory backing it at CreateBufferView time
   3944     if (buffer_state) {
   3945         skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCreateBufferView()",
   3946                                               "VUID-VkBufferViewCreateInfo-buffer-00935");
   3947         // In order to create a valid buffer view, the buffer must have been created with at least one of the following flags:
   3948         // UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
   3949         skip |= ValidateBufferUsageFlags(device_data, buffer_state,
   3950                                          VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
   3951                                          "VUID-VkBufferViewCreateInfo-buffer-00932", "vkCreateBufferView()",
   3952                                          "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
   3953 
   3954         // Buffer view offset must be less than the size of buffer
   3955         if (pCreateInfo->offset >= buffer_state->createInfo.size) {
   3956             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3957                             HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-00925",
   3958                             "VkBufferViewCreateInfo offset (%" PRIuLEAST64
   3959                             ") must be less than the size of the buffer (%" PRIuLEAST64 ").",
   3960                             pCreateInfo->offset, buffer_state->createInfo.size);
   3961         }
   3962 
   3963         const VkPhysicalDeviceLimits *device_limits = &(GetPDProperties()->limits);
   3964         // Buffer view offset must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment
   3965         if ((pCreateInfo->offset % device_limits->minTexelBufferOffsetAlignment) != 0) {
   3966             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   3967                             HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-00926",
   3968                             "VkBufferViewCreateInfo offset (%" PRIuLEAST64
   3969                             ") must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment (%" PRIuLEAST64 ").",
   3970                             pCreateInfo->offset, device_limits->minTexelBufferOffsetAlignment);
   3971         }
   3972 
   3973         skip |= ValidateBufferViewRange(device_data, buffer_state, pCreateInfo, device_limits);
   3974 
   3975         skip |= ValidateBufferViewBuffer(device_data, buffer_state, pCreateInfo);
   3976     }
   3977     return skip;
   3978 }
   3979 
   3980 void CoreChecks::PostCallRecordCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
   3981                                                 const VkAllocationCallbacks *pAllocator, VkBufferView *pView, VkResult result) {
   3982     if (result != VK_SUCCESS) return;
   3983     (*GetBufferViewMap())[*pView] = std::unique_ptr<BUFFER_VIEW_STATE>(new BUFFER_VIEW_STATE(*pView, pCreateInfo));
   3984 }
   3985 
   3986 // For the given format verify that the aspect masks make sense
   3987 bool CoreChecks::ValidateImageAspectMask(const layer_data *device_data, VkImage image, VkFormat format,
   3988                                          VkImageAspectFlags aspect_mask, const char *func_name, const char *vuid) {
   3989     bool skip = false;
   3990     VkDebugReportObjectTypeEXT objectType = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
   3991     if (image != VK_NULL_HANDLE) {
   3992         objectType = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT;
   3993     }
   3994 
   3995     if (FormatIsColor(format)) {
   3996         if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
   3997             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   3998                             "%s: Color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set.", func_name);
   3999         } else if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != aspect_mask) {
   4000             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4001                             "%s: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set.", func_name);
   4002         }
   4003     } else if (FormatIsDepthAndStencil(format)) {
   4004         if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) {
   4005             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4006                             "%s: Depth/stencil image formats must have at least one of VK_IMAGE_ASPECT_DEPTH_BIT and "
   4007                             "VK_IMAGE_ASPECT_STENCIL_BIT set.",
   4008                             func_name);
   4009         } else if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspect_mask) {
   4010             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4011                             "%s: Combination depth/stencil image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT and "
   4012                             "VK_IMAGE_ASPECT_STENCIL_BIT set.",
   4013                             func_name);
   4014         }
   4015     } else if (FormatIsDepthOnly(format)) {
   4016         if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
   4017             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4018                             "%s: Depth-only image formats must have the VK_IMAGE_ASPECT_DEPTH_BIT set.", func_name);
   4019         } else if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspect_mask) {
   4020             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4021                             "%s: Depth-only image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT set.", func_name);
   4022         }
   4023     } else if (FormatIsStencilOnly(format)) {
   4024         if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
   4025             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4026                             "%s: Stencil-only image formats must have the VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name);
   4027         } else if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspect_mask) {
   4028             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4029                             "%s: Stencil-only image formats can have only the VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name);
   4030         }
   4031     } else if (FormatIsMultiplane(format)) {
   4032         VkImageAspectFlags valid_flags = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
   4033         if (3 == FormatPlaneCount(format)) {
   4034             valid_flags = valid_flags | VK_IMAGE_ASPECT_PLANE_2_BIT;
   4035         }
   4036         if ((aspect_mask & valid_flags) != aspect_mask) {
   4037             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
   4038                             "%s: Multi-plane image formats may have only VK_IMAGE_ASPECT_COLOR_BIT or VK_IMAGE_ASPECT_PLANE_n_BITs "
   4039                             "set, where n = [0, 1, 2].",
   4040                             func_name);
   4041         }
   4042     }
   4043     return skip;
   4044 }
   4045 
   4046 bool CoreChecks::ValidateImageSubresourceRange(const layer_data *device_data, const uint32_t image_mip_count,
   4047                                                const uint32_t image_layer_count, const VkImageSubresourceRange &subresourceRange,
   4048                                                const char *cmd_name, const char *param_name, const char *image_layer_count_var_name,
   4049                                                const uint64_t image_handle, SubresourceRangeErrorCodes errorCodes) {
   4050     bool skip = false;
   4051 
   4052     // Validate mip levels
   4053     if (subresourceRange.baseMipLevel >= image_mip_count) {
   4054         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
   4055                         errorCodes.base_mip_err,
   4056                         "%s: %s.baseMipLevel (= %" PRIu32
   4057                         ") is greater or equal to the mip level count of the image (i.e. greater or equal to %" PRIu32 ").",
   4058                         cmd_name, param_name, subresourceRange.baseMipLevel, image_mip_count);
   4059     }
   4060 
   4061     if (subresourceRange.levelCount != VK_REMAINING_MIP_LEVELS) {
   4062         if (subresourceRange.levelCount == 0) {
   4063             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
   4064                             errorCodes.mip_count_err, "%s: %s.levelCount is 0.", cmd_name, param_name);
   4065         } else {
   4066             const uint64_t necessary_mip_count = uint64_t{subresourceRange.baseMipLevel} + uint64_t{subresourceRange.levelCount};
   4067 
   4068             if (necessary_mip_count > image_mip_count) {
   4069                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
   4070                                 errorCodes.mip_count_err,
   4071                                 "%s: %s.baseMipLevel + .levelCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
   4072                                 ") is greater than the mip level count of the image (i.e. greater than %" PRIu32 ").",
   4073                                 cmd_name, param_name, subresourceRange.baseMipLevel, subresourceRange.levelCount,
   4074                                 necessary_mip_count, image_mip_count);
   4075             }
   4076         }
   4077     }
   4078 
   4079     // Validate array layers
   4080     if (subresourceRange.baseArrayLayer >= image_layer_count) {
   4081         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
   4082                         errorCodes.base_layer_err,
   4083                         "%s: %s.baseArrayLayer (= %" PRIu32
   4084                         ") is greater or equal to the %s of the image when it was created (i.e. greater or equal to %" PRIu32 ").",
   4085                         cmd_name, param_name, subresourceRange.baseArrayLayer, image_layer_count_var_name, image_layer_count);
   4086     }
   4087 
   4088     if (subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS) {
   4089         if (subresourceRange.layerCount == 0) {
   4090             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
   4091                             errorCodes.layer_count_err, "%s: %s.layerCount is 0.", cmd_name, param_name);
   4092         } else {
   4093             const uint64_t necessary_layer_count =
   4094                 uint64_t{subresourceRange.baseArrayLayer} + uint64_t{subresourceRange.layerCount};
   4095 
   4096             if (necessary_layer_count > image_layer_count) {
   4097                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
   4098                                 errorCodes.layer_count_err,
   4099                                 "%s: %s.baseArrayLayer + .layerCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
   4100                                 ") is greater than the %s of the image when it was created (i.e. greater than %" PRIu32 ").",
   4101                                 cmd_name, param_name, subresourceRange.baseArrayLayer, subresourceRange.layerCount,
   4102                                 necessary_layer_count, image_layer_count_var_name, image_layer_count);
   4103             }
   4104         }
   4105     }
   4106 
   4107     return skip;
   4108 }
   4109 
   4110 bool CoreChecks::ValidateCreateImageViewSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
   4111                                                          bool is_imageview_2d_type,
   4112                                                          const VkImageSubresourceRange &subresourceRange) {
   4113     bool is_khr_maintenance1 = GetDeviceExtensions()->vk_khr_maintenance1;
   4114     bool is_image_slicable = image_state->createInfo.imageType == VK_IMAGE_TYPE_3D &&
   4115                              (image_state->createInfo.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR);
   4116     bool is_3D_to_2D_map = is_khr_maintenance1 && is_image_slicable && is_imageview_2d_type;
   4117 
   4118     const auto image_layer_count = is_3D_to_2D_map ? image_state->createInfo.extent.depth : image_state->createInfo.arrayLayers;
   4119     const auto image_layer_count_var_name = is_3D_to_2D_map ? "extent.depth" : "arrayLayers";
   4120 
   4121     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
   4122     subresourceRangeErrorCodes.base_mip_err = "VUID-VkImageViewCreateInfo-subresourceRange-01478";
   4123     subresourceRangeErrorCodes.mip_count_err = "VUID-VkImageViewCreateInfo-subresourceRange-01718";
   4124     subresourceRangeErrorCodes.base_layer_err = is_khr_maintenance1 ? (is_3D_to_2D_map ? "VUID-VkImageViewCreateInfo-image-01484"
   4125                                                                                        : "VUID-VkImageViewCreateInfo-image-01482")
   4126                                                                     : "VUID-VkImageViewCreateInfo-subresourceRange-01480";
   4127     subresourceRangeErrorCodes.layer_count_err = is_khr_maintenance1
   4128                                                      ? (is_3D_to_2D_map ? "VUID-VkImageViewCreateInfo-subresourceRange-01485"
   4129                                                                         : "VUID-VkImageViewCreateInfo-subresourceRange-01483")
   4130                                                      : "VUID-VkImageViewCreateInfo-subresourceRange-01719";
   4131 
   4132     return ValidateImageSubresourceRange(device_data, image_state->createInfo.mipLevels, image_layer_count, subresourceRange,
   4133                                          "vkCreateImageView", "pCreateInfo->subresourceRange", image_layer_count_var_name,
   4134                                          HandleToUint64(image_state->image), subresourceRangeErrorCodes);
   4135 }
   4136 
   4137 bool CoreChecks::ValidateCmdClearColorSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
   4138                                                        const VkImageSubresourceRange &subresourceRange, const char *param_name) {
   4139     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
   4140     subresourceRangeErrorCodes.base_mip_err = "VUID-vkCmdClearColorImage-baseMipLevel-01470";
   4141     subresourceRangeErrorCodes.mip_count_err = "VUID-vkCmdClearColorImage-pRanges-01692";
   4142     subresourceRangeErrorCodes.base_layer_err = "VUID-vkCmdClearColorImage-baseArrayLayer-01472";
   4143     subresourceRangeErrorCodes.layer_count_err = "VUID-vkCmdClearColorImage-pRanges-01693";
   4144 
   4145     return ValidateImageSubresourceRange(device_data, image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers,
   4146                                          subresourceRange, "vkCmdClearColorImage", param_name, "arrayLayers",
   4147                                          HandleToUint64(image_state->image), subresourceRangeErrorCodes);
   4148 }
   4149 
   4150 bool CoreChecks::ValidateCmdClearDepthSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
   4151                                                        const VkImageSubresourceRange &subresourceRange, const char *param_name) {
   4152     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
   4153     subresourceRangeErrorCodes.base_mip_err = "VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474";
   4154     subresourceRangeErrorCodes.mip_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01694";
   4155     subresourceRangeErrorCodes.base_layer_err = "VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476";
   4156     subresourceRangeErrorCodes.layer_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01695";
   4157 
   4158     return ValidateImageSubresourceRange(device_data, image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers,
   4159                                          subresourceRange, "vkCmdClearDepthStencilImage", param_name, "arrayLayers",
   4160                                          HandleToUint64(image_state->image), subresourceRangeErrorCodes);
   4161 }
   4162 
   4163 bool CoreChecks::ValidateImageBarrierSubresourceRange(const layer_data *device_data, const IMAGE_STATE *image_state,
   4164                                                       const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
   4165                                                       const char *param_name) {
   4166     SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
   4167     subresourceRangeErrorCodes.base_mip_err = "VUID-VkImageMemoryBarrier-subresourceRange-01486";
   4168     subresourceRangeErrorCodes.mip_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01724";
   4169     subresourceRangeErrorCodes.base_layer_err = "VUID-VkImageMemoryBarrier-subresourceRange-01488";
   4170     subresourceRangeErrorCodes.layer_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01725";
   4171 
   4172     return ValidateImageSubresourceRange(device_data, image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers,
   4173                                          subresourceRange, cmd_name, param_name, "arrayLayers", HandleToUint64(image_state->image),
   4174                                          subresourceRangeErrorCodes);
   4175 }
   4176 
   4177 bool CoreChecks::PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
   4178                                                 const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
   4179     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4180     bool skip = false;
   4181     IMAGE_STATE *image_state = GetImageState(pCreateInfo->image);
   4182     if (image_state) {
   4183         skip |= ValidateImageUsageFlags(
   4184             device_data, image_state,
   4185             VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
   4186                 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
   4187                 VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
   4188             false, kVUIDUndefined, "vkCreateImageView()",
   4189             "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT|SHADING_RATE_IMAGE]_BIT");
   4190         // If this isn't a sparse image, it needs to have memory backing it at CreateImageView time
   4191         skip |=
   4192             ValidateMemoryIsBoundToImage(device_data, image_state, "vkCreateImageView()", "VUID-VkImageViewCreateInfo-image-01020");
   4193         // Checks imported from image layer
   4194         skip |= ValidateCreateImageViewSubresourceRange(
   4195             device_data, image_state,
   4196             pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D || pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY,
   4197             pCreateInfo->subresourceRange);
   4198 
   4199         VkImageCreateFlags image_flags = image_state->createInfo.flags;
   4200         VkFormat image_format = image_state->createInfo.format;
   4201         VkImageUsageFlags image_usage = image_state->createInfo.usage;
   4202         VkImageTiling image_tiling = image_state->createInfo.tiling;
   4203         VkFormat view_format = pCreateInfo->format;
   4204         VkImageAspectFlags aspect_mask = pCreateInfo->subresourceRange.aspectMask;
   4205         VkImageType image_type = image_state->createInfo.imageType;
   4206         VkImageViewType view_type = pCreateInfo->viewType;
   4207 
   4208         // If there's a chained VkImageViewUsageCreateInfo struct, modify image_usage to match
   4209         auto chained_ivuci_struct = lvl_find_in_chain<VkImageViewUsageCreateInfoKHR>(pCreateInfo->pNext);
   4210         if (chained_ivuci_struct) {
   4211             if (chained_ivuci_struct->usage & ~image_usage) {
   4212                 std::stringstream ss;
   4213                 ss << "vkCreateImageView(): Chained VkImageViewUsageCreateInfo usage field (0x" << std::hex
   4214                    << chained_ivuci_struct->usage << ") must not include flags not present in underlying image's usage (0x"
   4215                    << image_usage << ").";
   4216                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4217                                 HandleToUint64(pCreateInfo->image), "VUID-VkImageViewUsageCreateInfo-usage-01587", "%s",
   4218                                 ss.str().c_str());
   4219             }
   4220 
   4221             image_usage = chained_ivuci_struct->usage;
   4222         }
   4223 
   4224         // Validate VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT state, if view/image formats differ
   4225         if ((image_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && (image_format != view_format)) {
   4226             if (FormatIsMultiplane(image_format)) {
   4227                 // View format must match the multiplane compatible format
   4228                 uint32_t plane = 3;  // invalid
   4229                 switch (aspect_mask) {
   4230                     case VK_IMAGE_ASPECT_PLANE_0_BIT:
   4231                         plane = 0;
   4232                         break;
   4233                     case VK_IMAGE_ASPECT_PLANE_1_BIT:
   4234                         plane = 1;
   4235                         break;
   4236                     case VK_IMAGE_ASPECT_PLANE_2_BIT:
   4237                         plane = 2;
   4238                         break;
   4239                     default:
   4240                         break;
   4241                 }
   4242 
   4243                 VkFormat compat_format = FindMultiplaneCompatibleFormat(image_format, plane);
   4244                 if (view_format != compat_format) {
   4245                     std::stringstream ss;
   4246                     ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
   4247                        << " is not compatible with plane " << plane << " of underlying image format "
   4248                        << string_VkFormat(image_format) << ", must be " << string_VkFormat(compat_format) << ".";
   4249                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4250                                     HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01586", "%s",
   4251                                     ss.str().c_str());
   4252                 }
   4253             } else {
   4254                 if ((!GetDeviceExtensions()->vk_khr_maintenance2 ||
   4255                      !(image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR))) {
   4256                     // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
   4257                     if (FormatCompatibilityClass(image_format) != FormatCompatibilityClass(view_format)) {
   4258                         std::stringstream ss;
   4259                         ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
   4260                            << " is not in the same format compatibility class as image ("
   4261                            << report_data->FormatHandle(pCreateInfo->image).c_str() << ")  format " << string_VkFormat(image_format)
   4262                            << ".  Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
   4263                            << "can support ImageViews with differing formats but they must be in the same compatibility class.";
   4264                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4265                                         HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01018", "%s",
   4266                                         ss.str().c_str());
   4267                     }
   4268                 }
   4269             }
   4270         } else {
   4271             // Format MUST be IDENTICAL to the format the image was created with
   4272             if (image_format != view_format) {
   4273                 std::stringstream ss;
   4274                 ss << "vkCreateImageView() format " << string_VkFormat(view_format) << " differs from image "
   4275                    << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
   4276                    << ".  Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
   4277                 skip |=
   4278                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4279                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01019", "%s", ss.str().c_str());
   4280             }
   4281         }
   4282 
   4283         // Validate correct image aspect bits for desired formats and format consistency
   4284         skip |= ValidateImageAspectMask(device_data, image_state->image, image_format, aspect_mask, "vkCreateImageView()");
   4285 
   4286         switch (image_type) {
   4287             case VK_IMAGE_TYPE_1D:
   4288                 if (view_type != VK_IMAGE_VIEW_TYPE_1D && view_type != VK_IMAGE_VIEW_TYPE_1D_ARRAY) {
   4289                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4290                                     HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
   4291                                     "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
   4292                                     string_VkImageViewType(view_type), string_VkImageType(image_type));
   4293                 }
   4294                 break;
   4295             case VK_IMAGE_TYPE_2D:
   4296                 if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
   4297                     if ((view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) &&
   4298                         !(image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
   4299                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4300                                         HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01003",
   4301                                         "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
   4302                                         string_VkImageViewType(view_type), string_VkImageType(image_type));
   4303                     } else if (view_type != VK_IMAGE_VIEW_TYPE_CUBE && view_type != VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
   4304                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4305                                         HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
   4306                                         "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
   4307                                         string_VkImageViewType(view_type), string_VkImageType(image_type));
   4308                     }
   4309                 }
   4310                 break;
   4311             case VK_IMAGE_TYPE_3D:
   4312                 if (GetDeviceExtensions()->vk_khr_maintenance1) {
   4313                     if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
   4314                         if ((view_type == VK_IMAGE_VIEW_TYPE_2D || view_type == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
   4315                             if (!(image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) {
   4316                                 skip |=
   4317                                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4318                                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01005",
   4319                                             "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
   4320                                             string_VkImageViewType(view_type), string_VkImageType(image_type));
   4321                             } else if ((image_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT |
   4322                                                        VK_IMAGE_CREATE_SPARSE_ALIASED_BIT))) {
   4323                                 skip |=
   4324                                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4325                                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
   4326                                             "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s "
   4327                                             "when the VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or "
   4328                                             "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags are enabled.",
   4329                                             string_VkImageViewType(view_type), string_VkImageType(image_type));
   4330                             }
   4331                         } else {
   4332                             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4333                                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
   4334                                             "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
   4335                                             string_VkImageViewType(view_type), string_VkImageType(image_type));
   4336                         }
   4337                     }
   4338                 } else {
   4339                     if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
   4340                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4341                                         HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
   4342                                         "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
   4343                                         string_VkImageViewType(view_type), string_VkImageType(image_type));
   4344                     }
   4345                 }
   4346                 break;
   4347             default:
   4348                 break;
   4349         }
   4350 
   4351         // External format checks needed when VK_ANDROID_external_memory_android_hardware_buffer enabled
   4352         if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
   4353             skip |= ValidateCreateImageViewANDROID(device_data, pCreateInfo);
   4354         }
   4355 
   4356         VkFormatProperties format_properties = GetPDFormatProperties(view_format);
   4357         VkFormatFeatureFlags tiling_features = (image_tiling & VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
   4358                                                                                        : format_properties.optimalTilingFeatures;
   4359 
   4360         if (tiling_features == 0) {
   4361             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4362                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-None-02273",
   4363                             "vkCreateImageView(): pCreateInfo->format %s with tiling %s has no supported format features on this "
   4364                             "physical device.",
   4365                             string_VkFormat(view_format), string_VkImageTiling(image_tiling));
   4366         } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
   4367             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4368                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02274",
   4369                             "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
   4370                             "VK_IMAGE_USAGE_SAMPLED_BIT.",
   4371                             string_VkFormat(view_format), string_VkImageTiling(image_tiling));
   4372         } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
   4373             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4374                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02275",
   4375                             "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
   4376                             "VK_IMAGE_USAGE_STORAGE_BIT.",
   4377                             string_VkFormat(view_format), string_VkImageTiling(image_tiling));
   4378         } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) &&
   4379                    !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
   4380             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4381                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02276",
   4382                             "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
   4383                             "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.",
   4384                             string_VkFormat(view_format), string_VkImageTiling(image_tiling));
   4385         } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
   4386                    !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
   4387             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4388                             HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02277",
   4389                             "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
   4390                             "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT.",
   4391                             string_VkFormat(view_format), string_VkImageTiling(image_tiling));
   4392         }
   4393 
   4394         if (image_usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) {
   4395             if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
   4396                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4397                                 HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-02086",
   4398                                 "vkCreateImageView() If image was created with usage containing "
   4399                                 "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, viewType must be "
   4400                                 "VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
   4401             }
   4402             if (view_format != VK_FORMAT_R8_UINT) {
   4403                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4404                                 HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-02087",
   4405                                 "vkCreateImageView() If image was created with usage containing "
   4406                                 "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, format must be VK_FORMAT_R8_UINT.");
   4407             }
   4408         }
   4409     }
   4410     return skip;
   4411 }
   4412 
   4413 void CoreChecks::PostCallRecordCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
   4414                                                const VkAllocationCallbacks *pAllocator, VkImageView *pView, VkResult result) {
   4415     if (result != VK_SUCCESS) return;
   4416     auto image_view_map = GetImageViewMap();
   4417     (*image_view_map)[*pView] = std::unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(*pView, pCreateInfo));
   4418 
   4419     auto image_state = GetImageState(pCreateInfo->image);
   4420     auto &sub_res_range = (*image_view_map)[*pView].get()->create_info.subresourceRange;
   4421     sub_res_range.levelCount = ResolveRemainingLevels(&sub_res_range, image_state->createInfo.mipLevels);
   4422     sub_res_range.layerCount = ResolveRemainingLayers(&sub_res_range, image_state->createInfo.arrayLayers);
   4423 }
   4424 
   4425 bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
   4426                                               uint32_t regionCount, const VkBufferCopy *pRegions) {
   4427     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4428     auto cb_node = GetCBNode(commandBuffer);
   4429     auto src_buffer_state = GetBufferState(srcBuffer);
   4430     auto dst_buffer_state = GetBufferState(dstBuffer);
   4431 
   4432     bool skip = false;
   4433     skip |=
   4434         ValidateMemoryIsBoundToBuffer(device_data, src_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-srcBuffer-00119");
   4435     skip |=
   4436         ValidateMemoryIsBoundToBuffer(device_data, dst_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-dstBuffer-00121");
   4437     // Validate that SRC & DST buffers have correct usage flags set
   4438     skip |=
   4439         ValidateBufferUsageFlags(device_data, src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
   4440                                  "VUID-vkCmdCopyBuffer-srcBuffer-00118", "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
   4441     skip |=
   4442         ValidateBufferUsageFlags(device_data, dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   4443                                  "VUID-vkCmdCopyBuffer-dstBuffer-00120", "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   4444     skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdCopyBuffer()",
   4445                                   VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
   4446                                   "VUID-vkCmdCopyBuffer-commandBuffer-cmdpool");
   4447     skip |= ValidateCmd(device_data, cb_node, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
   4448     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-renderpass");
   4449     return skip;
   4450 }
   4451 
   4452 void CoreChecks::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
   4453                                             uint32_t regionCount, const VkBufferCopy *pRegions) {
   4454     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4455     auto cb_node = GetCBNode(commandBuffer);
   4456     auto src_buffer_state = GetBufferState(srcBuffer);
   4457     auto dst_buffer_state = GetBufferState(dstBuffer);
   4458 
   4459     // Update bindings between buffers and cmd buffer
   4460     AddCommandBufferBindingBuffer(device_data, cb_node, src_buffer_state);
   4461     AddCommandBufferBindingBuffer(device_data, cb_node, dst_buffer_state);
   4462 }
   4463 
   4464 bool CoreChecks::ValidateIdleBuffer(layer_data *device_data, VkBuffer buffer) {
   4465     bool skip = false;
   4466     auto buffer_state = GetBufferState(buffer);
   4467     if (!buffer_state) {
   4468         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, HandleToUint64(buffer),
   4469                         kVUID_Core_DrawState_DoubleDestroy, "Cannot free buffer %s that has not been allocated.",
   4470                         report_data->FormatHandle(buffer).c_str());
   4471     } else {
   4472         if (buffer_state->in_use.load()) {
   4473             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
   4474                             HandleToUint64(buffer), "VUID-vkDestroyBuffer-buffer-00922",
   4475                             "Cannot free buffer %s that is in use by a command buffer.", report_data->FormatHandle(buffer).c_str());
   4476         }
   4477     }
   4478     return skip;
   4479 }
   4480 
   4481 bool CoreChecks::PreCallValidateDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
   4482     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4483     IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
   4484     VK_OBJECT obj_struct = {HandleToUint64(imageView), kVulkanObjectTypeImageView};
   4485 
   4486     bool skip = false;
   4487     if (image_view_state) {
   4488         skip |= ValidateObjectNotInUse(device_data, image_view_state, obj_struct, "vkDestroyImageView",
   4489                                        "VUID-vkDestroyImageView-imageView-01026");
   4490     }
   4491     return skip;
   4492 }
   4493 
   4494 void CoreChecks::PreCallRecordDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
   4495     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4496     IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
   4497     if (!image_view_state) return;
   4498     VK_OBJECT obj_struct = {HandleToUint64(imageView), kVulkanObjectTypeImageView};
   4499 
   4500     // Any bound cmd buffers are now invalid
   4501     InvalidateCommandBuffers(device_data, image_view_state->cb_bindings, obj_struct);
   4502     (*GetImageViewMap()).erase(imageView);
   4503 }
   4504 
   4505 bool CoreChecks::PreCallValidateDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
   4506     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4507     auto buffer_state = GetBufferState(buffer);
   4508 
   4509     bool skip = false;
   4510     if (buffer_state) {
   4511         skip |= ValidateIdleBuffer(device_data, buffer);
   4512     }
   4513     return skip;
   4514 }
   4515 
   4516 void CoreChecks::PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
   4517     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4518     if (!buffer) return;
   4519     auto buffer_state = GetBufferState(buffer);
   4520     VK_OBJECT obj_struct = {HandleToUint64(buffer), kVulkanObjectTypeBuffer};
   4521 
   4522     InvalidateCommandBuffers(device_data, buffer_state->cb_bindings, obj_struct);
   4523     for (auto mem_binding : buffer_state->GetBoundMemory()) {
   4524         auto mem_info = GetMemObjInfo(mem_binding);
   4525         if (mem_info) {
   4526             RemoveBufferMemoryRange(HandleToUint64(buffer), mem_info);
   4527         }
   4528     }
   4529     ClearMemoryObjectBindings(HandleToUint64(buffer), kVulkanObjectTypeBuffer);
   4530     EraseQFOReleaseBarriers<VkBufferMemoryBarrier>(device_data, buffer);
   4531     GetBufferMap()->erase(buffer_state->buffer);
   4532 }
   4533 
   4534 bool CoreChecks::PreCallValidateDestroyBufferView(VkDevice device, VkBufferView bufferView,
   4535                                                   const VkAllocationCallbacks *pAllocator) {
   4536     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4537     auto buffer_view_state = GetBufferViewState(bufferView);
   4538     VK_OBJECT obj_struct = {HandleToUint64(bufferView), kVulkanObjectTypeBufferView};
   4539     bool skip = false;
   4540     if (buffer_view_state) {
   4541         skip |= ValidateObjectNotInUse(device_data, buffer_view_state, obj_struct, "vkDestroyBufferView",
   4542                                        "VUID-vkDestroyBufferView-bufferView-00936");
   4543     }
   4544     return skip;
   4545 }
   4546 
   4547 void CoreChecks::PreCallRecordDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
   4548     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   4549     if (!bufferView) return;
   4550     auto buffer_view_state = GetBufferViewState(bufferView);
   4551     VK_OBJECT obj_struct = {HandleToUint64(bufferView), kVulkanObjectTypeBufferView};
   4552 
   4553     // Any bound cmd buffers are now invalid
   4554     InvalidateCommandBuffers(device_data, buffer_view_state->cb_bindings, obj_struct);
   4555     GetBufferViewMap()->erase(bufferView);
   4556 }
   4557 
   4558 bool CoreChecks::PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
   4559                                               VkDeviceSize size, uint32_t data) {
   4560     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4561     auto cb_node = GetCBNode(commandBuffer);
   4562     auto buffer_state = GetBufferState(dstBuffer);
   4563     bool skip = false;
   4564     skip |= ValidateMemoryIsBoundToBuffer(device_data, buffer_state, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-dstBuffer-00031");
   4565     skip |= ValidateCmdQueueFlags(device_data, cb_node, "vkCmdFillBuffer()",
   4566                                   VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
   4567                                   "VUID-vkCmdFillBuffer-commandBuffer-cmdpool");
   4568     skip |= ValidateCmd(device_data, cb_node, CMD_FILLBUFFER, "vkCmdFillBuffer()");
   4569     // Validate that DST buffer has correct usage flags set
   4570     skip |=
   4571         ValidateBufferUsageFlags(device_data, buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   4572                                  "VUID-vkCmdFillBuffer-dstBuffer-00029", "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   4573     skip |= InsideRenderPass(device_data, cb_node, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-renderpass");
   4574     return skip;
   4575 }
   4576 
   4577 void CoreChecks::PreCallRecordCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
   4578                                             VkDeviceSize size, uint32_t data) {
   4579     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4580     auto cb_node = GetCBNode(commandBuffer);
   4581     auto buffer_state = GetBufferState(dstBuffer);
   4582     // Update bindings between buffer and cmd buffer
   4583     AddCommandBufferBindingBuffer(device_data, cb_node, buffer_state);
   4584 }
   4585 
   4586 bool CoreChecks::ValidateBufferImageCopyData(const debug_report_data *report_data, uint32_t regionCount,
   4587                                              const VkBufferImageCopy *pRegions, IMAGE_STATE *image_state, const char *function) {
   4588     bool skip = false;
   4589 
   4590     for (uint32_t i = 0; i < regionCount; i++) {
   4591         if (image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
   4592             if ((pRegions[i].imageOffset.y != 0) || (pRegions[i].imageExtent.height != 1)) {
   4593                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4594                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-srcImage-00199",
   4595                                 "%s(): pRegion[%d] imageOffset.y is %d and imageExtent.height is %d. For 1D images these must be 0 "
   4596                                 "and 1, respectively.",
   4597                                 function, i, pRegions[i].imageOffset.y, pRegions[i].imageExtent.height);
   4598             }
   4599         }
   4600 
   4601         if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) || (image_state->createInfo.imageType == VK_IMAGE_TYPE_2D)) {
   4602             if ((pRegions[i].imageOffset.z != 0) || (pRegions[i].imageExtent.depth != 1)) {
   4603                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4604                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-srcImage-00201",
   4605                                 "%s(): pRegion[%d] imageOffset.z is %d and imageExtent.depth is %d. For 1D and 2D images these "
   4606                                 "must be 0 and 1, respectively.",
   4607                                 function, i, pRegions[i].imageOffset.z, pRegions[i].imageExtent.depth);
   4608             }
   4609         }
   4610 
   4611         if (image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
   4612             if ((0 != pRegions[i].imageSubresource.baseArrayLayer) || (1 != pRegions[i].imageSubresource.layerCount)) {
   4613                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4614                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-baseArrayLayer-00213",
   4615                                 "%s(): pRegion[%d] imageSubresource.baseArrayLayer is %d and imageSubresource.layerCount is %d. "
   4616                                 "For 3D images these must be 0 and 1, respectively.",
   4617                                 function, i, pRegions[i].imageSubresource.baseArrayLayer, pRegions[i].imageSubresource.layerCount);
   4618             }
   4619         }
   4620 
   4621         // If the the calling command's VkImage parameter's format is not a depth/stencil format,
   4622         // then bufferOffset must be a multiple of the calling command's VkImage parameter's element size
   4623         uint32_t element_size = FormatElementSize(image_state->createInfo.format);
   4624         if (!FormatIsDepthAndStencil(image_state->createInfo.format) && SafeModulo(pRegions[i].bufferOffset, element_size) != 0) {
   4625             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4626                             HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00193",
   4627                             "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64
   4628                             " must be a multiple of this format's texel size (%" PRIu32 ").",
   4629                             function, i, pRegions[i].bufferOffset, element_size);
   4630         }
   4631 
   4632         //  BufferOffset must be a multiple of 4
   4633         if (SafeModulo(pRegions[i].bufferOffset, 4) != 0) {
   4634             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4635                             HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00194",
   4636                             "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64 " must be a multiple of 4.", function, i,
   4637                             pRegions[i].bufferOffset);
   4638         }
   4639 
   4640         //  BufferRowLength must be 0, or greater than or equal to the width member of imageExtent
   4641         if ((pRegions[i].bufferRowLength != 0) && (pRegions[i].bufferRowLength < pRegions[i].imageExtent.width)) {
   4642             skip |=
   4643                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4644                         HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferRowLength-00195",
   4645                         "%s(): pRegion[%d] bufferRowLength (%d) must be zero or greater-than-or-equal-to imageExtent.width (%d).",
   4646                         function, i, pRegions[i].bufferRowLength, pRegions[i].imageExtent.width);
   4647         }
   4648 
   4649         //  BufferImageHeight must be 0, or greater than or equal to the height member of imageExtent
   4650         if ((pRegions[i].bufferImageHeight != 0) && (pRegions[i].bufferImageHeight < pRegions[i].imageExtent.height)) {
   4651             skip |= log_msg(
   4652                 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4653                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferImageHeight-00196",
   4654                 "%s(): pRegion[%d] bufferImageHeight (%d) must be zero or greater-than-or-equal-to imageExtent.height (%d).",
   4655                 function, i, pRegions[i].bufferImageHeight, pRegions[i].imageExtent.height);
   4656         }
   4657 
   4658         // subresource aspectMask must have exactly 1 bit set
   4659         const int num_bits = sizeof(VkFlags) * CHAR_BIT;
   4660         std::bitset<num_bits> aspect_mask_bits(pRegions[i].imageSubresource.aspectMask);
   4661         if (aspect_mask_bits.count() != 1) {
   4662             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4663                             HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-aspectMask-00212",
   4664                             "%s: aspectMasks for imageSubresource in each region must have only a single bit set.", function);
   4665         }
   4666 
   4667         // image subresource aspect bit must match format
   4668         if (!VerifyAspectsPresent(pRegions[i].imageSubresource.aspectMask, image_state->createInfo.format)) {
   4669             skip |= log_msg(
   4670                 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4671                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-aspectMask-00211",
   4672                 "%s(): pRegion[%d] subresource aspectMask 0x%x specifies aspects that are not present in image format 0x%x.",
   4673                 function, i, pRegions[i].imageSubresource.aspectMask, image_state->createInfo.format);
   4674         }
   4675 
   4676         // Checks that apply only to compressed images
   4677         if (FormatIsCompressed(image_state->createInfo.format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
   4678             auto block_size = FormatTexelBlockExtent(image_state->createInfo.format);
   4679 
   4680             //  BufferRowLength must be a multiple of block width
   4681             if (SafeModulo(pRegions[i].bufferRowLength, block_size.width) != 0) {
   4682                 skip |= log_msg(
   4683                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4684                     HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferRowLength-00203",
   4685                     "%s(): pRegion[%d] bufferRowLength (%d) must be a multiple of the compressed image's texel width (%d)..",
   4686                     function, i, pRegions[i].bufferRowLength, block_size.width);
   4687             }
   4688 
   4689             //  BufferRowHeight must be a multiple of block height
   4690             if (SafeModulo(pRegions[i].bufferImageHeight, block_size.height) != 0) {
   4691                 skip |= log_msg(
   4692                     report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4693                     HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferImageHeight-00204",
   4694                     "%s(): pRegion[%d] bufferImageHeight (%d) must be a multiple of the compressed image's texel height (%d)..",
   4695                     function, i, pRegions[i].bufferImageHeight, block_size.height);
   4696             }
   4697 
   4698             //  image offsets must be multiples of block dimensions
   4699             if ((SafeModulo(pRegions[i].imageOffset.x, block_size.width) != 0) ||
   4700                 (SafeModulo(pRegions[i].imageOffset.y, block_size.height) != 0) ||
   4701                 (SafeModulo(pRegions[i].imageOffset.z, block_size.depth) != 0)) {
   4702                 skip |=
   4703                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4704                             HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageOffset-00205",
   4705                             "%s(): pRegion[%d] imageOffset(x,y) (%d, %d) must be multiples of the compressed image's texel "
   4706                             "width & height (%d, %d)..",
   4707                             function, i, pRegions[i].imageOffset.x, pRegions[i].imageOffset.y, block_size.width, block_size.height);
   4708             }
   4709 
   4710             // bufferOffset must be a multiple of block size (linear bytes)
   4711             uint32_t block_size_in_bytes = FormatElementSize(image_state->createInfo.format);
   4712             if (SafeModulo(pRegions[i].bufferOffset, block_size_in_bytes) != 0) {
   4713                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4714                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00206",
   4715                                 "%s(): pRegion[%d] bufferOffset (0x%" PRIxLEAST64
   4716                                 ") must be a multiple of the compressed image's texel block size (%" PRIu32 ")..",
   4717                                 function, i, pRegions[i].bufferOffset, block_size_in_bytes);
   4718             }
   4719 
   4720             // imageExtent width must be a multiple of block width, or extent+offset width must equal subresource width
   4721             VkExtent3D mip_extent = GetImageSubresourceExtent(image_state, &(pRegions[i].imageSubresource));
   4722             if ((SafeModulo(pRegions[i].imageExtent.width, block_size.width) != 0) &&
   4723                 (pRegions[i].imageExtent.width + pRegions[i].imageOffset.x != mip_extent.width)) {
   4724                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4725                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageExtent-00207",
   4726                                 "%s(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block width "
   4727                                 "(%d), or when added to offset.x (%d) must equal the image subresource width (%d)..",
   4728                                 function, i, pRegions[i].imageExtent.width, block_size.width, pRegions[i].imageOffset.x,
   4729                                 mip_extent.width);
   4730             }
   4731 
   4732             // imageExtent height must be a multiple of block height, or extent+offset height must equal subresource height
   4733             if ((SafeModulo(pRegions[i].imageExtent.height, block_size.height) != 0) &&
   4734                 (pRegions[i].imageExtent.height + pRegions[i].imageOffset.y != mip_extent.height)) {
   4735                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4736                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageExtent-00208",
   4737                                 "%s(): pRegion[%d] extent height (%d) must be a multiple of the compressed texture block height "
   4738                                 "(%d), or when added to offset.y (%d) must equal the image subresource height (%d)..",
   4739                                 function, i, pRegions[i].imageExtent.height, block_size.height, pRegions[i].imageOffset.y,
   4740                                 mip_extent.height);
   4741             }
   4742 
   4743             // imageExtent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
   4744             if ((SafeModulo(pRegions[i].imageExtent.depth, block_size.depth) != 0) &&
   4745                 (pRegions[i].imageExtent.depth + pRegions[i].imageOffset.z != mip_extent.depth)) {
   4746                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   4747                                 HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageExtent-00209",
   4748                                 "%s(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block depth "
   4749                                 "(%d), or when added to offset.z (%d) must equal the image subresource depth (%d)..",
   4750                                 function, i, pRegions[i].imageExtent.depth, block_size.depth, pRegions[i].imageOffset.z,
   4751                                 mip_extent.depth);
   4752             }
   4753         }
   4754     }
   4755 
   4756     return skip;
   4757 }
   4758 
   4759 static bool ValidateImageBounds(const debug_report_data *report_data, const IMAGE_STATE *image_state, const uint32_t regionCount,
   4760                                 const VkBufferImageCopy *pRegions, const char *func_name, const char *msg_code) {
   4761     bool skip = false;
   4762     const VkImageCreateInfo *image_info = &(image_state->createInfo);
   4763 
   4764     for (uint32_t i = 0; i < regionCount; i++) {
   4765         VkExtent3D extent = pRegions[i].imageExtent;
   4766         VkOffset3D offset = pRegions[i].imageOffset;
   4767 
   4768         if (IsExtentSizeZero(&extent))  // Warn on zero area subresource
   4769         {
   4770             skip |=
   4771                 log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)0,
   4772                         kVUID_Core_Image_ZeroAreaSubregion, "%s: pRegion[%d] imageExtent of {%1d, %1d, %1d} has zero area",
   4773                         func_name, i, extent.width, extent.height, extent.depth);
   4774         }
   4775 
   4776         VkExtent3D image_extent = GetImageSubresourceExtent(image_state, &(pRegions[i].imageSubresource));
   4777 
   4778         // If we're using a compressed format, valid extent is rounded up to multiple of block size (per 18.1)
   4779         if (FormatIsCompressed(image_info->format)) {
   4780             auto block_extent = FormatTexelBlockExtent(image_info->format);
   4781             if (image_extent.width % block_extent.width) {
   4782                 image_extent.width += (block_extent.width - (image_extent.width % block_extent.width));
   4783             }
   4784             if (image_extent.height % block_extent.height) {
   4785                 image_extent.height += (block_extent.height - (image_extent.height % block_extent.height));
   4786             }
   4787             if (image_extent.depth % block_extent.depth) {
   4788                 image_extent.depth += (block_extent.depth - (image_extent.depth % block_extent.depth));
   4789             }
   4790         }
   4791 
   4792         if (0 != ExceedsBounds(&offset, &extent, &image_extent)) {
   4793             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)0,
   4794                             msg_code, "%s: pRegion[%d] exceeds image bounds..", func_name, i);
   4795         }
   4796     }
   4797 
   4798     return skip;
   4799 }
   4800 
   4801 static inline bool ValidateBufferBounds(const debug_report_data *report_data, IMAGE_STATE *image_state, BUFFER_STATE *buff_state,
   4802                                         uint32_t regionCount, const VkBufferImageCopy *pRegions, const char *func_name,
   4803                                         const char *msg_code) {
   4804     bool skip = false;
   4805 
   4806     VkDeviceSize buffer_size = buff_state->createInfo.size;
   4807 
   4808     for (uint32_t i = 0; i < regionCount; i++) {
   4809         VkExtent3D copy_extent = pRegions[i].imageExtent;
   4810 
   4811         VkDeviceSize buffer_width = (0 == pRegions[i].bufferRowLength ? copy_extent.width : pRegions[i].bufferRowLength);
   4812         VkDeviceSize buffer_height = (0 == pRegions[i].bufferImageHeight ? copy_extent.height : pRegions[i].bufferImageHeight);
   4813         VkDeviceSize unit_size = FormatElementSize(image_state->createInfo.format);  // size (bytes) of texel or block
   4814 
   4815         // Handle special buffer packing rules for specific depth/stencil formats
   4816         if (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
   4817             unit_size = FormatElementSize(VK_FORMAT_S8_UINT);
   4818         } else if (pRegions[i].imageSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) {
   4819             switch (image_state->createInfo.format) {
   4820                 case VK_FORMAT_D16_UNORM_S8_UINT:
   4821                     unit_size = FormatElementSize(VK_FORMAT_D16_UNORM);
   4822                     break;
   4823                 case VK_FORMAT_D32_SFLOAT_S8_UINT:
   4824                     unit_size = FormatElementSize(VK_FORMAT_D32_SFLOAT);
   4825                     break;
   4826                 case VK_FORMAT_X8_D24_UNORM_PACK32:  // Fall through
   4827                 case VK_FORMAT_D24_UNORM_S8_UINT:
   4828                     unit_size = 4;
   4829                     break;
   4830                 default:
   4831                     break;
   4832             }
   4833         }
   4834 
   4835         if (FormatIsCompressed(image_state->createInfo.format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
   4836             // Switch to texel block units, rounding up for any partially-used blocks
   4837             auto block_dim = FormatTexelBlockExtent(image_state->createInfo.format);
   4838             buffer_width = (buffer_width + block_dim.width - 1) / block_dim.width;
   4839             buffer_height = (buffer_height + block_dim.height - 1) / block_dim.height;
   4840 
   4841             copy_extent.width = (copy_extent.width + block_dim.width - 1) / block_dim.width;
   4842             copy_extent.height = (copy_extent.height + block_dim.height - 1) / block_dim.height;
   4843             copy_extent.depth = (copy_extent.depth + block_dim.depth - 1) / block_dim.depth;
   4844         }
   4845 
   4846         // Either depth or layerCount may be greater than 1 (not both). This is the number of 'slices' to copy
   4847         uint32_t z_copies = std::max(copy_extent.depth, pRegions[i].imageSubresource.layerCount);
   4848         if (IsExtentSizeZero(&copy_extent) || (0 == z_copies)) {
   4849             // TODO: Issue warning here? Already warned in ValidateImageBounds()...
   4850         } else {
   4851             // Calculate buffer offset of final copied byte, + 1.
   4852             VkDeviceSize max_buffer_offset = (z_copies - 1) * buffer_height * buffer_width;      // offset to slice
   4853             max_buffer_offset += ((copy_extent.height - 1) * buffer_width) + copy_extent.width;  // add row,col
   4854             max_buffer_offset *= unit_size;                                                      // convert to bytes
   4855             max_buffer_offset += pRegions[i].bufferOffset;                                       // add initial offset (bytes)
   4856 
   4857             if (buffer_size < max_buffer_offset) {
   4858                 skip |=
   4859                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)0,
   4860                             msg_code, "%s: pRegion[%d] exceeds buffer size of %" PRIu64 " bytes..", func_name, i, buffer_size);
   4861             }
   4862         }
   4863     }
   4864 
   4865     return skip;
   4866 }
   4867 
   4868 bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   4869                                                      VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
   4870     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4871     auto cb_node = GetCBNode(commandBuffer);
   4872     auto src_image_state = GetImageState(srcImage);
   4873     auto dst_buffer_state = GetBufferState(dstBuffer);
   4874 
   4875     bool skip = ValidateBufferImageCopyData(report_data, regionCount, pRegions, src_image_state, "vkCmdCopyImageToBuffer");
   4876 
   4877     // Validate command buffer state
   4878     skip |= ValidateCmd(device_data, cb_node, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
   4879 
   4880     // Command pool must support graphics, compute, or transfer operations
   4881     auto pPool = GetCommandPoolNode(cb_node->createInfo.commandPool);
   4882 
   4883     VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
   4884 
   4885     if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
   4886         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   4887                         HandleToUint64(cb_node->createInfo.commandPool), "VUID-vkCmdCopyImageToBuffer-commandBuffer-cmdpool",
   4888                         "Cannot call vkCmdCopyImageToBuffer() on a command buffer allocated from a pool without graphics, compute, "
   4889                         "or transfer capabilities..");
   4890     }
   4891     skip |= ValidateImageBounds(report_data, src_image_state, regionCount, pRegions, "vkCmdCopyImageToBuffer()",
   4892                                 "VUID-vkCmdCopyImageToBuffer-pRegions-00182");
   4893     skip |= ValidateBufferBounds(report_data, src_image_state, dst_buffer_state, regionCount, pRegions, "vkCmdCopyImageToBuffer()",
   4894                                  "VUID-vkCmdCopyImageToBuffer-pRegions-00183");
   4895 
   4896     skip |= ValidateImageSampleCount(device_data, src_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdCopyImageToBuffer(): srcImage",
   4897                                      "VUID-vkCmdCopyImageToBuffer-srcImage-00188");
   4898     skip |= ValidateMemoryIsBoundToImage(device_data, src_image_state, "vkCmdCopyImageToBuffer()",
   4899                                          "VUID-vkCmdCopyImageToBuffer-srcImage-00187");
   4900     skip |= ValidateMemoryIsBoundToBuffer(device_data, dst_buffer_state, "vkCmdCopyImageToBuffer()",
   4901                                           "VUID-vkCmdCopyImageToBuffer-dstBuffer-00192");
   4902 
   4903     // Validate that SRC image & DST buffer have correct usage flags set
   4904     skip |= ValidateImageUsageFlags(device_data, src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
   4905                                     "VUID-vkCmdCopyImageToBuffer-srcImage-00186", "vkCmdCopyImageToBuffer()",
   4906                                     "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
   4907     skip |= ValidateBufferUsageFlags(device_data, dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
   4908                                      "VUID-vkCmdCopyImageToBuffer-dstBuffer-00191", "vkCmdCopyImageToBuffer()",
   4909                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
   4910     if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
   4911         skip |= ValidateImageFormatFeatureFlags(device_data, src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT,
   4912                                                 "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-srcImage-01998",
   4913                                                 "VUID-vkCmdCopyImageToBuffer-srcImage-01998");
   4914     }
   4915     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-renderpass");
   4916     bool hit_error = false;
   4917     const char *src_invalid_layout_vuid =
   4918         (src_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   4919             ? "VUID-vkCmdCopyImageToBuffer-srcImageLayout-01397"
   4920             : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190";
   4921     for (uint32_t i = 0; i < regionCount; ++i) {
   4922         skip |= ValidateImageSubresourceLayers(device_data, cb_node, &pRegions[i].imageSubresource, "vkCmdCopyImageToBuffer()",
   4923                                                "imageSubresource", i);
   4924         skip |= VerifyImageLayout(device_data, cb_node, src_image_state, pRegions[i].imageSubresource, srcImageLayout,
   4925                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdCopyImageToBuffer()", src_invalid_layout_vuid,
   4926                                   "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00189", &hit_error);
   4927         skip |= ValidateCopyBufferImageTransferGranularityRequirements(device_data, cb_node, src_image_state, &pRegions[i], i,
   4928                                                                        "vkCmdCopyImageToBuffer()",
   4929                                                                        "VUID-vkCmdCopyImageToBuffer-imageOffset-01794");
   4930         skip |= ValidateImageMipLevel(device_data, cb_node, src_image_state, pRegions[i].imageSubresource.mipLevel, i,
   4931                                       "vkCmdCopyImageToBuffer()", "imageSubresource",
   4932                                       "VUID-vkCmdCopyImageToBuffer-imageSubresource-01703");
   4933         skip |= ValidateImageArrayLayerRange(device_data, cb_node, src_image_state, pRegions[i].imageSubresource.baseArrayLayer,
   4934                                              pRegions[i].imageSubresource.layerCount, i, "vkCmdCopyImageToBuffer()",
   4935                                              "imageSubresource", "VUID-vkCmdCopyImageToBuffer-imageSubresource-01704");
   4936     }
   4937     return skip;
   4938 }
   4939 
   4940 void CoreChecks::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
   4941                                                    VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
   4942     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4943     auto cb_node = GetCBNode(commandBuffer);
   4944     auto src_image_state = GetImageState(srcImage);
   4945     auto dst_buffer_state = GetBufferState(dstBuffer);
   4946 
   4947     // Make sure that all image slices are updated to correct layout
   4948     for (uint32_t i = 0; i < regionCount; ++i) {
   4949         SetImageLayout(device_data, cb_node, src_image_state, pRegions[i].imageSubresource, srcImageLayout);
   4950     }
   4951     // Update bindings between buffer/image and cmd buffer
   4952     AddCommandBufferBindingImage(device_data, cb_node, src_image_state);
   4953     AddCommandBufferBindingBuffer(device_data, cb_node, dst_buffer_state);
   4954 }
   4955 
   4956 bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
   4957                                                      VkImageLayout dstImageLayout, uint32_t regionCount,
   4958                                                      const VkBufferImageCopy *pRegions) {
   4959     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   4960     auto cb_node = GetCBNode(commandBuffer);
   4961     auto src_buffer_state = GetBufferState(srcBuffer);
   4962     auto dst_image_state = GetImageState(dstImage);
   4963 
   4964     bool skip = ValidateBufferImageCopyData(report_data, regionCount, pRegions, dst_image_state, "vkCmdCopyBufferToImage");
   4965 
   4966     // Validate command buffer state
   4967     skip |= ValidateCmd(device_data, cb_node, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
   4968 
   4969     // Command pool must support graphics, compute, or transfer operations
   4970     auto pPool = GetCommandPoolNode(cb_node->createInfo.commandPool);
   4971     VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
   4972     if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
   4973         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   4974                         HandleToUint64(cb_node->createInfo.commandPool), "VUID-vkCmdCopyBufferToImage-commandBuffer-cmdpool",
   4975                         "Cannot call vkCmdCopyBufferToImage() on a command buffer allocated from a pool without graphics, compute, "
   4976                         "or transfer capabilities..");
   4977     }
   4978     skip |= ValidateImageBounds(report_data, dst_image_state, regionCount, pRegions, "vkCmdCopyBufferToImage()",
   4979                                 "VUID-vkCmdCopyBufferToImage-pRegions-00172");
   4980     skip |= ValidateBufferBounds(report_data, dst_image_state, src_buffer_state, regionCount, pRegions, "vkCmdCopyBufferToImage()",
   4981                                  "VUID-vkCmdCopyBufferToImage-pRegions-00171");
   4982     skip |= ValidateImageSampleCount(device_data, dst_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdCopyBufferToImage(): dstImage",
   4983                                      "VUID-vkCmdCopyBufferToImage-dstImage-00179");
   4984     skip |= ValidateMemoryIsBoundToBuffer(device_data, src_buffer_state, "vkCmdCopyBufferToImage()",
   4985                                           "VUID-vkCmdCopyBufferToImage-srcBuffer-00176");
   4986     skip |= ValidateMemoryIsBoundToImage(device_data, dst_image_state, "vkCmdCopyBufferToImage()",
   4987                                          "VUID-vkCmdCopyBufferToImage-dstImage-00178");
   4988     skip |= ValidateBufferUsageFlags(device_data, src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
   4989                                      "VUID-vkCmdCopyBufferToImage-srcBuffer-00174", "vkCmdCopyBufferToImage()",
   4990                                      "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
   4991     skip |= ValidateImageUsageFlags(device_data, dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
   4992                                     "VUID-vkCmdCopyBufferToImage-dstImage-00177", "vkCmdCopyBufferToImage()",
   4993                                     "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
   4994     if (GetApiVersion() >= VK_API_VERSION_1_1 || GetDeviceExtensions()->vk_khr_maintenance1) {
   4995         skip |= ValidateImageFormatFeatureFlags(device_data, dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
   4996                                                 "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-dstImage-01997",
   4997                                                 "VUID-vkCmdCopyBufferToImage-dstImage-01997");
   4998     }
   4999     skip |= InsideRenderPass(device_data, cb_node, "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-renderpass");
   5000     bool hit_error = false;
   5001     const char *dst_invalid_layout_vuid =
   5002         (dst_image_state->shared_presentable && GetDeviceExtensions()->vk_khr_shared_presentable_image)
   5003             ? "VUID-vkCmdCopyBufferToImage-dstImageLayout-01396"
   5004             : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00181";
   5005     for (uint32_t i = 0; i < regionCount; ++i) {
   5006         skip |= ValidateImageSubresourceLayers(device_data, cb_node, &pRegions[i].imageSubresource, "vkCmdCopyBufferToImage()",
   5007                                                "imageSubresource", i);
   5008         skip |= VerifyImageLayout(device_data, cb_node, dst_image_state, pRegions[i].imageSubresource, dstImageLayout,
   5009                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdCopyBufferToImage()", dst_invalid_layout_vuid,
   5010                                   "VUID-vkCmdCopyBufferToImage-dstImageLayout-00180", &hit_error);
   5011         skip |= ValidateCopyBufferImageTransferGranularityRequirements(device_data, cb_node, dst_image_state, &pRegions[i], i,
   5012                                                                        "vkCmdCopyBufferToImage()",
   5013                                                                        "VUID-vkCmdCopyBufferToImage-imageOffset-01793");
   5014         skip |= ValidateImageMipLevel(device_data, cb_node, dst_image_state, pRegions[i].imageSubresource.mipLevel, i,
   5015                                       "vkCmdCopyBufferToImage()", "imageSubresource",
   5016                                       "VUID-vkCmdCopyBufferToImage-imageSubresource-01701");
   5017         skip |= ValidateImageArrayLayerRange(device_data, cb_node, dst_image_state, pRegions[i].imageSubresource.baseArrayLayer,
   5018                                              pRegions[i].imageSubresource.layerCount, i, "vkCmdCopyBufferToImage()",
   5019                                              "imageSubresource", "VUID-vkCmdCopyBufferToImage-imageSubresource-01702");
   5020     }
   5021     return skip;
   5022 }
   5023 
   5024 void CoreChecks::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
   5025                                                    VkImageLayout dstImageLayout, uint32_t regionCount,
   5026                                                    const VkBufferImageCopy *pRegions) {
   5027     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
   5028     auto cb_node = GetCBNode(commandBuffer);
   5029     auto src_buffer_state = GetBufferState(srcBuffer);
   5030     auto dst_image_state = GetImageState(dstImage);
   5031 
   5032     // Make sure that all image slices are updated to correct layout
   5033     for (uint32_t i = 0; i < regionCount; ++i) {
   5034         SetImageLayout(device_data, cb_node, dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
   5035     }
   5036     AddCommandBufferBindingBuffer(device_data, cb_node, src_buffer_state);
   5037     AddCommandBufferBindingImage(device_data, cb_node, dst_image_state);
   5038 }
   5039 
   5040 bool CoreChecks::PreCallValidateGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
   5041                                                           VkSubresourceLayout *pLayout) {
   5042     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
   5043     const auto report_data = device_data->report_data;
   5044     bool skip = false;
   5045     const VkImageAspectFlags sub_aspect = pSubresource->aspectMask;
   5046 
   5047     // The aspectMask member of pSubresource must only have a single bit set
   5048     const int num_bits = sizeof(sub_aspect) * CHAR_BIT;
   5049     std::bitset<num_bits> aspect_mask_bits(sub_aspect);
   5050     if (aspect_mask_bits.count() != 1) {
   5051         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
   5052                         "VUID-vkGetImageSubresourceLayout-aspectMask-00997",
   5053                         "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must have exactly 1 bit set.");
   5054     }
   5055 
   5056     IMAGE_STATE *image_entry = GetImageState(image);
   5057     if (!image_entry) {
   5058         return skip;
   5059     }
   5060 
   5061     // image must have been created with tiling equal to VK_IMAGE_TILING_LINEAR
   5062     if (image_entry->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
   5063         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
   5064                         "VUID-vkGetImageSubresourceLayout-image-00996",
   5065                         "vkGetImageSubresourceLayout(): Image must have tiling of VK_IMAGE_TILING_LINEAR.");
   5066     }
   5067 
   5068     // mipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created
   5069     if (pSubresource->mipLevel >= image_entry->createInfo.mipLevels) {
   5070         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
   5071                         "VUID-vkGetImageSubresourceLayout-mipLevel-01716",
   5072                         "vkGetImageSubresourceLayout(): pSubresource.mipLevel (%d) must be less than %d.", pSubresource->mipLevel,
   5073                         image_entry->createInfo.mipLevels);
   5074     }
   5075 
   5076     // arrayLayer must be less than the arrayLayers specified in VkImageCreateInfo when the image was created
   5077     if (pSubresource->arrayLayer >= image_entry->createInfo.arrayLayers) {
   5078         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
   5079                         "VUID-vkGetImageSubresourceLayout-arrayLayer-01717",
   5080                         "vkGetImageSubresourceLayout(): pSubresource.arrayLayer (%d) must be less than %d.",
   5081                         pSubresource->arrayLayer, image_entry->createInfo.arrayLayers);
   5082     }
   5083 
   5084     // subresource's aspect must be compatible with image's format.
   5085     const VkFormat img_format = image_entry->createInfo.format;
   5086     if (FormatIsMultiplane(img_format)) {
   5087         VkImageAspectFlags allowed_flags = (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
   5088         const char *vuid = "VUID-vkGetImageSubresourceLayout-format-01581";  // 2-plane version
   5089         if (FormatPlaneCount(img_format) > 2u) {
   5090             allowed_flags |= VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
   5091             vuid = "VUID-vkGetImageSubresourceLayout-format-01582";  // 3-plane version
   5092         }
   5093         if (sub_aspect != (sub_aspect & allowed_flags)) {
   5094             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   5095                             HandleToUint64(image), vuid,
   5096                             "vkGetImageSubresourceLayout(): For multi-planar images, VkImageSubresource.aspectMask (0x%" PRIx32
   5097                             ") must be a single-plane specifier flag.",
   5098                             sub_aspect);
   5099         }
   5100     } else if (FormatIsColor(img_format)) {
   5101         if (sub_aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
   5102             skip |= log_msg(
   5103                 report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
   5104                 "VUID-VkImageSubresource-aspectMask-parameter",
   5105                 "vkGetImageSubresourceLayout(): For color formats, VkImageSubresource.aspectMask must be VK_IMAGE_ASPECT_COLOR.");
   5106         }
   5107     } else if (FormatIsDepthOrStencil(img_format)) {
   5108         if ((sub_aspect != VK_IMAGE_ASPECT_DEPTH_BIT) && (sub_aspect != VK_IMAGE_ASPECT_STENCIL_BIT)) {
   5109             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   5110                             HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter",
   5111                             "vkGetImageSubresourceLayout(): For depth/stencil formats, VkImageSubresource.aspectMask must be "
   5112                             "either VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT.");
   5113         }
   5114     }
   5115 
   5116     if (GetDeviceExtensions()->vk_android_external_memory_android_hardware_buffer) {
   5117         skip |= ValidateGetImageSubresourceLayoutANDROID(device_data, image);
   5118     }
   5119 
   5120     return skip;
   5121 }
   5122