Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
      2  * Copyright (c) 2015-2016 Valve Corporation
      3  * Copyright (c) 2015-2016 LunarG, Inc.
      4  * Copyright (C) 2015-2016 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: Jeremy Hayes <jeremy (at) lunarg.com>
     19  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     20  * Author: Mike Stroyan <mike (at) LunarG.com>
     21  * Author: Tobin Ehlis <tobin (at) lunarg.com>
     22  */
     23 
     24 // Allow use of STL min and max functions in Windows
     25 #define NOMINMAX
     26 
     27 #include <algorithm>
     28 #include <assert.h>
     29 #include <cinttypes>
     30 #include <memory>
     31 #include <mutex>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <unordered_map>
     36 #include <vector>
     37 
     38 #include "vk_loader_platform.h"
     39 #include "vk_dispatch_table_helper.h"
     40 #include "vk_struct_string_helper_cpp.h"
     41 #include "vk_enum_validate_helper.h"
     42 #include "image.h"
     43 #include "vk_layer_config.h"
     44 #include "vk_layer_extension_utils.h"
     45 #include "vk_layer_table.h"
     46 #include "vk_layer_data.h"
     47 #include "vk_layer_extension_utils.h"
     48 #include "vk_layer_utils.h"
     49 #include "vk_layer_logging.h"
     50 
     51 using namespace std;
     52 
     53 namespace image {
     54 
     55 struct layer_data {
     56     VkInstance instance;
     57 
     58     debug_report_data *report_data;
     59     vector<VkDebugReportCallbackEXT> logging_callback;
     60     VkLayerDispatchTable *device_dispatch_table;
     61     VkLayerInstanceDispatchTable *instance_dispatch_table;
     62     VkPhysicalDevice physicalDevice;
     63     VkPhysicalDeviceProperties physicalDeviceProperties;
     64 
     65     unordered_map<VkImage, IMAGE_STATE> imageMap;
     66 
     67     layer_data()
     68         : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), physicalDevice(0),
     69           physicalDeviceProperties(){};
     70 };
     71 
     72 static unordered_map<void *, layer_data *> layer_data_map;
     73 static std::mutex global_lock;
     74 
     75 static void init_image(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
     76     layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_image");
     77 }
     78 
     79 static IMAGE_STATE const *getImageState(layer_data const *dev_data, VkImage image) {
     80     auto it = dev_data->imageMap.find(image);
     81     if (it == dev_data->imageMap.end()) {
     82         return nullptr;
     83     }
     84     return &it->second;
     85 }
     86 
     87 VKAPI_ATTR VkResult VKAPI_CALL
     88 CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
     89                              const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
     90     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
     91     VkResult res = my_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
     92     if (res == VK_SUCCESS) {
     93         res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback);
     94     }
     95     return res;
     96 }
     97 
     98 VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance,
     99                                                          VkDebugReportCallbackEXT msgCallback,
    100                                                          const VkAllocationCallbacks *pAllocator) {
    101     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    102     my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
    103     layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);
    104 }
    105 
    106 VKAPI_ATTR void VKAPI_CALL
    107 DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
    108                       size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
    109     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    110     my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
    111                                                             pMsg);
    112 }
    113 
    114 VKAPI_ATTR VkResult VKAPI_CALL
    115 CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
    116     VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    117 
    118     assert(chain_info->u.pLayerInfo);
    119     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
    120     PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
    121     if (fpCreateInstance == NULL) {
    122         return VK_ERROR_INITIALIZATION_FAILED;
    123     }
    124 
    125     // Advance the link info for the next element on the chain
    126     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    127 
    128     VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
    129     if (result != VK_SUCCESS)
    130         return result;
    131 
    132     layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
    133     my_data->instance = *pInstance;
    134     my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
    135     layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
    136 
    137     my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance,
    138                                                         pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
    139 
    140     init_image(my_data, pAllocator);
    141 
    142     return result;
    143 }
    144 
    145 VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
    146     // Grab the key before the instance is destroyed.
    147     dispatch_key key = get_dispatch_key(instance);
    148     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
    149     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
    150     pTable->DestroyInstance(instance, pAllocator);
    151 
    152     // Clean up logging callback, if any
    153     while (my_data->logging_callback.size() > 0) {
    154         VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
    155         layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
    156         my_data->logging_callback.pop_back();
    157     }
    158 
    159     layer_debug_report_destroy_instance(my_data->report_data);
    160     delete my_data->instance_dispatch_table;
    161     layer_data_map.erase(key);
    162 }
    163 
    164 VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physicalDevice,
    165                                             const VkDeviceCreateInfo *pCreateInfo,
    166                                             const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
    167     layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    168     VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    169 
    170     assert(chain_info->u.pLayerInfo);
    171     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
    172     PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
    173     PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
    174     if (fpCreateDevice == NULL) {
    175         return VK_ERROR_INITIALIZATION_FAILED;
    176     }
    177 
    178     // Advance the link info for the next element on the chain
    179     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    180 
    181     VkResult result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
    182     if (result != VK_SUCCESS) {
    183         return result;
    184     }
    185 
    186     layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
    187 
    188     // Setup device dispatch table
    189     my_device_data->device_dispatch_table = new VkLayerDispatchTable;
    190     layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
    191 
    192     my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
    193     my_device_data->physicalDevice = physicalDevice;
    194 
    195     my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice,
    196                                                                            &(my_device_data->physicalDeviceProperties));
    197 
    198     return result;
    199 }
    200 
    201 VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
    202     dispatch_key key = get_dispatch_key(device);
    203     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
    204     my_data->device_dispatch_table->DestroyDevice(device, pAllocator);
    205     delete my_data->device_dispatch_table;
    206     layer_data_map.erase(key);
    207 }
    208 
    209 static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
    210 
    211 static const VkLayerProperties global_layer = {
    212     "VK_LAYER_LUNARG_image", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
    213 };
    214 
    215 // Start of the Image layer proper
    216 
    217 static inline uint32_t validate_VkImageLayoutKHR(VkImageLayout input_value) {
    218     return ((validate_VkImageLayout(input_value) == 1) || (input_value == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR));
    219 }
    220 
    221 VKAPI_ATTR VkResult VKAPI_CALL CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
    222                                            const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
    223     bool skip_call = false;
    224     VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
    225     VkImageFormatProperties ImageFormatProperties;
    226 
    227     layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
    228     VkPhysicalDevice physicalDevice = device_data->physicalDevice;
    229     layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    230 
    231     if (pCreateInfo->format != VK_FORMAT_UNDEFINED) {
    232         VkFormatProperties properties;
    233         phy_dev_data->instance_dispatch_table->GetPhysicalDeviceFormatProperties(device_data->physicalDevice, pCreateInfo->format,
    234                                                                                  &properties);
    235         if ((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0)) {
    236             std::stringstream ss;
    237             ss << "vkCreateImage format parameter (" << string_VkFormat(pCreateInfo->format) << ") is an unsupported format";
    238             // TODO: Verify against Valid Use section of spec. Generally if something yield an undefined result, it's invalid
    239             skip_call |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
    240                                  0, __LINE__, IMAGE_FORMAT_UNSUPPORTED, "IMAGE", "%s", ss.str().c_str());
    241         }
    242 
    243         // Validate that format supports usage as color attachment
    244         if (pCreateInfo->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
    245             if ((pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL) &&
    246                 ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)) {
    247                 std::stringstream ss;
    248                 ss << "vkCreateImage: VkFormat for TILING_OPTIMAL image (" << string_VkFormat(pCreateInfo->format)
    249                    << ") does not support requested Image usage type VK_IMAGE_USAGE_COLOR_ATTACHMENT";
    250                 skip_call |=
    251                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
    252                             __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
    253             }
    254             if ((pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) &&
    255                 ((properties.linearTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)) {
    256                 std::stringstream ss;
    257                 ss << "vkCreateImage: VkFormat for TILING_LINEAR image (" << string_VkFormat(pCreateInfo->format)
    258                    << ") does not support requested Image usage type VK_IMAGE_USAGE_COLOR_ATTACHMENT";
    259                 skip_call |=
    260                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
    261                             __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
    262             }
    263         }
    264         // Validate that format supports usage as depth/stencil attachment
    265         if (pCreateInfo->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
    266             if ((pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL) &&
    267                 ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)) {
    268                 std::stringstream ss;
    269                 ss << "vkCreateImage: VkFormat for TILING_OPTIMAL image (" << string_VkFormat(pCreateInfo->format)
    270                    << ") does not support requested Image usage type VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT";
    271                 skip_call |=
    272                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
    273                             __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
    274             }
    275             if ((pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) &&
    276                 ((properties.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)) {
    277                 std::stringstream ss;
    278                 ss << "vkCreateImage: VkFormat for TILING_LINEAR image (" << string_VkFormat(pCreateInfo->format)
    279                    << ") does not support requested Image usage type VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT";
    280                 skip_call |=
    281                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
    282                             __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
    283             }
    284         }
    285     } else {
    286         skip_call |=
    287             log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
    288                     IMAGE_INVALID_FORMAT, "IMAGE", "vkCreateImage: VkFormat for image must not be VK_FORMAT_UNDEFINED");
    289     }
    290 
    291     // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
    292     phy_dev_data->instance_dispatch_table->GetPhysicalDeviceImageFormatProperties(
    293         physicalDevice, pCreateInfo->format, pCreateInfo->imageType, pCreateInfo->tiling, pCreateInfo->usage, pCreateInfo->flags,
    294         &ImageFormatProperties);
    295 
    296     VkDeviceSize imageGranularity = device_data->physicalDeviceProperties.limits.bufferImageGranularity;
    297     imageGranularity = imageGranularity == 1 ? 0 : imageGranularity;
    298 
    299     // Make sure all required dimension are non-zero at least.
    300     bool failedMinSize = false;
    301     switch (pCreateInfo->imageType) {
    302     case VK_IMAGE_TYPE_3D:
    303         if (pCreateInfo->extent.depth == 0) {
    304             failedMinSize = true;
    305         }
    306     // Intentional fall-through
    307     case VK_IMAGE_TYPE_2D:
    308         if (pCreateInfo->extent.height == 0) {
    309             failedMinSize = true;
    310         }
    311     // Intentional fall-through
    312     case VK_IMAGE_TYPE_1D:
    313         if (pCreateInfo->extent.width == 0) {
    314             failedMinSize = true;
    315         }
    316         break;
    317     default:
    318         break;
    319     }
    320     if (failedMinSize) {
    321         skip_call |=
    322             log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    323                     0, __LINE__, IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image",
    324                     "CreateImage extents is 0 for at least one required dimension for image of type %d: "
    325                     "Width = %d Height = %d Depth = %d.",
    326                     pCreateInfo->imageType, pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth);
    327     }
    328 
    329     if ((pCreateInfo->extent.depth > ImageFormatProperties.maxExtent.depth) ||
    330         (pCreateInfo->extent.width > ImageFormatProperties.maxExtent.width) ||
    331         (pCreateInfo->extent.height > ImageFormatProperties.maxExtent.height)) {
    332         skip_call |= log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    333                             0, __LINE__, IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image",
    334                             "CreateImage extents exceed allowable limits for format: "
    335                             "Width = %d Height = %d Depth = %d:  Limits for Width = %d Height = %d Depth = %d for format %s.",
    336                             pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->extent.depth,
    337                             ImageFormatProperties.maxExtent.width, ImageFormatProperties.maxExtent.height,
    338                             ImageFormatProperties.maxExtent.depth, string_VkFormat(pCreateInfo->format));
    339     }
    340 
    341     uint64_t totalSize = ((uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height *
    342                               (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers *
    343                               (uint64_t)pCreateInfo->samples * (uint64_t)vk_format_get_size(pCreateInfo->format) +
    344                           (uint64_t)imageGranularity) &
    345                          ~(uint64_t)imageGranularity;
    346 
    347     if (totalSize > ImageFormatProperties.maxResourceSize) {
    348         skip_call |= log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    349                             0, __LINE__, IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image",
    350                             "CreateImage resource size exceeds allowable maximum "
    351                             "Image resource size = 0x%" PRIxLEAST64 ", maximum resource size = 0x%" PRIxLEAST64 " ",
    352                             totalSize, ImageFormatProperties.maxResourceSize);
    353     }
    354 
    355     if (pCreateInfo->mipLevels > ImageFormatProperties.maxMipLevels) {
    356         skip_call |= log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    357                             0, __LINE__, IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image",
    358                             "CreateImage mipLevels=%d exceeds allowable maximum supported by format of %d", pCreateInfo->mipLevels,
    359                             ImageFormatProperties.maxMipLevels);
    360     }
    361 
    362     if (pCreateInfo->arrayLayers > ImageFormatProperties.maxArrayLayers) {
    363         skip_call |= log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    364                             0, __LINE__, IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image",
    365                             "CreateImage arrayLayers=%d exceeds allowable maximum supported by format of %d",
    366                             pCreateInfo->arrayLayers, ImageFormatProperties.maxArrayLayers);
    367     }
    368 
    369     if ((pCreateInfo->samples & ImageFormatProperties.sampleCounts) == 0) {
    370         skip_call |= log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    371                             0, __LINE__, IMAGE_INVALID_FORMAT_LIMITS_VIOLATION, "Image",
    372                             "CreateImage samples %s is not supported by format 0x%.8X",
    373                             string_VkSampleCountFlagBits(pCreateInfo->samples), ImageFormatProperties.sampleCounts);
    374     }
    375 
    376     if (pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && pCreateInfo->initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) {
    377         skip_call |= log_msg(phy_dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    378                             0, __LINE__, IMAGE_INVALID_LAYOUT, "Image",
    379                             "vkCreateImage parameter, pCreateInfo->initialLayout, must be VK_IMAGE_LAYOUT_UNDEFINED or "
    380                             "VK_IMAGE_LAYOUT_PREINITIALIZED");
    381     }
    382 
    383     if (!skip_call) {
    384         result = device_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage);
    385     }
    386     if (result == VK_SUCCESS) {
    387         std::lock_guard<std::mutex> lock(global_lock);
    388         device_data->imageMap[*pImage] = IMAGE_STATE(pCreateInfo);
    389     }
    390     return result;
    391 }
    392 
    393 VKAPI_ATTR void VKAPI_CALL DestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
    394     layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
    395     std::unique_lock<std::mutex> lock(global_lock);
    396     device_data->imageMap.erase(image);
    397     lock.unlock();
    398     device_data->device_dispatch_table->DestroyImage(device, image, pAllocator);
    399 }
    400 
    401 VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
    402                                                 const VkAllocationCallbacks *pAllocator,
    403                                                 VkRenderPass *pRenderPass) {
    404     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
    405     bool skipCall = false;
    406 
    407     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
    408         if (!validate_VkImageLayoutKHR(pCreateInfo->pAttachments[i].initialLayout) ||
    409             !validate_VkImageLayoutKHR(pCreateInfo->pAttachments[i].finalLayout)) {
    410             std::stringstream ss;
    411             ss << "vkCreateRenderPass parameter, VkImageLayout in pCreateInfo->pAttachments[" << i << "], is unrecognized";
    412             // TODO: Verify against Valid Use section of spec. Generally if something yield an undefined result, it's invalid
    413             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    414                                 IMAGE_RENDERPASS_INVALID_ATTACHMENT, "IMAGE", "%s", ss.str().c_str());
    415         }
    416     }
    417 
    418     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
    419         if (!validate_VkAttachmentLoadOp(pCreateInfo->pAttachments[i].loadOp)) {
    420             std::stringstream ss;
    421             ss << "vkCreateRenderPass parameter, VkAttachmentLoadOp in pCreateInfo->pAttachments[" << i << "], is unrecognized";
    422             // TODO: Verify against Valid Use section of spec. Generally if something yield an undefined result, it's invalid
    423             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    424                                 IMAGE_RENDERPASS_INVALID_ATTACHMENT, "IMAGE", "%s", ss.str().c_str());
    425         }
    426     }
    427 
    428     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
    429         if (!validate_VkAttachmentStoreOp(pCreateInfo->pAttachments[i].storeOp)) {
    430             std::stringstream ss;
    431             ss << "vkCreateRenderPass parameter, VkAttachmentStoreOp in pCreateInfo->pAttachments[" << i << "], is unrecognized";
    432             // TODO: Verify against Valid Use section of spec. Generally if something yield an undefined result, it's invalid
    433             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    434                                 IMAGE_RENDERPASS_INVALID_ATTACHMENT, "IMAGE", "%s", ss.str().c_str());
    435         }
    436     }
    437 
    438     // Any depth buffers specified as attachments?
    439     bool depthFormatPresent = false;
    440     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
    441         depthFormatPresent |= vk_format_is_depth_or_stencil(pCreateInfo->pAttachments[i].format);
    442     }
    443 
    444     if (!depthFormatPresent) {
    445         // No depth attachment is present, validate that subpasses set depthStencilAttachment to VK_ATTACHMENT_UNUSED;
    446         for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
    447             if (pCreateInfo->pSubpasses[i].pDepthStencilAttachment &&
    448                 pCreateInfo->pSubpasses[i].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
    449                 std::stringstream ss;
    450                 ss << "vkCreateRenderPass has no depth/stencil attachment, yet subpass[" << i
    451                    << "] has VkSubpassDescription::depthStencilAttachment value that is not VK_ATTACHMENT_UNUSED";
    452                 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    453                                     IMAGE_RENDERPASS_INVALID_DS_ATTACHMENT, "IMAGE", "%s", ss.str().c_str());
    454             }
    455         }
    456     }
    457     if (skipCall)
    458         return VK_ERROR_VALIDATION_FAILED_EXT;
    459 
    460     VkResult result = my_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
    461 
    462     return result;
    463 }
    464 
    465 VKAPI_ATTR VkResult VKAPI_CALL CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
    466                                                const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
    467     bool skipCall = false;
    468     layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
    469     auto imageEntry = getImageState(device_data, pCreateInfo->image);
    470     if (imageEntry) {
    471         if (pCreateInfo->subresourceRange.baseMipLevel >= imageEntry->mipLevels) {
    472             std::stringstream ss;
    473             ss << "vkCreateImageView called with baseMipLevel " << pCreateInfo->subresourceRange.baseMipLevel << " for image "
    474                << pCreateInfo->image << " that only has " << imageEntry->mipLevels << " mip levels.";
    475             skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    476                                 IMAGE_VIEW_CREATE_ERROR, "IMAGE", "%s", ss.str().c_str());
    477         }
    478         if (pCreateInfo->subresourceRange.baseArrayLayer >= imageEntry->arraySize) {
    479             std::stringstream ss;
    480             ss << "vkCreateImageView called with baseArrayLayer " << pCreateInfo->subresourceRange.baseArrayLayer << " for image "
    481                << pCreateInfo->image << " that only has " << imageEntry->arraySize << " array layers.";
    482             skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    483                                 IMAGE_VIEW_CREATE_ERROR, "IMAGE", "%s", ss.str().c_str());
    484         }
    485         if (!pCreateInfo->subresourceRange.levelCount) {
    486             std::stringstream ss;
    487             ss << "vkCreateImageView called with 0 in pCreateInfo->subresourceRange.levelCount.";
    488             skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    489                                 IMAGE_VIEW_CREATE_ERROR, "IMAGE", "%s", ss.str().c_str());
    490         }
    491         if (!pCreateInfo->subresourceRange.layerCount) {
    492             std::stringstream ss;
    493             ss << "vkCreateImageView called with 0 in pCreateInfo->subresourceRange.layerCount.";
    494             skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
    495                                 IMAGE_VIEW_CREATE_ERROR, "IMAGE", "%s", ss.str().c_str());
    496         }
    497 
    498         VkImageCreateFlags imageFlags = imageEntry->flags;
    499         VkFormat imageFormat = imageEntry->format;
    500         VkFormat ivciFormat = pCreateInfo->format;
    501         VkImageAspectFlags aspectMask = pCreateInfo->subresourceRange.aspectMask;
    502 
    503         // Validate VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT state
    504         if (imageFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
    505             // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
    506             if (vk_format_get_compatibility_class(imageFormat) != vk_format_get_compatibility_class(ivciFormat)) {
    507                 std::stringstream ss;
    508                 ss << "vkCreateImageView(): ImageView format " << string_VkFormat(ivciFormat)
    509                    << " is not in the same format compatibility class as image (" << (uint64_t)pCreateInfo->image << ")  format "
    510                    << string_VkFormat(imageFormat) << ".  Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
    511                    << "can support ImageViews with differing formats but they must be in the same compatibility class.";
    512                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
    513                                     __LINE__, IMAGE_VIEW_CREATE_ERROR, "IMAGE", "%s", ss.str().c_str());
    514             }
    515         } else {
    516             // Format MUST be IDENTICAL to the format the image was created with
    517             if (imageFormat != ivciFormat) {
    518                 std::stringstream ss;
    519                 ss << "vkCreateImageView() format " << string_VkFormat(ivciFormat) << " differs from image "
    520                    << (uint64_t)pCreateInfo->image << " format " << string_VkFormat(imageFormat)
    521                    << ".  Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
    522                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
    523                                     __LINE__, IMAGE_VIEW_CREATE_ERROR, "IMAGE", "%s", ss.str().c_str());
    524             }
    525         }
    526 
    527         // Validate correct image aspect bits for desired formats and format consistency
    528         if (vk_format_is_color(imageFormat)) {
    529             if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
    530                 std::stringstream ss;
    531                 ss << "vkCreateImageView: Color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set";
    532                 skipCall |=
    533                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    534                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    535             }
    536             if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != aspectMask) {
    537                 std::stringstream ss;
    538                 ss << "vkCreateImageView: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set";
    539                 skipCall |=
    540                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    541                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    542             }
    543             if (!vk_format_is_color(ivciFormat)) {
    544                 std::stringstream ss;
    545                 ss << "vkCreateImageView: The image view's format can differ from the parent image's format, but both must be "
    546                    << "color formats.  ImageFormat is " << string_VkFormat(imageFormat) << " ImageViewFormat is "
    547                    << string_VkFormat(ivciFormat);
    548                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    549                                     (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
    550             }
    551             // TODO:  Uncompressed formats are compatible if they occupy they same number of bits per pixel.
    552             //        Compressed formats are compatible if the only difference between them is the numerical type of
    553             //        the uncompressed pixels (e.g. signed vs. unsigned, or sRGB vs. UNORM encoding).
    554         } else if (vk_format_is_depth_and_stencil(imageFormat)) {
    555             if ((aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) {
    556                 std::stringstream ss;
    557                 ss << "vkCreateImageView: Depth/stencil image formats must have at least one of VK_IMAGE_ASPECT_DEPTH_BIT and "
    558                       "VK_IMAGE_ASPECT_STENCIL_BIT set";
    559                 skipCall |=
    560                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    561                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    562             }
    563             if ((aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspectMask) {
    564                 std::stringstream ss;
    565                 ss << "vkCreateImageView: Combination depth/stencil image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT and "
    566                       "VK_IMAGE_ASPECT_STENCIL_BIT set";
    567                 skipCall |=
    568                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    569                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    570             }
    571         } else if (vk_format_is_depth_only(imageFormat)) {
    572             if ((aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
    573                 std::stringstream ss;
    574                 ss << "vkCreateImageView: Depth-only image formats must have the VK_IMAGE_ASPECT_DEPTH_BIT set";
    575                 skipCall |=
    576                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    577                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    578             }
    579             if ((aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspectMask) {
    580                 std::stringstream ss;
    581                 ss << "vkCreateImageView: Depth-only image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT set";
    582                 skipCall |=
    583                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    584                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    585             }
    586         } else if (vk_format_is_stencil_only(imageFormat)) {
    587             if ((aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
    588                 std::stringstream ss;
    589                 ss << "vkCreateImageView: Stencil-only image formats must have the VK_IMAGE_ASPECT_STENCIL_BIT set";
    590                 skipCall |=
    591                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    592                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    593             }
    594             if ((aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspectMask) {
    595                 std::stringstream ss;
    596                 ss << "vkCreateImageView: Stencil-only image formats can have only the VK_IMAGE_ASPECT_STENCIL_BIT set";
    597                 skipCall |=
    598                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    599                             (uint64_t)pCreateInfo->image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    600             }
    601         }
    602     }
    603 
    604     if (skipCall) {
    605         return VK_ERROR_VALIDATION_FAILED_EXT;
    606     }
    607 
    608     VkResult result = device_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView);
    609     return result;
    610 }
    611 
    612 VKAPI_ATTR void VKAPI_CALL CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image,
    613                                               VkImageLayout imageLayout, const VkClearColorValue *pColor,
    614                                               uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
    615     bool skipCall = false;
    616     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    617 
    618     if (imageLayout != VK_IMAGE_LAYOUT_GENERAL && imageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
    619         skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    620                             (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_LAYOUT, "IMAGE",
    621                             "vkCmdClearColorImage parameter, imageLayout, must be VK_IMAGE_LAYOUT_GENERAL or "
    622                             "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL");
    623     }
    624 
    625     // For each range, image aspect must be color only
    626     for (uint32_t i = 0; i < rangeCount; i++) {
    627         if (pRanges[i].aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
    628             char const str[] =
    629                 "vkCmdClearColorImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_COLOR_BIT";
    630             skipCall |=
    631                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    632                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
    633         }
    634     }
    635 
    636     auto image_state = getImageState(device_data, image);
    637     if (image_state) {
    638         if (vk_format_is_depth_or_stencil(image_state->format)) {
    639             char const str[] = "vkCmdClearColorImage called with depth/stencil image.";
    640             skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    641                                 reinterpret_cast<uint64_t &>(image), __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", str);
    642         } else if (vk_format_is_compressed(image_state->format)) {
    643             char const str[] = "vkCmdClearColorImage called with compressed image.";
    644             skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    645                                 reinterpret_cast<uint64_t &>(image), __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", str);
    646         }
    647     }
    648 
    649     if (!skipCall) {
    650         device_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
    651     }
    652 }
    653 
    654 VKAPI_ATTR void VKAPI_CALL
    655 CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
    656                           const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
    657                           const VkImageSubresourceRange *pRanges) {
    658     bool skipCall = false;
    659     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    660     // For each range, Image aspect must be depth or stencil or both
    661     for (uint32_t i = 0; i < rangeCount; i++) {
    662         if (((pRanges[i].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
    663             ((pRanges[i].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT)) {
    664             char const str[] = "vkCmdClearDepthStencilImage aspectMasks for all subresource ranges must be "
    665                                "set to VK_IMAGE_ASPECT_DEPTH_BIT and/or VK_IMAGE_ASPECT_STENCIL_BIT";
    666             skipCall |=
    667                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    668                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
    669         }
    670     }
    671 
    672     auto image_state = getImageState(device_data, image);
    673     if (image_state && !vk_format_is_depth_or_stencil(image_state->format)) {
    674         char const str[] = "vkCmdClearDepthStencilImage called without a depth/stencil image.";
    675         skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
    676                             reinterpret_cast<uint64_t &>(image), __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", str);
    677     }
    678 
    679     if (!skipCall) {
    680         device_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount,
    681                                                                       pRanges);
    682     }
    683 }
    684 
    685 // Returns true if [x, xoffset] and [y, yoffset] overlap
    686 static bool ranges_intersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) {
    687     bool result = false;
    688     uint32_t intersection_min = std::max(static_cast<uint32_t>(start), static_cast<uint32_t>(end));
    689     uint32_t intersection_max = std::min(static_cast<uint32_t>(start) + start_offset, static_cast<uint32_t>(end) + end_offset);
    690 
    691     if (intersection_max > intersection_min) {
    692         result = true;
    693     }
    694     return result;
    695 }
    696 
    697 // Returns true if two VkImageCopy structures overlap
    698 static bool region_intersects(const VkImageCopy *src, const VkImageCopy *dst, VkImageType type) {
    699     bool result = true;
    700     if ((src->srcSubresource.mipLevel == dst->dstSubresource.mipLevel) &&
    701         (ranges_intersect(src->srcSubresource.baseArrayLayer, src->srcSubresource.layerCount, dst->dstSubresource.baseArrayLayer,
    702                           dst->dstSubresource.layerCount))) {
    703 
    704         switch (type) {
    705         case VK_IMAGE_TYPE_3D:
    706             result &= ranges_intersect(src->srcOffset.z, src->extent.depth, dst->dstOffset.z, dst->extent.depth);
    707         // Intentionally fall through to 2D case
    708         case VK_IMAGE_TYPE_2D:
    709             result &= ranges_intersect(src->srcOffset.y, src->extent.height, dst->dstOffset.y, dst->extent.height);
    710         // Intentionally fall through to 1D case
    711         case VK_IMAGE_TYPE_1D:
    712             result &= ranges_intersect(src->srcOffset.x, src->extent.width, dst->dstOffset.x, dst->extent.width);
    713             break;
    714         default:
    715             // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
    716             assert(false);
    717         }
    718     }
    719     return result;
    720 }
    721 
    722 // Returns true if offset and extent exceed image extents
    723 static bool exceeds_bounds(const VkOffset3D *offset, const VkExtent3D *extent, const IMAGE_STATE *image) {
    724     bool result = false;
    725     // Extents/depths cannot be negative but checks left in for clarity
    726 
    727     return result;
    728 }
    729 
    730 bool cmd_copy_image_valid_usage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImage dstImage, uint32_t regionCount,
    731                                 const VkImageCopy *pRegions) {
    732 
    733     bool skipCall = false;
    734     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    735     auto srcImageEntry = getImageState(device_data, srcImage);
    736     auto dstImageEntry = getImageState(device_data, dstImage);
    737 
    738     // TODO: This does not cover swapchain-created images. This should fall out when this layer is moved
    739     // into the core_validation layer
    740     if (srcImageEntry && dstImageEntry) {
    741 
    742         for (uint32_t i = 0; i < regionCount; i++) {
    743 
    744             if (pRegions[i].srcSubresource.layerCount == 0) {
    745                 std::stringstream ss;
    746                 ss << "vkCmdCopyImage: number of layers in pRegions[" << i << "] srcSubresource is zero";
    747                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
    748                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    749                                     __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    750             }
    751 
    752             if (pRegions[i].dstSubresource.layerCount == 0) {
    753                 std::stringstream ss;
    754                 ss << "vkCmdCopyImage: number of layers in pRegions[" << i << "] dstSubresource is zero";
    755                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
    756                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    757                                     __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    758             }
    759 
    760             // For each region the layerCount member of srcSubresource and dstSubresource must match
    761             if (pRegions[i].srcSubresource.layerCount != pRegions[i].dstSubresource.layerCount) {
    762                 std::stringstream ss;
    763                 ss << "vkCmdCopyImage: number of layers in source and destination subresources for pRegions[" << i
    764                    << "] do not match";
    765                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    766                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    767                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    768             }
    769 
    770             // For each region, the aspectMask member of srcSubresource and dstSubresource must match
    771             if (pRegions[i].srcSubresource.aspectMask != pRegions[i].dstSubresource.aspectMask) {
    772                 char const str[] = "vkCmdCopyImage: Src and dest aspectMasks for each region must match";
    773                 skipCall |=
    774                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    775                             reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
    776             }
    777 
    778             // AspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT
    779             if ((pRegions[i].srcSubresource.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) ||
    780                 (pRegions[i].dstSubresource.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT)) {
    781                 std::stringstream ss;
    782                 ss << "vkCmdCopyImage: pRegions[" << i << "] may not specify aspectMask containing VK_IMAGE_ASPECT_METADATA_BIT";
    783                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    784                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    785                                     __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
    786             }
    787 
    788             // For each region, if aspectMask contains VK_IMAGE_ASPECT_COLOR_BIT, it must not contain either of
    789             // VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT
    790             if ((pRegions[i].srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
    791                 (pRegions[i].srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
    792                 char const str[] = "vkCmdCopyImage aspectMask cannot specify both COLOR and DEPTH/STENCIL aspects";
    793                 skipCall |=
    794                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    795                             reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
    796             }
    797 
    798             // If either of the calling command's srcImage or dstImage parameters are of VkImageType VK_IMAGE_TYPE_3D,
    799             // the baseArrayLayer and layerCount members of both srcSubresource and dstSubresource must be 0 and 1, respectively
    800             if (((srcImageEntry->imageType == VK_IMAGE_TYPE_3D) || (dstImageEntry->imageType == VK_IMAGE_TYPE_3D)) &&
    801                 ((pRegions[i].srcSubresource.baseArrayLayer != 0) || (pRegions[i].srcSubresource.layerCount != 1) ||
    802                  (pRegions[i].dstSubresource.baseArrayLayer != 0) || (pRegions[i].dstSubresource.layerCount != 1))) {
    803                 std::stringstream ss;
    804                 ss << "vkCmdCopyImage: src or dstImage type was IMAGE_TYPE_3D, but in subRegion[" << i
    805                    << "] baseArrayLayer was not zero or layerCount was not 1.";
    806                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    807                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    808                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    809             }
    810 
    811             // MipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created
    812             if (pRegions[i].srcSubresource.mipLevel >= srcImageEntry->mipLevels) {
    813                 std::stringstream ss;
    814                 ss << "vkCmdCopyImage: pRegions[" << i
    815                    << "] specifies a src mipLevel greater than the number specified when the srcImage was created.";
    816                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    817                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    818                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    819             }
    820             if (pRegions[i].dstSubresource.mipLevel >= dstImageEntry->mipLevels) {
    821                 std::stringstream ss;
    822                 ss << "vkCmdCopyImage: pRegions[" << i
    823                    << "] specifies a dst mipLevel greater than the number specified when the dstImage was created.";
    824                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    825                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    826                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    827             }
    828 
    829             // (baseArrayLayer + layerCount) must be less than or equal to the arrayLayers specified in VkImageCreateInfo when the
    830             // image was created
    831             if ((pRegions[i].srcSubresource.baseArrayLayer + pRegions[i].srcSubresource.layerCount) > srcImageEntry->arraySize) {
    832                 std::stringstream ss;
    833                 ss << "vkCmdCopyImage: srcImage arrayLayers was " << srcImageEntry->arraySize << " but subRegion[" << i
    834                    << "] baseArrayLayer + layerCount is "
    835                    << (pRegions[i].srcSubresource.baseArrayLayer + pRegions[i].srcSubresource.layerCount);
    836                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    837                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    838                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    839             }
    840             if ((pRegions[i].dstSubresource.baseArrayLayer + pRegions[i].dstSubresource.layerCount) > dstImageEntry->arraySize) {
    841                 std::stringstream ss;
    842                 ss << "vkCmdCopyImage: dstImage arrayLayers was " << dstImageEntry->arraySize << " but subRegion[" << i
    843                    << "] baseArrayLayer + layerCount is "
    844                    << (pRegions[i].dstSubresource.baseArrayLayer + pRegions[i].dstSubresource.layerCount);
    845                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    846                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    847                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    848             }
    849 
    850             // The source region specified by a given element of pRegions must be a region that is contained within srcImage
    851             if (exceeds_bounds(&pRegions[i].srcOffset, &pRegions[i].extent, srcImageEntry)) {
    852                 std::stringstream ss;
    853                 ss << "vkCmdCopyImage: srcSubResource in pRegions[" << i << "] exceeds extents srcImage was created with";
    854                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    855                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    856                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    857             }
    858 
    859             // The destination region specified by a given element of pRegions must be a region that is contained within dstImage
    860             if (exceeds_bounds(&pRegions[i].dstOffset, &pRegions[i].extent, dstImageEntry)) {
    861                 std::stringstream ss;
    862                 ss << "vkCmdCopyImage: dstSubResource in pRegions[" << i << "] exceeds extents dstImage was created with";
    863                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    864                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    865                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    866             }
    867 
    868             // The union of all source regions, and the union of all destination regions, specified by the elements of pRegions,
    869             // must not overlap in memory
    870             if (srcImage == dstImage) {
    871                 for (uint32_t j = 0; j < regionCount; j++) {
    872                     if (region_intersects(&pRegions[i], &pRegions[j], srcImageEntry->imageType)) {
    873                         std::stringstream ss;
    874                         ss << "vkCmdCopyImage: pRegions[" << i << "] src overlaps with pRegions[" << j << "].";
    875                         skipCall |=
    876                             log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
    877                                     VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t &>(commandBuffer),
    878                                     __LINE__, IMAGE_INVALID_EXTENTS, "IMAGE", "%s", ss.str().c_str());
    879                     }
    880                 }
    881             }
    882         }
    883 
    884         // The formats of srcImage and dstImage must be compatible. Formats are considered compatible if their texel size in bytes
    885         // is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT because
    886         // because both texels are 4 bytes in size. Depth/stencil formats must match exactly.
    887         if (vk_format_is_depth_or_stencil(srcImageEntry->format) || vk_format_is_depth_or_stencil(dstImageEntry->format)) {
    888             if (srcImageEntry->format != dstImageEntry->format) {
    889                 char const str[] = "vkCmdCopyImage called with unmatched source and dest image depth/stencil formats.";
    890                 skipCall |=
    891                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    892                             reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, IMAGE_MISMATCHED_IMAGE_FORMAT, "IMAGE", str);
    893             }
    894         } else {
    895             size_t srcSize = vk_format_get_size(srcImageEntry->format);
    896             size_t destSize = vk_format_get_size(dstImageEntry->format);
    897             if (srcSize != destSize) {
    898                 char const str[] = "vkCmdCopyImage called with unmatched source and dest image format sizes.";
    899                 skipCall |=
    900                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    901                             reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, IMAGE_MISMATCHED_IMAGE_FORMAT, "IMAGE", str);
    902             }
    903         }
    904     }
    905     return skipCall;
    906 }
    907 
    908 VKAPI_ATTR void VKAPI_CALL CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage,
    909                                         VkImageLayout srcImageLayout, VkImage dstImage,
    910                                         VkImageLayout dstImageLayout, uint32_t regionCount,
    911                                         const VkImageCopy *pRegions) {
    912 
    913     bool skipCall = false;
    914     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    915 
    916     skipCall = cmd_copy_image_valid_usage(commandBuffer, srcImage, dstImage, regionCount, pRegions);
    917 
    918     if (!skipCall) {
    919         device_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
    920                                                          regionCount, pRegions);
    921     }
    922 }
    923 
    924 VKAPI_ATTR void VKAPI_CALL CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
    925                                                const VkClearAttachment *pAttachments, uint32_t rectCount,
    926                                                const VkClearRect *pRects) {
    927     bool skipCall = false;
    928     VkImageAspectFlags aspectMask;
    929     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    930     for (uint32_t i = 0; i < attachmentCount; i++) {
    931         aspectMask = pAttachments[i].aspectMask;
    932         if (aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
    933             if (aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
    934                 // VK_IMAGE_ASPECT_COLOR_BIT is not the only bit set for this attachment
    935                 char const str[] =
    936                     "vkCmdClearAttachments aspectMask [%d] must set only VK_IMAGE_ASPECT_COLOR_BIT of a color attachment.";
    937                 skipCall |=
    938                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    939                             (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str, i);
    940             }
    941         } else {
    942             // Image aspect must be depth or stencil or both
    943             if (((aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
    944                 ((aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT)) {
    945                 char const str[] = "vkCmdClearAttachments aspectMask [%d] must be set to VK_IMAGE_ASPECT_DEPTH_BIT and/or "
    946                                    "VK_IMAGE_ASPECT_STENCIL_BIT";
    947                 skipCall |=
    948                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    949                             (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str, i);
    950             }
    951         }
    952     }
    953 
    954     if (!skipCall) {
    955         device_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
    956     }
    957 }
    958 
    959 VKAPI_ATTR void VKAPI_CALL CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
    960                                                 VkImageLayout srcImageLayout, VkBuffer dstBuffer,
    961                                                 uint32_t regionCount, const VkBufferImageCopy *pRegions) {
    962     bool skipCall = false;
    963     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    964     // For each region, the number of layers in the image subresource should not be zero
    965     // Image aspect must be ONE OF color, depth, stencil
    966     for (uint32_t i = 0; i < regionCount; i++) {
    967         if (pRegions[i].imageSubresource.layerCount == 0) {
    968             char const str[] = "vkCmdCopyImageToBuffer: number of layers in image subresource is zero";
    969             // TODO: Verify against Valid Use section of spec, if this case yields undefined results, then it's an error
    970             skipCall |=
    971                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    972                         (uint64_t)commandBuffer, __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
    973         }
    974 
    975         VkImageAspectFlags aspectMask = pRegions[i].imageSubresource.aspectMask;
    976         if ((aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) && (aspectMask != VK_IMAGE_ASPECT_DEPTH_BIT) &&
    977             (aspectMask != VK_IMAGE_ASPECT_STENCIL_BIT)) {
    978             char const str[] = "vkCmdCopyImageToBuffer: aspectMasks for each region must specify only COLOR or DEPTH or STENCIL";
    979             skipCall |=
    980                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
    981                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
    982         }
    983     }
    984 
    985     if (!skipCall) {
    986         device_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount,
    987                                                                  pRegions);
    988     }
    989 }
    990 
    991 VKAPI_ATTR void VKAPI_CALL CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer,
    992                                                 VkImage dstImage, VkImageLayout dstImageLayout,
    993                                                 uint32_t regionCount, const VkBufferImageCopy *pRegions) {
    994     bool skipCall = false;
    995     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
    996     // For each region, the number of layers in the image subresource should not be zero
    997     // Image aspect must be ONE OF color, depth, stencil
    998     for (uint32_t i = 0; i < regionCount; i++) {
    999         if (pRegions[i].imageSubresource.layerCount == 0) {
   1000             char const str[] = "vkCmdCopyBufferToImage: number of layers in image subresource is zero";
   1001             // TODO: Verify against Valid Use section of spec, if this case yields undefined results, then it's an error
   1002             skipCall |=
   1003                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1004                         (uint64_t)commandBuffer, __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
   1005         }
   1006 
   1007         VkImageAspectFlags aspectMask = pRegions[i].imageSubresource.aspectMask;
   1008         if ((aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) && (aspectMask != VK_IMAGE_ASPECT_DEPTH_BIT) &&
   1009             (aspectMask != VK_IMAGE_ASPECT_STENCIL_BIT)) {
   1010             char const str[] = "vkCmdCopyBufferToImage: aspectMasks for each region must specify only COLOR or DEPTH or STENCIL";
   1011             skipCall |=
   1012                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1013                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
   1014         }
   1015     }
   1016 
   1017     if (!skipCall) {
   1018         device_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount,
   1019                                                                  pRegions);
   1020     }
   1021 }
   1022 
   1023 VKAPI_ATTR void VKAPI_CALL
   1024 CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
   1025              VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
   1026     bool skipCall = false;
   1027     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   1028 
   1029     auto srcImageEntry = getImageState(device_data, srcImage);
   1030     auto dstImageEntry = getImageState(device_data, dstImage);
   1031 
   1032     if (srcImageEntry && dstImageEntry) {
   1033 
   1034         VkFormat srcFormat = srcImageEntry->format;
   1035         VkFormat dstFormat = dstImageEntry->format;
   1036 
   1037         // Validate consistency for signed and unsigned formats
   1038         if ((vk_format_is_sint(srcFormat) && !vk_format_is_sint(dstFormat)) ||
   1039             (vk_format_is_uint(srcFormat) && !vk_format_is_uint(dstFormat))) {
   1040             std::stringstream ss;
   1041             ss << "vkCmdBlitImage: If one of srcImage and dstImage images has signed/unsigned integer format, "
   1042                << "the other one must also have signed/unsigned integer format.  "
   1043                << "Source format is " << string_VkFormat(srcFormat) << " Destination format is " << string_VkFormat(dstFormat);
   1044             skipCall |=
   1045                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1046                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
   1047         }
   1048 
   1049         // Validate aspect bits and formats for depth/stencil images
   1050         if (vk_format_is_depth_or_stencil(srcFormat) || vk_format_is_depth_or_stencil(dstFormat)) {
   1051             if (srcFormat != dstFormat) {
   1052                 std::stringstream ss;
   1053                 ss << "vkCmdBlitImage: If one of srcImage and dstImage images has a format of depth, stencil or depth "
   1054                    << "stencil, the other one must have exactly the same format.  "
   1055                    << "Source format is " << string_VkFormat(srcFormat) << " Destination format is " << string_VkFormat(dstFormat);
   1056                 skipCall |=
   1057                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1058                             (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_FORMAT, "IMAGE", "%s", ss.str().c_str());
   1059             }
   1060 
   1061             for (uint32_t i = 0; i < regionCount; i++) {
   1062                 if (pRegions[i].srcSubresource.layerCount == 0) {
   1063                     char const str[] = "vkCmdBlitImage: number of layers in source subresource is zero";
   1064                     // TODO: Verify against Valid Use section of spec, if this case yields undefined results, then it's an error
   1065                     skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1066                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1067                                         IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
   1068                 }
   1069 
   1070                 if (pRegions[i].dstSubresource.layerCount == 0) {
   1071                     char const str[] = "vkCmdBlitImage: number of layers in destination subresource is zero";
   1072                     // TODO: Verify against Valid Use section of spec, if this case yields undefined results, then it's an error
   1073                     skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1074                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1075                                         IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
   1076                 }
   1077 
   1078                 if (pRegions[i].srcSubresource.layerCount != pRegions[i].dstSubresource.layerCount) {
   1079                     char const str[] = "vkCmdBlitImage: number of layers in source and destination subresources must match";
   1080                     skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1081                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1082                                         IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
   1083                 }
   1084 
   1085                 VkImageAspectFlags srcAspect = pRegions[i].srcSubresource.aspectMask;
   1086                 VkImageAspectFlags dstAspect = pRegions[i].dstSubresource.aspectMask;
   1087 
   1088                 if (srcAspect != dstAspect) {
   1089                     std::stringstream ss;
   1090                     ss << "vkCmdBlitImage: Image aspects of depth/stencil images should match";
   1091                     // TODO: Verify against Valid Use section of spec, if this case yields undefined results, then it's an error
   1092                     skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1093                                         VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1094                                         IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
   1095                 }
   1096                 if (vk_format_is_depth_and_stencil(srcFormat)) {
   1097                     if ((srcAspect != VK_IMAGE_ASPECT_DEPTH_BIT) && (srcAspect != VK_IMAGE_ASPECT_STENCIL_BIT)) {
   1098                         std::stringstream ss;
   1099                         ss << "vkCmdBlitImage: Combination depth/stencil image formats must have only one of "
   1100                               "VK_IMAGE_ASPECT_DEPTH_BIT "
   1101                            << "and VK_IMAGE_ASPECT_STENCIL_BIT set in srcImage and dstImage";
   1102                         skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1103                                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1104                                             IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
   1105                     }
   1106                 } else if (vk_format_is_stencil_only(srcFormat)) {
   1107                     if (srcAspect != VK_IMAGE_ASPECT_STENCIL_BIT) {
   1108                         std::stringstream ss;
   1109                         ss << "vkCmdBlitImage: Stencil-only image formats must have only the VK_IMAGE_ASPECT_STENCIL_BIT "
   1110                            << "set in both the srcImage and dstImage";
   1111                         skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1112                                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1113                                             IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
   1114                     }
   1115                 } else if (vk_format_is_depth_only(srcFormat)) {
   1116                     if (srcAspect != VK_IMAGE_ASPECT_DEPTH_BIT) {
   1117                         std::stringstream ss;
   1118                         ss << "vkCmdBlitImage: Depth-only image formats must have only the VK_IMAGE_ASPECT_DEPTH "
   1119                            << "set in both the srcImage and dstImage";
   1120                         skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
   1121                                             VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
   1122                                             IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
   1123                     }
   1124                 }
   1125             }
   1126         }
   1127 
   1128         // Validate filter
   1129         if (vk_format_is_depth_or_stencil(srcFormat) || vk_format_is_int(srcFormat)) {
   1130             if (filter != VK_FILTER_NEAREST) {
   1131                 std::stringstream ss;
   1132                 ss << "vkCmdBlitImage: If the format of srcImage is a depth, stencil, depth stencil or integer-based format "
   1133                    << "then filter must be VK_FILTER_NEAREST.";
   1134                 skipCall |=
   1135                     log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1136                             (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_FILTER, "IMAGE", "%s", ss.str().c_str());
   1137             }
   1138         }
   1139     }
   1140 
   1141     if (!skipCall) {
   1142         device_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
   1143                                                          pRegions, filter);
   1144     }
   1145 }
   1146 
   1147 VKAPI_ATTR void VKAPI_CALL
   1148 CmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
   1149                    VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
   1150                    uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
   1151                    uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
   1152     bool skipCall = false;
   1153     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   1154 
   1155     for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
   1156         VkImageMemoryBarrier const *const barrier = (VkImageMemoryBarrier const *const) & pImageMemoryBarriers[i];
   1157         if (barrier->sType == VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER) {
   1158             if (barrier->subresourceRange.layerCount == 0) {
   1159                 std::stringstream ss;
   1160                 ss << "vkCmdPipelineBarrier called with 0 in ppMemoryBarriers[" << i << "]->subresourceRange.layerCount.";
   1161                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
   1162                                     __LINE__, IMAGE_INVALID_IMAGE_RESOURCE, "IMAGE", "%s", ss.str().c_str());
   1163             }
   1164         }
   1165     }
   1166 
   1167     if (skipCall) {
   1168         return;
   1169     }
   1170 
   1171     device_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
   1172                                                            memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
   1173                                                            pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
   1174 }
   1175 
   1176 VKAPI_ATTR void VKAPI_CALL
   1177 CmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
   1178                 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) {
   1179     bool skipCall = false;
   1180     layer_data *device_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
   1181     auto srcImageEntry = getImageState(device_data, srcImage);
   1182     auto dstImageEntry = getImageState(device_data, dstImage);
   1183 
   1184     // For each region, the number of layers in the image subresource should not be zero
   1185     // For each region, src and dest image aspect must be color only
   1186     for (uint32_t i = 0; i < regionCount; i++) {
   1187         if (pRegions[i].srcSubresource.layerCount == 0) {
   1188             char const str[] = "vkCmdResolveImage: number of layers in source subresource is zero";
   1189             // TODO: Verify against Valid Use section of spec. Generally if something yield an undefined result, it's invalid/error
   1190             skipCall |=
   1191                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1192                         (uint64_t)commandBuffer, __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
   1193         }
   1194 
   1195         if (pRegions[i].dstSubresource.layerCount == 0) {
   1196             char const str[] = "vkCmdResolveImage: number of layers in destination subresource is zero";
   1197 
   1198             // TODO: Verify against Valid Use section of spec. Generally if something yield an undefined result, it's invalid/error
   1199             skipCall |=
   1200                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1201                         (uint64_t)commandBuffer, __LINE__, IMAGE_MISMATCHED_IMAGE_ASPECT, "IMAGE", str);
   1202         }
   1203 
   1204         if ((pRegions[i].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
   1205             (pRegions[i].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)) {
   1206             char const str[] =
   1207                 "vkCmdResolveImage: src and dest aspectMasks for each region must specify only VK_IMAGE_ASPECT_COLOR_BIT";
   1208             skipCall |=
   1209                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1210                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", str);
   1211         }
   1212     }
   1213 
   1214     if (srcImageEntry && dstImageEntry) {
   1215         if (srcImageEntry->format != dstImageEntry->format) {
   1216             char const str[] = "vkCmdResolveImage called with unmatched source and dest formats.";
   1217             skipCall |=
   1218                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1219                         (uint64_t)commandBuffer, __LINE__, IMAGE_MISMATCHED_IMAGE_FORMAT, "IMAGE", str);
   1220         }
   1221         if (srcImageEntry->imageType != dstImageEntry->imageType) {
   1222             char const str[] = "vkCmdResolveImage called with unmatched source and dest image types.";
   1223             skipCall |=
   1224                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1225                         (uint64_t)commandBuffer, __LINE__, IMAGE_MISMATCHED_IMAGE_TYPE, "IMAGE", str);
   1226         }
   1227         if (srcImageEntry->samples == VK_SAMPLE_COUNT_1_BIT) {
   1228             char const str[] = "vkCmdResolveImage called with source sample count less than 2.";
   1229             skipCall |=
   1230                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1231                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_RESOLVE_SAMPLES, "IMAGE", str);
   1232         }
   1233         if (dstImageEntry->samples != VK_SAMPLE_COUNT_1_BIT) {
   1234             char const str[] = "vkCmdResolveImage called with dest sample count greater than 1.";
   1235             skipCall |=
   1236                 log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
   1237                         (uint64_t)commandBuffer, __LINE__, IMAGE_INVALID_RESOLVE_SAMPLES, "IMAGE", str);
   1238         }
   1239     }
   1240 
   1241     if (!skipCall) {
   1242         device_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
   1243                                                             regionCount, pRegions);
   1244     }
   1245 }
   1246 
   1247 VKAPI_ATTR void VKAPI_CALL
   1248 GetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) {
   1249     bool skipCall = false;
   1250     layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1251     VkFormat format;
   1252 
   1253     auto imageEntry = getImageState(device_data, image);
   1254 
   1255     // Validate that image aspects match formats
   1256     if (imageEntry) {
   1257         format = imageEntry->format;
   1258         if (vk_format_is_color(format)) {
   1259             if (pSubresource->aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
   1260                 std::stringstream ss;
   1261                 ss << "vkGetImageSubresourceLayout: For color formats, the aspectMask field of VkImageSubresource must be "
   1262                       "VK_IMAGE_ASPECT_COLOR.";
   1263                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1264                                     (uint64_t)image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
   1265             }
   1266         } else if (vk_format_is_depth_or_stencil(format)) {
   1267             if ((pSubresource->aspectMask != VK_IMAGE_ASPECT_DEPTH_BIT) &&
   1268                 (pSubresource->aspectMask != VK_IMAGE_ASPECT_STENCIL_BIT)) {
   1269                 std::stringstream ss;
   1270                 ss << "vkGetImageSubresourceLayout: For depth/stencil formats, the aspectMask selects either the depth or stencil "
   1271                       "image aspectMask.";
   1272                 skipCall |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
   1273                                     (uint64_t)image, __LINE__, IMAGE_INVALID_IMAGE_ASPECT, "IMAGE", "%s", ss.str().c_str());
   1274             }
   1275         }
   1276     }
   1277 
   1278     if (!skipCall) {
   1279         device_data->device_dispatch_table->GetImageSubresourceLayout(device, image, pSubresource, pLayout);
   1280     }
   1281 }
   1282 
   1283 VKAPI_ATTR void VKAPI_CALL
   1284 GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
   1285     layer_data *phy_dev_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   1286     phy_dev_data->instance_dispatch_table->GetPhysicalDeviceProperties(physicalDevice, pProperties);
   1287 }
   1288 
   1289 VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
   1290                                                                   const char *pLayerName, uint32_t *pCount,
   1291                                                                   VkExtensionProperties *pProperties) {
   1292     // Image does not have any physical device extensions
   1293     if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
   1294         return util_GetExtensionProperties(0, NULL, pCount, pProperties);
   1295 
   1296     assert(physicalDevice);
   1297 
   1298     dispatch_key key = get_dispatch_key(physicalDevice);
   1299     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
   1300     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   1301     return pTable->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
   1302 }
   1303 
   1304 static PFN_vkVoidFunction
   1305 intercept_core_instance_command(const char *name);
   1306 static PFN_vkVoidFunction
   1307 intercept_core_device_command(const char *name);
   1308 
   1309 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
   1310     PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
   1311     if (proc)
   1312         return proc;
   1313 
   1314     assert(device);
   1315 
   1316     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1317 
   1318     VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
   1319     {
   1320         if (pTable->GetDeviceProcAddr == NULL)
   1321             return NULL;
   1322         return pTable->GetDeviceProcAddr(device, funcName);
   1323     }
   1324 }
   1325 
   1326 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
   1327     PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
   1328     if (!proc)
   1329         proc = intercept_core_device_command(funcName);
   1330     if (proc)
   1331         return proc;
   1332 
   1333     assert(instance);
   1334     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   1335 
   1336     proc = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
   1337     if (proc)
   1338         return proc;
   1339 
   1340     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   1341     if (pTable->GetInstanceProcAddr == NULL)
   1342         return NULL;
   1343     return pTable->GetInstanceProcAddr(instance, funcName);
   1344 }
   1345 
   1346 static PFN_vkVoidFunction
   1347 intercept_core_instance_command(const char *name) {
   1348     static const struct {
   1349         const char *name;
   1350         PFN_vkVoidFunction proc;
   1351     } core_instance_commands[] = {
   1352         { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
   1353         { "vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance) },
   1354         { "vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance) },
   1355         { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
   1356         { "vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties) },
   1357         { "vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties) },
   1358     };
   1359 
   1360     // we should never be queried for these commands
   1361     assert(strcmp(name, "vkEnumerateInstanceLayerProperties") &&
   1362            strcmp(name, "vkEnumerateInstanceExtensionProperties") &&
   1363            strcmp(name, "vkEnumerateDeviceLayerProperties"));
   1364 
   1365     for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
   1366         if (!strcmp(core_instance_commands[i].name, name))
   1367             return core_instance_commands[i].proc;
   1368     }
   1369 
   1370     return nullptr;
   1371 }
   1372 
   1373 static PFN_vkVoidFunction
   1374 intercept_core_device_command(const char *name) {
   1375     static const struct {
   1376         const char *name;
   1377         PFN_vkVoidFunction proc;
   1378     } core_device_commands[] = {
   1379         { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
   1380         { "vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice) },
   1381         { "vkCreateImage", reinterpret_cast<PFN_vkVoidFunction>(CreateImage) },
   1382         { "vkDestroyImage", reinterpret_cast<PFN_vkVoidFunction>(DestroyImage) },
   1383         { "vkCreateImageView", reinterpret_cast<PFN_vkVoidFunction>(CreateImageView) },
   1384         { "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
   1385         { "vkCmdClearColorImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearColorImage) },
   1386         { "vkCmdClearDepthStencilImage", reinterpret_cast<PFN_vkVoidFunction>(CmdClearDepthStencilImage) },
   1387         { "vkCmdClearAttachments", reinterpret_cast<PFN_vkVoidFunction>(CmdClearAttachments) },
   1388         { "vkCmdCopyImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImage) },
   1389         { "vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer) },
   1390         { "vkCmdCopyBufferToImage", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyBufferToImage) },
   1391         { "vkCmdBlitImage", reinterpret_cast<PFN_vkVoidFunction>(CmdBlitImage) },
   1392         { "vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier) },
   1393         { "vkCmdResolveImage", reinterpret_cast<PFN_vkVoidFunction>(CmdResolveImage) },
   1394         { "vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
   1395     };
   1396 
   1397     for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
   1398         if (!strcmp(core_device_commands[i].name, name))
   1399             return core_device_commands[i].proc;
   1400     }
   1401 
   1402     return nullptr;
   1403 }
   1404 
   1405 } // namespace image
   1406 
   1407 // vk_layer_logging.h expects these to be defined
   1408 
   1409 VKAPI_ATTR VkResult VKAPI_CALL
   1410 vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
   1411                                const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
   1412     return image::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
   1413 }
   1414 
   1415 VKAPI_ATTR void VKAPI_CALL
   1416 vkDestroyDebugReportCallbackEXT(VkInstance instance,
   1417                                 VkDebugReportCallbackEXT msgCallback,
   1418                                 const VkAllocationCallbacks *pAllocator) {
   1419     image::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
   1420 }
   1421 
   1422 VKAPI_ATTR void VKAPI_CALL
   1423 vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
   1424                         size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
   1425     image::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
   1426 }
   1427 
   1428 // loader-layer interface v0
   1429 
   1430 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   1431 vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
   1432     return util_GetExtensionProperties(1, image::instance_extensions, pCount, pProperties);
   1433 }
   1434 
   1435 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   1436 vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
   1437     return util_GetLayerProperties(1, &image::global_layer, pCount, pProperties);
   1438 }
   1439 
   1440 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   1441 vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
   1442     return util_GetLayerProperties(1, &image::global_layer, pCount, pProperties);
   1443 }
   1444 
   1445 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
   1446                                                                                     const char *pLayerName, uint32_t *pCount,
   1447                                                                                     VkExtensionProperties *pProperties) {
   1448     // the layer command handles VK_NULL_HANDLE just fine
   1449     return image::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
   1450 }
   1451 
   1452 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
   1453     return image::GetDeviceProcAddr(dev, funcName);
   1454 }
   1455 
   1456 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
   1457     if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties"))
   1458         return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceLayerProperties);
   1459     if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties"))
   1460         return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceExtensionProperties);
   1461     if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties"))
   1462         return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateDeviceLayerProperties);
   1463     if (!strcmp(funcName, "vkGetInstanceProcAddr"))
   1464         return reinterpret_cast<PFN_vkVoidFunction>(vkGetInstanceProcAddr);
   1465 
   1466     return image::GetInstanceProcAddr(instance, funcName);
   1467 }
   1468