Home | History | Annotate | Download | only in swapchain
      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: Ian Elliott <ian (at) lunarg.com>
     19  * Author: Ian Elliott <ianelliott (at) google.com>
     20  */
     21 
     22 #include <mutex>
     23 #include <stdio.h>
     24 #include <string.h>
     25 #include <vk_loader_platform.h>
     26 #include <vulkan/vk_icd.h>
     27 #include "swapchain.h"
     28 #include "vk_layer_extension_utils.h"
     29 #include "vk_enum_string_helper.h"
     30 #include "vk_layer_utils.h"
     31 
     32 namespace swapchain {
     33 
     34 static std::mutex global_lock;
     35 
     36 // The following is for logging error messages:
     37 static std::unordered_map<void *, layer_data *> layer_data_map;
     38 
     39 static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
     40 
     41 static const VkLayerProperties swapchain_layer = {
     42     "VK_LAYER_LUNARG_swapchain", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
     43 };
     44 
     45 static void createDeviceRegisterExtensions(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
     46                                            VkDevice device) {
     47     uint32_t i;
     48     layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
     49     layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
     50 
     51     VkLayerDispatchTable *pDisp = my_device_data->device_dispatch_table;
     52     PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
     53 
     54     pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR");
     55     pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR");
     56     pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR");
     57     pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR");
     58     pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR");
     59     pDisp->GetDeviceQueue = (PFN_vkGetDeviceQueue)gpa(device, "vkGetDeviceQueue");
     60 
     61     SwpPhysicalDevice *pPhysicalDevice = NULL;
     62     {
     63         auto it = my_instance_data->physicalDeviceMap.find(physicalDevice);
     64         pPhysicalDevice = (it == my_instance_data->physicalDeviceMap.end()) ? NULL : &it->second;
     65     }
     66     if (pPhysicalDevice) {
     67         my_device_data->deviceMap[device].pPhysicalDevice = pPhysicalDevice;
     68         pPhysicalDevice->pDevice = &my_device_data->deviceMap[device];
     69     } else {
     70         // TBD: Should we leave error in (since Swapchain really needs this
     71         // link)?
     72         log_msg(my_instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
     73                 (uint64_t)physicalDevice, __LINE__, SWAPCHAIN_INVALID_HANDLE, "Swapchain",
     74                 "vkCreateDevice() called with a non-valid VkPhysicalDevice.");
     75     }
     76     my_device_data->deviceMap[device].device = device;
     77     my_device_data->deviceMap[device].swapchainExtensionEnabled = false;
     78 
     79     // Record whether the WSI device extension was enabled for this VkDevice.
     80     // No need to check if the extension was advertised by
     81     // vkEnumerateDeviceExtensionProperties(), since the loader handles that.
     82     for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
     83         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
     84 
     85             my_device_data->deviceMap[device].swapchainExtensionEnabled = true;
     86         }
     87     }
     88 }
     89 
     90 static void createInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
     91     uint32_t i;
     92     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
     93     VkLayerInstanceDispatchTable *pDisp = my_data->instance_dispatch_table;
     94     PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr;
     95 #ifdef VK_USE_PLATFORM_ANDROID_KHR
     96     pDisp->CreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)gpa(instance, "vkCreateAndroidSurfaceKHR");
     97 #endif // VK_USE_PLATFORM_ANDROID_KHR
     98 #ifdef VK_USE_PLATFORM_MIR_KHR
     99     pDisp->CreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)gpa(instance, "vkCreateMirSurfaceKHR");
    100     pDisp->GetPhysicalDeviceMirPresentationSupportKHR =
    101         (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
    102 #endif // VK_USE_PLATFORM_MIR_KHR
    103 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    104     pDisp->CreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)gpa(instance, "vkCreateWaylandSurfaceKHR");
    105     pDisp->GetPhysicalDeviceWaylandPresentationSupportKHR =
    106         (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
    107 #endif // VK_USE_PLATFORM_WAYLAND_KHR
    108 #ifdef VK_USE_PLATFORM_WIN32_KHR
    109     pDisp->CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)gpa(instance, "vkCreateWin32SurfaceKHR");
    110     pDisp->GetPhysicalDeviceWin32PresentationSupportKHR =
    111         (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
    112 #endif // VK_USE_PLATFORM_WIN32_KHR
    113 #ifdef VK_USE_PLATFORM_XCB_KHR
    114     pDisp->CreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)gpa(instance, "vkCreateXcbSurfaceKHR");
    115     pDisp->GetPhysicalDeviceXcbPresentationSupportKHR =
    116         (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
    117 #endif // VK_USE_PLATFORM_XCB_KHR
    118 #ifdef VK_USE_PLATFORM_XLIB_KHR
    119     pDisp->CreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)gpa(instance, "vkCreateXlibSurfaceKHR");
    120     pDisp->GetPhysicalDeviceXlibPresentationSupportKHR =
    121         (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR");
    122 #endif // VK_USE_PLATFORM_XLIB_KHR
    123     pDisp->DestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)gpa(instance, "vkDestroySurfaceKHR");
    124     pDisp->GetPhysicalDeviceSurfaceSupportKHR =
    125         (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
    126     pDisp->GetPhysicalDeviceSurfaceCapabilitiesKHR =
    127         (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
    128     pDisp->GetPhysicalDeviceSurfaceFormatsKHR =
    129         (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR");
    130     pDisp->GetPhysicalDeviceSurfacePresentModesKHR =
    131         (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)gpa(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR");
    132 
    133     // Remember this instance, and whether the VK_KHR_surface extension
    134     // was enabled for it:
    135     my_data->instanceMap[instance].instance = instance;
    136     my_data->instanceMap[instance].surfaceExtensionEnabled = false;
    137 #ifdef VK_USE_PLATFORM_ANDROID_KHR
    138     my_data->instanceMap[instance].androidSurfaceExtensionEnabled = false;
    139 #endif // VK_USE_PLATFORM_ANDROID_KHR
    140 #ifdef VK_USE_PLATFORM_MIR_KHR
    141     my_data->instanceMap[instance].mirSurfaceExtensionEnabled = false;
    142 #endif // VK_USE_PLATFORM_MIR_KHR
    143 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    144     my_data->instanceMap[instance].waylandSurfaceExtensionEnabled = false;
    145 #endif // VK_USE_PLATFORM_WAYLAND_KHR
    146 #ifdef VK_USE_PLATFORM_WIN32_KHR
    147     my_data->instanceMap[instance].win32SurfaceExtensionEnabled = false;
    148 #endif // VK_USE_PLATFORM_WIN32_KHR
    149 #ifdef VK_USE_PLATFORM_XCB_KHR
    150     my_data->instanceMap[instance].xcbSurfaceExtensionEnabled = false;
    151 #endif // VK_USE_PLATFORM_XCB_KHR
    152 #ifdef VK_USE_PLATFORM_XLIB_KHR
    153     my_data->instanceMap[instance].xlibSurfaceExtensionEnabled = false;
    154 #endif // VK_USE_PLATFORM_XLIB_KHR
    155 
    156     // Look for one or more debug report create info structures, and copy the
    157     // callback(s) for each one found (for use by vkDestroyInstance)
    158     layer_copy_tmp_callbacks(pCreateInfo->pNext, &my_data->num_tmp_callbacks, &my_data->tmp_dbg_create_infos,
    159                              &my_data->tmp_callbacks);
    160 
    161     // Record whether the WSI instance extension was enabled for this
    162     // VkInstance.  No need to check if the extension was advertised by
    163     // vkEnumerateInstanceExtensionProperties(), since the loader handles that.
    164     for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
    165         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME) == 0) {
    166 
    167             my_data->instanceMap[instance].surfaceExtensionEnabled = true;
    168         }
    169 #ifdef VK_USE_PLATFORM_ANDROID_KHR
    170         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) {
    171 
    172             my_data->instanceMap[instance].androidSurfaceExtensionEnabled = true;
    173         }
    174 #endif // VK_USE_PLATFORM_ANDROID_KHR
    175 #ifdef VK_USE_PLATFORM_MIR_KHR
    176         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME) == 0) {
    177 
    178             my_data->instanceMap[instance].mirSurfaceExtensionEnabled = true;
    179         }
    180 #endif // VK_USE_PLATFORM_MIR_KHR
    181 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    182         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) {
    183 
    184             my_data->instanceMap[instance].waylandSurfaceExtensionEnabled = true;
    185         }
    186 #endif // VK_USE_PLATFORM_WAYLAND_KHR
    187 #ifdef VK_USE_PLATFORM_WIN32_KHR
    188         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) {
    189 
    190             my_data->instanceMap[instance].win32SurfaceExtensionEnabled = true;
    191         }
    192 #endif // VK_USE_PLATFORM_WIN32_KHR
    193 #ifdef VK_USE_PLATFORM_XCB_KHR
    194         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) {
    195 
    196             my_data->instanceMap[instance].xcbSurfaceExtensionEnabled = true;
    197         }
    198 #endif // VK_USE_PLATFORM_XCB_KHR
    199 #ifdef VK_USE_PLATFORM_XLIB_KHR
    200         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) {
    201 
    202             my_data->instanceMap[instance].xlibSurfaceExtensionEnabled = true;
    203         }
    204 #endif // VK_USE_PLATFORM_XLIB_KHR
    205     }
    206 }
    207 
    208 #include "vk_dispatch_table_helper.h"
    209 static void init_swapchain(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
    210 
    211     layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_swapchain");
    212 }
    213 
    214 static const char *surfaceTransformStr(VkSurfaceTransformFlagBitsKHR value) {
    215     // Return a string corresponding to the value:
    216     return string_VkSurfaceTransformFlagBitsKHR(value);
    217 }
    218 
    219 static const char *surfaceCompositeAlphaStr(VkCompositeAlphaFlagBitsKHR value) {
    220     // Return a string corresponding to the value:
    221     return string_VkCompositeAlphaFlagBitsKHR(value);
    222 }
    223 
    224 static const char *presentModeStr(VkPresentModeKHR value) {
    225     // Return a string corresponding to the value:
    226     return string_VkPresentModeKHR(value);
    227 }
    228 
    229 static const char *sharingModeStr(VkSharingMode value) {
    230     // Return a string corresponding to the value:
    231     return string_VkSharingMode(value);
    232 }
    233 
    234 VKAPI_ATTR VkResult VKAPI_CALL
    235 CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
    236     VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    237 
    238     assert(chain_info->u.pLayerInfo);
    239     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
    240     PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
    241     if (fpCreateInstance == NULL) {
    242         return VK_ERROR_INITIALIZATION_FAILED;
    243     }
    244 
    245     // Advance the link info for the next element on the chain
    246     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    247 
    248     VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
    249     if (result != VK_SUCCESS) {
    250         return result;
    251     }
    252 
    253     layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
    254     my_data->instance = *pInstance;
    255     my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
    256     layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
    257 
    258     my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance,
    259                                                         pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
    260 
    261     // Call the following function after my_data is initialized:
    262     createInstanceRegisterExtensions(pCreateInfo, *pInstance);
    263     init_swapchain(my_data, pAllocator);
    264 
    265     return result;
    266 }
    267 
    268 VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
    269     dispatch_key key = get_dispatch_key(instance);
    270     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
    271     SwpInstance *pInstance = NULL;
    272     {
    273         auto it = my_data->instanceMap.find(instance);
    274         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    275     }
    276 
    277     // Call down the call chain:
    278     my_data->instance_dispatch_table->DestroyInstance(instance, pAllocator);
    279 
    280     std::lock_guard<std::mutex> lock(global_lock);
    281 
    282     // Enable the temporary callback(s) here to catch cleanup issues:
    283     bool callback_setup = false;
    284     if (my_data->num_tmp_callbacks > 0) {
    285         if (!layer_enable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_dbg_create_infos,
    286                                         my_data->tmp_callbacks)) {
    287             callback_setup = true;
    288         }
    289     }
    290 
    291     // Do additional internal cleanup:
    292     if (pInstance) {
    293         // Delete all of the SwpPhysicalDevice's, SwpSurface's, and the
    294         // SwpInstance associated with this instance:
    295         for (auto it = pInstance->physicalDevices.begin(); it != pInstance->physicalDevices.end(); it++) {
    296 
    297             // Free memory that was allocated for/by this SwpPhysicalDevice:
    298             SwpPhysicalDevice *pPhysicalDevice = it->second;
    299             if (pPhysicalDevice) {
    300                 if (pPhysicalDevice->pDevice) {
    301                     LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, instance, "VkInstance", SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN,
    302                               "%s() called before all of its associated "
    303                               "VkDevices were destroyed.",
    304                               __FUNCTION__);
    305                 }
    306                 free(pPhysicalDevice->pSurfaceFormats);
    307                 free(pPhysicalDevice->pPresentModes);
    308             }
    309 
    310             // Erase the SwpPhysicalDevice's from the my_data->physicalDeviceMap (which
    311             // are simply pointed to by the SwpInstance):
    312             my_data->physicalDeviceMap.erase(it->second->physicalDevice);
    313         }
    314         for (auto it = pInstance->surfaces.begin(); it != pInstance->surfaces.end(); it++) {
    315 
    316             // Free memory that was allocated for/by this SwpPhysicalDevice:
    317             SwpSurface *pSurface = it->second;
    318             if (pSurface) {
    319                 LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, instance, "VkInstance", SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN,
    320                           "%s() called before all of its associated "
    321                           "VkSurfaceKHRs were destroyed.",
    322                           __FUNCTION__);
    323             }
    324         }
    325         my_data->instanceMap.erase(instance);
    326     }
    327 
    328     // Disable and cleanup the temporary callback(s):
    329     if (callback_setup) {
    330         layer_disable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_callbacks);
    331     }
    332     if (my_data->num_tmp_callbacks > 0) {
    333         layer_free_tmp_callbacks(my_data->tmp_dbg_create_infos, my_data->tmp_callbacks);
    334         my_data->num_tmp_callbacks = 0;
    335     }
    336 
    337     // Clean up logging callback, if any
    338     while (my_data->logging_callback.size() > 0) {
    339         VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
    340         layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
    341         my_data->logging_callback.pop_back();
    342     }
    343     layer_debug_report_destroy_instance(my_data->report_data);
    344 
    345     delete my_data->instance_dispatch_table;
    346     layer_data_map.erase(key);
    347 }
    348 
    349 VKAPI_ATTR void VKAPI_CALL
    350 GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
    351                                        VkQueueFamilyProperties *pQueueFamilyProperties) {
    352     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    353 
    354     // Call down the call chain:
    355     my_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount,
    356                                                                              pQueueFamilyProperties);
    357 
    358     // Record the result of this query:
    359     std::lock_guard<std::mutex> lock(global_lock);
    360     SwpPhysicalDevice *pPhysicalDevice = NULL;
    361     {
    362         auto it = my_data->physicalDeviceMap.find(physicalDevice);
    363         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
    364     }
    365     if (pPhysicalDevice && pQueueFamilyPropertyCount && !pQueueFamilyProperties) {
    366         pPhysicalDevice->gotQueueFamilyPropertyCount = true;
    367         pPhysicalDevice->numOfQueueFamilies = *pQueueFamilyPropertyCount;
    368     }
    369 }
    370 
    371 #ifdef VK_USE_PLATFORM_ANDROID_KHR
    372 VKAPI_ATTR VkResult VKAPI_CALL
    373 CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo,
    374                         const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
    375     VkResult result = VK_SUCCESS;
    376     bool skipCall = false;
    377     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    378     std::unique_lock<std::mutex> lock(global_lock);
    379     SwpInstance *pInstance = NULL;
    380     {
    381         auto it = my_data->instanceMap.find(instance);
    382         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    383     }
    384 
    385     // Validate that the platform extension was enabled:
    386     if (pInstance && !pInstance->androidSurfaceExtensionEnabled) {
    387         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    388                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    389                               VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
    390     }
    391 
    392     if (!pCreateInfo) {
    393         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    394     } else {
    395         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR) {
    396             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
    397                                               "VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR");
    398         }
    399         if (pCreateInfo->pNext != NULL) {
    400             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    401         }
    402     }
    403 
    404     if (!skipCall) {
    405         // Call down the call chain:
    406         lock.unlock();
    407         result = my_data->instance_dispatch_table->CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    408         lock.lock();
    409 
    410         // Obtain this pointer again after locking:
    411         {
    412             auto it = my_data->instanceMap.find(instance);
    413             pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    414         }
    415         if ((result == VK_SUCCESS) && pInstance && pSurface) {
    416             // Record the VkSurfaceKHR returned by the ICD:
    417             my_data->surfaceMap[*pSurface].surface = *pSurface;
    418             my_data->surfaceMap[*pSurface].pInstance = pInstance;
    419             my_data->surfaceMap[*pSurface].usedAllocatorToCreate = (pAllocator != NULL);
    420             my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
    421             my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
    422             // Point to the associated SwpInstance:
    423             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
    424         }
    425         return result;
    426     }
    427     return VK_ERROR_VALIDATION_FAILED_EXT;
    428 }
    429 #endif // VK_USE_PLATFORM_ANDROID_KHR
    430 
    431 #ifdef VK_USE_PLATFORM_MIR_KHR
    432 VKAPI_ATTR VkResult VKAPI_CALL
    433 CreateMirSurfaceKHR(VkInstance instance, const VkMirSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator,
    434                     VkSurfaceKHR *pSurface) {
    435     VkResult result = VK_SUCCESS;
    436     bool skipCall = false;
    437     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    438     std::unique_lock<std::mutex> lock(global_lock);
    439     SwpInstance *pInstance = NULL;
    440     {
    441         auto it = my_data->instanceMap.find(instance);
    442         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    443     }
    444 
    445     // Validate that the platform extension was enabled:
    446     if (pInstance && !pInstance->mirSurfaceExtensionEnabled) {
    447         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    448                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    449                               VK_KHR_MIR_SURFACE_EXTENSION_NAME);
    450     }
    451 
    452     if (!pCreateInfo) {
    453         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    454     } else {
    455         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR) {
    456             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
    457                                               "VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR");
    458         }
    459         if (pCreateInfo->pNext != NULL) {
    460             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    461         }
    462     }
    463 
    464     if (!skipCall) {
    465         // Call down the call chain:
    466         lock.unlock();
    467         result = my_data->instance_dispatch_table->CreateMirSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    468         lock.lock();
    469 
    470         // Obtain this pointer again after locking:
    471         {
    472             auto it = my_data->instanceMap.find(instance);
    473             pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    474         }
    475         if ((result == VK_SUCCESS) && pInstance && pSurface) {
    476             // Record the VkSurfaceKHR returned by the ICD:
    477             my_data->surfaceMap[*pSurface].surface = *pSurface;
    478             my_data->surfaceMap[*pSurface].pInstance = pInstance;
    479             my_data->surfaceMap[*pSurface].usedAllocatorToCreate = (pAllocator != NULL);
    480             my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
    481             my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
    482             // Point to the associated SwpInstance:
    483             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
    484         }
    485         return result;
    486     }
    487     return VK_ERROR_VALIDATION_FAILED_EXT;
    488 }
    489 
    490 VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceMirPresentationSupportKHR(VkPhysicalDevice physicalDevice,
    491                                                                           uint32_t queueFamilyIndex,
    492                                                                           MirConnection *connection) {
    493     VkBool32 result = VK_FALSE;
    494     bool skipCall = false;
    495     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    496     std::unique_lock<std::mutex> lock(global_lock);
    497     SwpPhysicalDevice *pPhysicalDevice = NULL;
    498     {
    499         auto it = my_data->physicalDeviceMap.find(physicalDevice);
    500         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
    501     }
    502 
    503     // Validate that the platform extension was enabled:
    504     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->mirSurfaceExtensionEnabled) {
    505         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
    506                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    507                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    508                               VK_KHR_MIR_SURFACE_EXTENSION_NAME);
    509     }
    510     if (pPhysicalDevice->gotQueueFamilyPropertyCount && (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
    511         skipCall |=
    512             LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
    513                                                    "VkPhysicalDevice", queueFamilyIndex, pPhysicalDevice->numOfQueueFamilies);
    514     }
    515     lock.unlock();
    516 
    517     if (!skipCall) {
    518         // Call down the call chain:
    519         result = my_data->instance_dispatch_table->GetPhysicalDeviceMirPresentationSupportKHR(physicalDevice, queueFamilyIndex,
    520                                                                                               connection);
    521     }
    522     return result;
    523 }
    524 #endif // VK_USE_PLATFORM_MIR_KHR
    525 
    526 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    527 VKAPI_ATTR VkResult VKAPI_CALL
    528 CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
    529                         const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
    530     VkResult result = VK_SUCCESS;
    531     bool skipCall = false;
    532     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    533     std::unique_lock<std::mutex> lock(global_lock);
    534     SwpInstance *pInstance = NULL;
    535     {
    536         auto it = my_data->instanceMap.find(instance);
    537         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    538     }
    539 
    540     // Validate that the platform extension was enabled:
    541     if (pInstance && !pInstance->waylandSurfaceExtensionEnabled) {
    542         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    543                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    544                               VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
    545     }
    546 
    547     if (!pCreateInfo) {
    548         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    549     } else {
    550         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR) {
    551             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
    552                                               "VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR");
    553         }
    554         if (pCreateInfo->pNext != NULL) {
    555             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    556         }
    557     }
    558 
    559     if (!skipCall) {
    560         // Call down the call chain:
    561         lock.unlock();
    562         result = my_data->instance_dispatch_table->CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    563         lock.lock();
    564 
    565         // Obtain this pointer again after locking:
    566         {
    567             auto it = my_data->instanceMap.find(instance);
    568             pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    569         }
    570         if ((result == VK_SUCCESS) && pInstance && pSurface) {
    571             // Record the VkSurfaceKHR returned by the ICD:
    572             my_data->surfaceMap[*pSurface].surface = *pSurface;
    573             my_data->surfaceMap[*pSurface].pInstance = pInstance;
    574             my_data->surfaceMap[*pSurface].usedAllocatorToCreate = (pAllocator != NULL);
    575             my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
    576             my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
    577             // Point to the associated SwpInstance:
    578             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
    579         }
    580         return result;
    581     }
    582     return VK_ERROR_VALIDATION_FAILED_EXT;
    583 }
    584 
    585 VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
    586                                                                               uint32_t queueFamilyIndex,
    587                                                                               struct wl_display *display) {
    588     VkBool32 result = VK_FALSE;
    589     bool skipCall = false;
    590     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    591     std::unique_lock<std::mutex> lock(global_lock);
    592     SwpPhysicalDevice *pPhysicalDevice = NULL;
    593     {
    594         auto it = my_data->physicalDeviceMap.find(physicalDevice);
    595         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
    596     }
    597 
    598     // Validate that the platform extension was enabled:
    599     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->waylandSurfaceExtensionEnabled) {
    600         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
    601                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    602                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    603                               VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
    604     }
    605     if (pPhysicalDevice->gotQueueFamilyPropertyCount && (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
    606         skipCall |=
    607             LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
    608                                                    "VkPhysicalDevice", queueFamilyIndex, pPhysicalDevice->numOfQueueFamilies);
    609     }
    610     lock.unlock();
    611 
    612     if (!skipCall) {
    613         // Call down the call chain:
    614         result = my_data->instance_dispatch_table->GetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex,
    615                                                                                                   display);
    616     }
    617     return result;
    618 }
    619 #endif // VK_USE_PLATFORM_WAYLAND_KHR
    620 
    621 #ifdef VK_USE_PLATFORM_WIN32_KHR
    622 VKAPI_ATTR VkResult VKAPI_CALL
    623 CreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
    624                       const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) {
    625     VkResult result = VK_SUCCESS;
    626     bool skipCall = false;
    627     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    628     std::unique_lock<std::mutex> lock(global_lock);
    629     SwpInstance *pInstance = NULL;
    630     {
    631         auto it = my_data->instanceMap.find(instance);
    632         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    633     }
    634 
    635     // Validate that the platform extension was enabled:
    636     if (pInstance && !pInstance->win32SurfaceExtensionEnabled) {
    637         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    638                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    639                               VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    640     }
    641 
    642     if (!pCreateInfo) {
    643         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    644     } else {
    645         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR) {
    646             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
    647                                               "VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR");
    648         }
    649         if (pCreateInfo->pNext != NULL) {
    650             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    651         }
    652     }
    653 
    654     if (!skipCall) {
    655         // Call down the call chain:
    656         lock.unlock();
    657         result = my_data->instance_dispatch_table->CreateWin32SurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    658         lock.lock();
    659 
    660         // Obtain this pointer again after locking:
    661         {
    662             auto it = my_data->instanceMap.find(instance);
    663             pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    664         }
    665         if ((result == VK_SUCCESS) && pInstance && pSurface) {
    666             // Record the VkSurfaceKHR returned by the ICD:
    667             my_data->surfaceMap[*pSurface].surface = *pSurface;
    668             my_data->surfaceMap[*pSurface].pInstance = pInstance;
    669             my_data->surfaceMap[*pSurface].usedAllocatorToCreate = (pAllocator != NULL);
    670             my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
    671             my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
    672             // Point to the associated SwpInstance:
    673             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
    674         }
    675         return result;
    676     }
    677     return VK_ERROR_VALIDATION_FAILED_EXT;
    678 }
    679 
    680 VKAPI_ATTR VkBool32 VKAPI_CALL
    681 GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex) {
    682     VkBool32 result = VK_FALSE;
    683     bool skipCall = false;
    684     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    685     std::unique_lock<std::mutex> lock(global_lock);
    686     SwpPhysicalDevice *pPhysicalDevice = NULL;
    687     {
    688         auto it = my_data->physicalDeviceMap.find(physicalDevice);
    689         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
    690     }
    691 
    692     // Validate that the platform extension was enabled:
    693     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->win32SurfaceExtensionEnabled) {
    694         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
    695                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    696                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    697                               VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
    698     }
    699     if (pPhysicalDevice->gotQueueFamilyPropertyCount && (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
    700         skipCall |=
    701             LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
    702                                                    "VkPhysicalDevice", queueFamilyIndex, pPhysicalDevice->numOfQueueFamilies);
    703     }
    704     lock.unlock();
    705 
    706     if (!skipCall) {
    707         // Call down the call chain:
    708         result = my_data->instance_dispatch_table->GetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
    709     }
    710     return result;
    711 }
    712 #endif // VK_USE_PLATFORM_WIN32_KHR
    713 
    714 #ifdef VK_USE_PLATFORM_XCB_KHR
    715 VKAPI_ATTR VkResult VKAPI_CALL
    716 CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator,
    717                       VkSurfaceKHR *pSurface) {
    718     VkResult result = VK_SUCCESS;
    719     bool skipCall = false;
    720     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    721     std::unique_lock<std::mutex> lock(global_lock);
    722     SwpInstance *pInstance = NULL;
    723     {
    724         auto it = my_data->instanceMap.find(instance);
    725         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    726     }
    727 
    728     // Validate that the platform extension was enabled:
    729     if (pInstance && !pInstance->xcbSurfaceExtensionEnabled) {
    730         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    731                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    732                               VK_KHR_XCB_SURFACE_EXTENSION_NAME);
    733     }
    734 
    735     if (!pCreateInfo) {
    736         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    737     } else {
    738         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR) {
    739             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
    740                                               "VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR");
    741         }
    742         if (pCreateInfo->pNext != NULL) {
    743             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    744         }
    745     }
    746 
    747     if (!skipCall) {
    748         // Call down the call chain:
    749         lock.unlock();
    750         result = my_data->instance_dispatch_table->CreateXcbSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    751         lock.lock();
    752 
    753         // Obtain this pointer again after locking:
    754         {
    755             auto it = my_data->instanceMap.find(instance);
    756             pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    757         }
    758         if ((result == VK_SUCCESS) && pInstance && pSurface) {
    759             // Record the VkSurfaceKHR returned by the ICD:
    760             my_data->surfaceMap[*pSurface].surface = *pSurface;
    761             my_data->surfaceMap[*pSurface].pInstance = pInstance;
    762             my_data->surfaceMap[*pSurface].usedAllocatorToCreate = (pAllocator != NULL);
    763             my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
    764             my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
    765             // Point to the associated SwpInstance:
    766             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
    767         }
    768         return result;
    769     }
    770     return VK_ERROR_VALIDATION_FAILED_EXT;
    771 }
    772 
    773 VKAPI_ATTR VkBool32 VKAPI_CALL
    774 GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
    775                                            xcb_connection_t *connection, xcb_visualid_t visual_id) {
    776     VkBool32 result = VK_FALSE;
    777     bool skipCall = false;
    778     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    779     std::unique_lock<std::mutex> lock(global_lock);
    780     SwpPhysicalDevice *pPhysicalDevice = NULL;
    781     {
    782         auto it = my_data->physicalDeviceMap.find(physicalDevice);
    783         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
    784     }
    785 
    786     // Validate that the platform extension was enabled:
    787     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->xcbSurfaceExtensionEnabled) {
    788         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
    789                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    790                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    791                               VK_KHR_XCB_SURFACE_EXTENSION_NAME);
    792     }
    793     if (pPhysicalDevice->gotQueueFamilyPropertyCount && (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
    794         skipCall |=
    795             LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
    796                                                    "VkPhysicalDevice", queueFamilyIndex, pPhysicalDevice->numOfQueueFamilies);
    797     }
    798     lock.unlock();
    799 
    800     if (!skipCall) {
    801         // Call down the call chain:
    802         result = my_data->instance_dispatch_table->GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex,
    803                                                                                               connection, visual_id);
    804     }
    805     return result;
    806 }
    807 #endif // VK_USE_PLATFORM_XCB_KHR
    808 
    809 #ifdef VK_USE_PLATFORM_XLIB_KHR
    810 VKAPI_ATTR VkResult VKAPI_CALL
    811 CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator,
    812                      VkSurfaceKHR *pSurface) {
    813     VkResult result = VK_SUCCESS;
    814     bool skipCall = false;
    815     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    816     std::unique_lock<std::mutex> lock(global_lock);
    817     SwpInstance *pInstance = NULL;
    818     {
    819         auto it = my_data->instanceMap.find(instance);
    820         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    821     }
    822 
    823     // Validate that the platform extension was enabled:
    824     if (pInstance && !pInstance->xlibSurfaceExtensionEnabled) {
    825         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    826                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    827                               VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
    828     }
    829 
    830     if (!pCreateInfo) {
    831         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    832     } else {
    833         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR) {
    834             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
    835                                               "VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR");
    836         }
    837         if (pCreateInfo->pNext != NULL) {
    838             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
    839         }
    840     }
    841 
    842     if (!skipCall) {
    843         // Call down the call chain:
    844         lock.unlock();
    845         result = my_data->instance_dispatch_table->CreateXlibSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
    846         lock.lock();
    847 
    848         // Obtain this pointer again after locking:
    849         {
    850             auto it = my_data->instanceMap.find(instance);
    851             pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    852         }
    853         if ((result == VK_SUCCESS) && pInstance && pSurface) {
    854             // Record the VkSurfaceKHR returned by the ICD:
    855             my_data->surfaceMap[*pSurface].surface = *pSurface;
    856             my_data->surfaceMap[*pSurface].pInstance = pInstance;
    857             my_data->surfaceMap[*pSurface].usedAllocatorToCreate = (pAllocator != NULL);
    858             my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
    859             my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
    860             // Point to the associated SwpInstance:
    861             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
    862         }
    863         return result;
    864     }
    865     return VK_ERROR_VALIDATION_FAILED_EXT;
    866 }
    867 
    868 VKAPI_ATTR VkBool32 VKAPI_CALL GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
    869                                                                            uint32_t queueFamilyIndex,
    870                                                                            Display *dpy, VisualID visualID) {
    871     VkBool32 result = VK_FALSE;
    872     bool skipCall = false;
    873     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
    874     std::unique_lock<std::mutex> lock(global_lock);
    875     SwpPhysicalDevice *pPhysicalDevice = NULL;
    876     {
    877         auto it = my_data->physicalDeviceMap.find(physicalDevice);
    878         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
    879     }
    880 
    881     // Validate that the platform extension was enabled:
    882     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->xlibSurfaceExtensionEnabled) {
    883         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
    884                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    885                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    886                               VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
    887     }
    888     if (pPhysicalDevice->gotQueueFamilyPropertyCount && (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
    889         skipCall |=
    890             LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
    891                                                    "VkPhysicalDevice", queueFamilyIndex, pPhysicalDevice->numOfQueueFamilies);
    892     }
    893     lock.unlock();
    894 
    895     if (!skipCall) {
    896         // Call down the call chain:
    897         result = my_data->instance_dispatch_table->GetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex,
    898                                                                                                dpy, visualID);
    899     }
    900     return result;
    901 }
    902 #endif // VK_USE_PLATFORM_XLIB_KHR
    903 
    904 VKAPI_ATTR void VKAPI_CALL
    905 DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
    906     bool skipCall = false;
    907     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    908     std::unique_lock<std::mutex> lock(global_lock);
    909     SwpSurface *pSurface = NULL;
    910     {
    911         auto it = my_data->surfaceMap.find(surface);
    912         pSurface = (it == my_data->surfaceMap.end()) ? NULL : &it->second;
    913     }
    914     SwpInstance *pInstance = NULL;
    915     {
    916         auto it = my_data->instanceMap.find(instance);
    917         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    918     }
    919 
    920     // Validate that the platform extension was enabled:
    921     if (pInstance && !pInstance->surfaceExtensionEnabled) {
    922         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pInstance, "VkInstance", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
    923                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
    924                               VK_KHR_SURFACE_EXTENSION_NAME);
    925     }
    926 
    927     // Regardless of skipCall value, do some internal cleanup:
    928     if (pSurface) {
    929         // Delete the SwpSurface associated with this surface:
    930         if (pSurface->pInstance) {
    931             pSurface->pInstance->surfaces.erase(surface);
    932         }
    933         if (!pSurface->swapchains.empty()) {
    934             LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, instance, "VkInstance", SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN,
    935                       "%s() called before all of its associated "
    936                       "VkSwapchainKHRs were destroyed.",
    937                       __FUNCTION__);
    938             // Empty and then delete all SwpSwapchain's
    939             for (auto it = pSurface->swapchains.begin(); it != pSurface->swapchains.end(); it++) {
    940                 // Delete all SwpImage's
    941                 it->second->images.clear();
    942                 // In case the swapchain's device hasn't been destroyed yet
    943                 // (which isn't likely, but is possible), delete its
    944                 // association with this swapchain (i.e. so we can't point to
    945                 // this swpchain from that device, later on):
    946                 if (it->second->pDevice) {
    947                     it->second->pDevice->swapchains.clear();
    948                 }
    949             }
    950             pSurface->swapchains.clear();
    951         }
    952         if ((pAllocator != NULL) != pSurface->usedAllocatorToCreate) {
    953             LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, instance, "VkInstance", SWAPCHAIN_INCOMPATIBLE_ALLOCATOR,
    954                       "%s() called with incompatible pAllocator from when "
    955                       "the object was created.",
    956                       __FUNCTION__);
    957         }
    958         my_data->surfaceMap.erase(surface);
    959     }
    960     lock.unlock();
    961 
    962     if (!skipCall) {
    963         // Call down the call chain:
    964         my_data->instance_dispatch_table->DestroySurfaceKHR(instance, surface, pAllocator);
    965     }
    966 }
    967 
    968 VKAPI_ATTR VkResult VKAPI_CALL
    969 EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) {
    970     VkResult result = VK_SUCCESS;
    971     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
    972 
    973     // Call down the call chain:
    974     result = my_data->instance_dispatch_table->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
    975 
    976     std::lock_guard<std::mutex> lock(global_lock);
    977     SwpInstance *pInstance = NULL;
    978     {
    979         auto it = my_data->instanceMap.find(instance);
    980         pInstance = (it == my_data->instanceMap.end()) ? NULL : &it->second;
    981     }
    982     if ((result == VK_SUCCESS) && pInstance && pPhysicalDevices && (*pPhysicalDeviceCount > 0)) {
    983         // Record the VkPhysicalDevices returned by the ICD:
    984         for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
    985             my_data->physicalDeviceMap[pPhysicalDevices[i]].physicalDevice = pPhysicalDevices[i];
    986             my_data->physicalDeviceMap[pPhysicalDevices[i]].pInstance = pInstance;
    987             my_data->physicalDeviceMap[pPhysicalDevices[i]].pDevice = NULL;
    988             my_data->physicalDeviceMap[pPhysicalDevices[i]].gotQueueFamilyPropertyCount = false;
    989             my_data->physicalDeviceMap[pPhysicalDevices[i]].gotSurfaceCapabilities = false;
    990             my_data->physicalDeviceMap[pPhysicalDevices[i]].surfaceFormatCount = 0;
    991             my_data->physicalDeviceMap[pPhysicalDevices[i]].pSurfaceFormats = NULL;
    992             my_data->physicalDeviceMap[pPhysicalDevices[i]].presentModeCount = 0;
    993             my_data->physicalDeviceMap[pPhysicalDevices[i]].pPresentModes = NULL;
    994             // Point to the associated SwpInstance:
    995             if (pInstance) {
    996                 pInstance->physicalDevices[pPhysicalDevices[i]] = &my_data->physicalDeviceMap[pPhysicalDevices[i]];
    997             }
    998         }
    999     }
   1000     return result;
   1001 }
   1002 
   1003 VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physicalDevice,
   1004                                             const VkDeviceCreateInfo *pCreateInfo,
   1005                                             const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
   1006     layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   1007     VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
   1008 
   1009     assert(chain_info->u.pLayerInfo);
   1010     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
   1011     PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
   1012     PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice");
   1013     if (fpCreateDevice == NULL) {
   1014         return VK_ERROR_INITIALIZATION_FAILED;
   1015     }
   1016 
   1017     // Advance the link info for the next element on the chain
   1018     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
   1019 
   1020     VkResult result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
   1021     if (result != VK_SUCCESS) {
   1022         return result;
   1023     }
   1024 
   1025     std::lock_guard<std::mutex> lock(global_lock);
   1026     layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
   1027 
   1028     // Setup device dispatch table
   1029     my_device_data->device_dispatch_table = new VkLayerDispatchTable;
   1030     layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
   1031 
   1032     my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
   1033     createDeviceRegisterExtensions(physicalDevice, pCreateInfo, *pDevice);
   1034 
   1035     return result;
   1036 }
   1037 
   1038 VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
   1039     dispatch_key key = get_dispatch_key(device);
   1040     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
   1041 
   1042     // Call down the call chain:
   1043     my_data->device_dispatch_table->DestroyDevice(device, pAllocator);
   1044 
   1045     // Do some internal cleanup:
   1046     std::lock_guard<std::mutex> lock(global_lock);
   1047     SwpDevice *pDevice = NULL;
   1048     {
   1049         auto it = my_data->deviceMap.find(device);
   1050         pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   1051     }
   1052     if (pDevice) {
   1053         // Delete the SwpDevice associated with this device:
   1054         if (pDevice->pPhysicalDevice) {
   1055             pDevice->pPhysicalDevice->pDevice = NULL;
   1056         }
   1057         if (!pDevice->swapchains.empty()) {
   1058             LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN,
   1059                       "%s() called before all of its associated "
   1060                       "VkSwapchainKHRs were destroyed.",
   1061                       __FUNCTION__);
   1062             // Empty and then delete all SwpSwapchain's
   1063             for (auto it = pDevice->swapchains.begin(); it != pDevice->swapchains.end(); it++) {
   1064                 // Delete all SwpImage's
   1065                 it->second->images.clear();
   1066                 // In case the swapchain's surface hasn't been destroyed yet
   1067                 // (which is likely) delete its association with this swapchain
   1068                 // (i.e. so we can't point to this swpchain from that surface,
   1069                 // later on):
   1070                 if (it->second->pSurface) {
   1071                     it->second->pSurface->swapchains.clear();
   1072                 }
   1073             }
   1074             pDevice->swapchains.clear();
   1075         }
   1076         my_data->deviceMap.erase(device);
   1077     }
   1078     delete my_data->device_dispatch_table;
   1079     layer_data_map.erase(key);
   1080 }
   1081 
   1082 VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice,
   1083                                                                   uint32_t queueFamilyIndex, VkSurfaceKHR surface,
   1084                                                                   VkBool32 *pSupported) {
   1085     VkResult result = VK_SUCCESS;
   1086     bool skipCall = false;
   1087     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   1088     std::unique_lock<std::mutex> lock(global_lock);
   1089     SwpPhysicalDevice *pPhysicalDevice = NULL;
   1090     {
   1091         auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1092         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1093     }
   1094 
   1095     // Validate that the surface extension was enabled:
   1096     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->surfaceExtensionEnabled) {
   1097         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
   1098                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1099                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
   1100                               VK_KHR_SURFACE_EXTENSION_NAME);
   1101     }
   1102     if (!pPhysicalDevice->gotQueueFamilyPropertyCount) {
   1103         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice, "VkPhysicalDevice",
   1104                               SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES, "%s() called before calling the "
   1105                                                                       "vkGetPhysicalDeviceQueueFamilyProperties "
   1106                                                                       "function.",
   1107                               __FUNCTION__);
   1108     } else if (pPhysicalDevice->gotQueueFamilyPropertyCount && (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
   1109         skipCall |=
   1110             LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
   1111                                                    "VkPhysicalDevice", queueFamilyIndex, pPhysicalDevice->numOfQueueFamilies);
   1112     }
   1113     if (!pSupported) {
   1114         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, physicalDevice, "pSupported");
   1115     }
   1116 
   1117     if (!skipCall) {
   1118         // Call down the call chain:
   1119         lock.unlock();
   1120         result = my_data->instance_dispatch_table->GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface,
   1121                                                                                       pSupported);
   1122         lock.lock();
   1123 
   1124         // Obtain this pointer again after locking:
   1125         {
   1126             auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1127             pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1128         }
   1129         if ((result == VK_SUCCESS) && pSupported && pPhysicalDevice) {
   1130             // Record the result of this query:
   1131             SwpInstance *pInstance = pPhysicalDevice->pInstance;
   1132             SwpSurface *pSurface = (pInstance) ? pInstance->surfaces[surface] : NULL;
   1133             if (pSurface) {
   1134                 pPhysicalDevice->supportedSurfaces[surface] = pSurface;
   1135                 if (!pSurface->numQueueFamilyIndexSupport) {
   1136                     if (pPhysicalDevice->gotQueueFamilyPropertyCount) {
   1137                         pSurface->pQueueFamilyIndexSupport =
   1138                             (VkBool32 *)malloc(pPhysicalDevice->numOfQueueFamilies * sizeof(VkBool32));
   1139                         if (pSurface->pQueueFamilyIndexSupport != NULL) {
   1140                             pSurface->numQueueFamilyIndexSupport = pPhysicalDevice->numOfQueueFamilies;
   1141                         }
   1142                     }
   1143                 }
   1144                 if (pSurface->numQueueFamilyIndexSupport) {
   1145                     pSurface->pQueueFamilyIndexSupport[queueFamilyIndex] = *pSupported;
   1146                 }
   1147             }
   1148         }
   1149         return result;
   1150     }
   1151     return VK_ERROR_VALIDATION_FAILED_EXT;
   1152 }
   1153 
   1154 VKAPI_ATTR VkResult VKAPI_CALL
   1155 GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
   1156                                         VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
   1157     VkResult result = VK_SUCCESS;
   1158     bool skipCall = false;
   1159     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   1160     std::unique_lock<std::mutex> lock(global_lock);
   1161     SwpPhysicalDevice *pPhysicalDevice = NULL;
   1162     {
   1163         auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1164         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1165     }
   1166 
   1167     // Validate that the surface extension was enabled:
   1168     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->surfaceExtensionEnabled) {
   1169         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
   1170                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1171                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
   1172                               VK_KHR_SURFACE_EXTENSION_NAME);
   1173     }
   1174     if (!pSurfaceCapabilities) {
   1175         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, physicalDevice, "pSurfaceCapabilities");
   1176     }
   1177 
   1178     if (!skipCall) {
   1179         // Call down the call chain:
   1180         lock.unlock();
   1181         result = my_data->instance_dispatch_table->GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface,
   1182                                                                                            pSurfaceCapabilities);
   1183         lock.lock();
   1184 
   1185         // Obtain this pointer again after locking:
   1186         {
   1187             auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1188             pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1189         }
   1190         if ((result == VK_SUCCESS) && pPhysicalDevice) {
   1191             // Record the result of this query:
   1192             pPhysicalDevice->gotSurfaceCapabilities = true;
   1193             // FIXME: NEED TO COPY THIS DATA, BECAUSE pSurfaceCapabilities POINTS TO APP-ALLOCATED DATA
   1194             pPhysicalDevice->surfaceCapabilities = *pSurfaceCapabilities;
   1195         }
   1196         return result;
   1197     }
   1198     return VK_ERROR_VALIDATION_FAILED_EXT;
   1199 }
   1200 
   1201 VKAPI_ATTR VkResult VKAPI_CALL
   1202 GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount,
   1203                                    VkSurfaceFormatKHR *pSurfaceFormats) {
   1204     VkResult result = VK_SUCCESS;
   1205     bool skipCall = false;
   1206     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   1207     std::unique_lock<std::mutex> lock(global_lock);
   1208     SwpPhysicalDevice *pPhysicalDevice = NULL;
   1209     {
   1210         auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1211         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1212     }
   1213 
   1214     // Validate that the surface extension was enabled:
   1215     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->surfaceExtensionEnabled) {
   1216         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
   1217                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1218                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
   1219                               VK_KHR_SURFACE_EXTENSION_NAME);
   1220     }
   1221     if (!pSurfaceFormatCount) {
   1222         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, physicalDevice, "pSurfaceFormatCount");
   1223     } else if (pPhysicalDevice && pSurfaceFormats) {
   1224         // Compare the preliminary value of *pSurfaceFormatCount with the
   1225         // value this time:
   1226         if (pPhysicalDevice->surfaceFormatCount == 0) {
   1227             // Since we haven't recorded a preliminary value of
   1228             // *pSurfaceFormatCount, that likely means that the application
   1229             // didn't previously call this function with a NULL value of
   1230             // pSurfaceFormats:
   1231             skipCall |= LOG_ERROR_ZERO_PRIOR_COUNT(
   1232                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
   1233                 physicalDevice, "pSurfaceFormatCount", "pSurfaceFormats");
   1234         } else if (*pSurfaceFormatCount > pPhysicalDevice->surfaceFormatCount) {
   1235             skipCall |= LOG_ERROR_INVALID_COUNT(
   1236                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
   1237                 physicalDevice, "pSurfaceFormatCount", "pSurfaceFormats",
   1238                 *pSurfaceFormatCount, pPhysicalDevice->surfaceFormatCount);
   1239         }
   1240     }
   1241 
   1242     if (!skipCall) {
   1243         // Call down the call chain:
   1244         lock.unlock();
   1245         result = my_data->instance_dispatch_table->GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount,
   1246                                                                                       pSurfaceFormats);
   1247         lock.lock();
   1248 
   1249         // Obtain this pointer again after locking:
   1250         {
   1251             auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1252             pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1253         }
   1254         if ((result == VK_SUCCESS) && pPhysicalDevice && !pSurfaceFormats && pSurfaceFormatCount) {
   1255             // Record the result of this preliminary query:
   1256             pPhysicalDevice->surfaceFormatCount = *pSurfaceFormatCount;
   1257         } else if ((result == VK_SUCCESS) && pPhysicalDevice &&
   1258                    pSurfaceFormats && pSurfaceFormatCount &&
   1259                    (*pSurfaceFormatCount > 0)) {
   1260             // Record the result of this query:
   1261             pPhysicalDevice->surfaceFormatCount = *pSurfaceFormatCount;
   1262             pPhysicalDevice->pSurfaceFormats = (VkSurfaceFormatKHR *)malloc(*pSurfaceFormatCount * sizeof(VkSurfaceFormatKHR));
   1263             if (pPhysicalDevice->pSurfaceFormats) {
   1264                 for (uint32_t i = 0; i < *pSurfaceFormatCount; i++) {
   1265                     pPhysicalDevice->pSurfaceFormats[i] = pSurfaceFormats[i];
   1266                 }
   1267             } else {
   1268                 pPhysicalDevice->surfaceFormatCount = 0;
   1269             }
   1270         }
   1271         return result;
   1272     }
   1273     return VK_ERROR_VALIDATION_FAILED_EXT;
   1274 }
   1275 
   1276 VKAPI_ATTR VkResult VKAPI_CALL
   1277 GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount,
   1278                                         VkPresentModeKHR *pPresentModes) {
   1279     VkResult result = VK_SUCCESS;
   1280     bool skipCall = false;
   1281     layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
   1282     std::unique_lock<std::mutex> lock(global_lock);
   1283     SwpPhysicalDevice *pPhysicalDevice = NULL;
   1284     {
   1285         auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1286         pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1287     }
   1288 
   1289     // Validate that the surface extension was enabled:
   1290     if (pPhysicalDevice && pPhysicalDevice->pInstance && !pPhysicalDevice->pInstance->surfaceExtensionEnabled) {
   1291         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, pPhysicalDevice->pInstance, "VkInstance",
   1292                               SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1293                               "%s() called even though the %s extension was not enabled for this VkInstance.", __FUNCTION__,
   1294                               VK_KHR_SURFACE_EXTENSION_NAME);
   1295     }
   1296     if (!pPresentModeCount) {
   1297         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, physicalDevice, "pPresentModeCount");
   1298     } else if (pPhysicalDevice && pPresentModes) {
   1299         // Compare the preliminary value of *pPresentModeCount with the
   1300         // value this time:
   1301         if (pPhysicalDevice->presentModeCount == 0) {
   1302             // Since we haven't recorded a preliminary value of
   1303             // *pPresentModeCount, that likely means that the application
   1304             // didn't previously call this function with a NULL value of
   1305             // pPresentModes:
   1306             skipCall |= LOG_ERROR_ZERO_PRIOR_COUNT(
   1307                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
   1308                 physicalDevice, "pPresentModeCount", "pPresentModes");
   1309         } else if (*pPresentModeCount > pPhysicalDevice->presentModeCount) {
   1310             skipCall |= LOG_ERROR_INVALID_COUNT(
   1311                 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
   1312                 physicalDevice, "pPresentModeCount", "pPresentModes",
   1313                 *pPresentModeCount, pPhysicalDevice->presentModeCount);
   1314         }
   1315     }
   1316 
   1317     if (!skipCall) {
   1318         // Call down the call chain:
   1319         lock.unlock();
   1320         result = my_data->instance_dispatch_table->GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface,
   1321                                                                                            pPresentModeCount, pPresentModes);
   1322         lock.lock();
   1323 
   1324         // Obtain this pointer again after locking:
   1325         {
   1326             auto it = my_data->physicalDeviceMap.find(physicalDevice);
   1327             pPhysicalDevice = (it == my_data->physicalDeviceMap.end()) ? NULL : &it->second;
   1328         }
   1329         if ((result == VK_SUCCESS) && pPhysicalDevice && !pPresentModes && pPresentModeCount) {
   1330             // Record the result of this preliminary query:
   1331             pPhysicalDevice->presentModeCount = *pPresentModeCount;
   1332         } else if ((result == VK_SUCCESS) && pPhysicalDevice &&
   1333                    pPresentModes && pPresentModeCount &&
   1334                    (*pPresentModeCount > 0)) {
   1335             // Record the result of this query:
   1336             pPhysicalDevice->presentModeCount = *pPresentModeCount;
   1337             pPhysicalDevice->pPresentModes = (VkPresentModeKHR *)malloc(*pPresentModeCount * sizeof(VkPresentModeKHR));
   1338             if (pPhysicalDevice->pPresentModes) {
   1339                 for (uint32_t i = 0; i < *pPresentModeCount; i++) {
   1340                     pPhysicalDevice->pPresentModes[i] = pPresentModes[i];
   1341                 }
   1342             } else {
   1343                 pPhysicalDevice->presentModeCount = 0;
   1344             }
   1345         }
   1346         return result;
   1347     }
   1348     return VK_ERROR_VALIDATION_FAILED_EXT;
   1349 }
   1350 
   1351 // This function does the up-front validation work for vkCreateSwapchainKHR(),
   1352 // and returns true if a logging callback indicates that the call down the
   1353 // chain should be skipped:
   1354 static bool validateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, VkSwapchainKHR *pSwapchain) {
   1355     // TODO: Validate cases of re-creating a swapchain (the current code
   1356     // assumes a new swapchain is being created).
   1357     bool skipCall = false;
   1358     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1359     char fn[] = "vkCreateSwapchainKHR";
   1360     SwpDevice *pDevice = NULL;
   1361     {
   1362         auto it = my_data->deviceMap.find(device);
   1363         pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   1364     }
   1365 
   1366     // Validate that the swapchain extension was enabled:
   1367     if (pDevice && !pDevice->swapchainExtensionEnabled) {
   1368         return LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1369                          "%s() called even though the %s extension was not enabled for this VkDevice.", fn,
   1370                          VK_KHR_SWAPCHAIN_EXTENSION_NAME);
   1371     }
   1372     if (!pCreateInfo) {
   1373         return LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
   1374     } else {
   1375         if (pCreateInfo->sType != VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR) {
   1376             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo",
   1377                                               "VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR");
   1378         }
   1379         if (pCreateInfo->pNext != NULL) {
   1380             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pCreateInfo");
   1381         }
   1382     }
   1383     if (!pSwapchain) {
   1384         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pSwapchain");
   1385     }
   1386 
   1387     // Keep around a useful pointer to pPhysicalDevice:
   1388     SwpPhysicalDevice *pPhysicalDevice = pDevice->pPhysicalDevice;
   1389 
   1390     // Validate pCreateInfo values with result of
   1391     // vkGetPhysicalDeviceQueueFamilyProperties
   1392     if (pPhysicalDevice && pPhysicalDevice->gotQueueFamilyPropertyCount) {
   1393         for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; i++) {
   1394             if (pCreateInfo->pQueueFamilyIndices[i] >= pPhysicalDevice->numOfQueueFamilies) {
   1395                 skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, pPhysicalDevice,
   1396                                                                    "VkPhysicalDevice", pCreateInfo->pQueueFamilyIndices[i],
   1397                                                                    pPhysicalDevice->numOfQueueFamilies);
   1398             }
   1399         }
   1400     }
   1401 
   1402     // Validate pCreateInfo values with the results of
   1403     // vkGetPhysicalDeviceSurfaceCapabilitiesKHR():
   1404     if (!pPhysicalDevice || !pPhysicalDevice->gotSurfaceCapabilities) {
   1405         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
   1406                               "%s() called before calling "
   1407                               "vkGetPhysicalDeviceSurfaceCapabilitiesKHR().",
   1408                               fn);
   1409     } else if (pCreateInfo) {
   1410         // Validate pCreateInfo->surface to make sure that
   1411         // vkGetPhysicalDeviceSurfaceSupportKHR() reported this as a supported
   1412         // surface:
   1413         SwpSurface *pSurface = ((pPhysicalDevice) ? pPhysicalDevice->supportedSurfaces[pCreateInfo->surface] : NULL);
   1414         if (!pSurface) {
   1415             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_CREATE_UNSUPPORTED_SURFACE,
   1416                                   "%s() called with pCreateInfo->surface that "
   1417                                   "was not returned by "
   1418                                   "vkGetPhysicalDeviceSurfaceSupportKHR() "
   1419                                   "for the device.",
   1420                                   fn);
   1421         }
   1422 
   1423         // Validate pCreateInfo->minImageCount against
   1424         // VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
   1425         VkSurfaceCapabilitiesKHR *pCapabilities = &pPhysicalDevice->surfaceCapabilities;
   1426         if ((pCreateInfo->minImageCount < pCapabilities->minImageCount) ||
   1427             ((pCapabilities->maxImageCount > 0) && (pCreateInfo->minImageCount > pCapabilities->maxImageCount))) {
   1428             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1429                                   SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT, "%s() called with pCreateInfo->minImageCount "
   1430                                                                            "= %d, which is outside the bounds returned "
   1431                                                                            "by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. "
   1432                                                                            "minImageCount = %d, maxImageCount = %d).",
   1433                                   fn, pCreateInfo->minImageCount, pCapabilities->minImageCount, pCapabilities->maxImageCount);
   1434         }
   1435         // Validate pCreateInfo->imageExtent against
   1436         // VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
   1437         if ((pCapabilities->currentExtent.width == -1) &&
   1438             ((pCreateInfo->imageExtent.width < pCapabilities->minImageExtent.width) ||
   1439              (pCreateInfo->imageExtent.width > pCapabilities->maxImageExtent.width) ||
   1440              (pCreateInfo->imageExtent.height < pCapabilities->minImageExtent.height) ||
   1441              (pCreateInfo->imageExtent.height > pCapabilities->maxImageExtent.height))) {
   1442             skipCall |= LOG_ERROR(
   1443                 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS,
   1444                 "%s() called with pCreateInfo->imageExtent = "
   1445                 "(%d,%d), which is outside the bounds "
   1446                 "returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): "
   1447                 "currentExtent = (%d,%d), minImageExtent = "
   1448                 "(%d,%d), maxImageExtent = (%d,%d).",
   1449                 fn, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height, pCapabilities->currentExtent.width,
   1450                 pCapabilities->currentExtent.height, pCapabilities->minImageExtent.width, pCapabilities->minImageExtent.height,
   1451                 pCapabilities->maxImageExtent.width, pCapabilities->maxImageExtent.height);
   1452         }
   1453         if ((pCapabilities->currentExtent.width != -1) &&
   1454             ((pCreateInfo->imageExtent.width != pCapabilities->currentExtent.width) ||
   1455              (pCreateInfo->imageExtent.height != pCapabilities->currentExtent.height))) {
   1456             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1457                                   SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN, "%s() called with pCreateInfo->imageExtent = "
   1458                                                                               "(%d,%d), which is not equal to the "
   1459                                                                               "currentExtent = (%d,%d) returned by "
   1460                                                                               "vkGetPhysicalDeviceSurfaceCapabilitiesKHR().",
   1461                                   fn, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height,
   1462                                   pCapabilities->currentExtent.width, pCapabilities->currentExtent.height);
   1463         }
   1464         // Validate pCreateInfo->preTransform has one bit set (1st two
   1465         // lines of if-statement), which bit is also set in
   1466         // VkSurfaceCapabilitiesKHR::supportedTransforms (3rd line of if-statement):
   1467         if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
   1468             !(pCreateInfo->preTransform & pCapabilities->supportedTransforms)) {
   1469             // This is an error situation; one for which we'd like to give
   1470             // the developer a helpful, multi-line error message.  Build it
   1471             // up a little at a time, and then log it:
   1472             std::string errorString = "";
   1473             char str[1024];
   1474             // Here's the first part of the message:
   1475             sprintf(str, "%s() called with a non-supported "
   1476                          "pCreateInfo->preTransform (i.e. %s).  "
   1477                          "Supported values are:\n",
   1478                     fn, surfaceTransformStr(pCreateInfo->preTransform));
   1479             errorString += str;
   1480             for (int i = 0; i < 32; i++) {
   1481                 // Build up the rest of the message:
   1482                 if ((1 << i) & pCapabilities->supportedTransforms) {
   1483                     const char *newStr = surfaceTransformStr((VkSurfaceTransformFlagBitsKHR)(1 << i));
   1484                     sprintf(str, "    %s\n", newStr);
   1485                     errorString += str;
   1486                 }
   1487             }
   1488             // Log the message that we've built up:
   1489             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   1490                                 reinterpret_cast<uint64_t &>(device), __LINE__, SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM, LAYER_NAME,
   1491                                 "%s", errorString.c_str());
   1492         }
   1493         // Validate pCreateInfo->compositeAlpha has one bit set (1st two
   1494         // lines of if-statement), which bit is also set in
   1495         // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha (3rd line of if-statement):
   1496         if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
   1497             !((pCreateInfo->compositeAlpha) & pCapabilities->supportedCompositeAlpha)) {
   1498             // This is an error situation; one for which we'd like to give
   1499             // the developer a helpful, multi-line error message.  Build it
   1500             // up a little at a time, and then log it:
   1501             std::string errorString = "";
   1502             char str[1024];
   1503             // Here's the first part of the message:
   1504             sprintf(str, "%s() called with a non-supported "
   1505                          "pCreateInfo->compositeAlpha (i.e. %s).  "
   1506                          "Supported values are:\n",
   1507                     fn, surfaceCompositeAlphaStr(pCreateInfo->compositeAlpha));
   1508             errorString += str;
   1509             for (int i = 0; i < 32; i++) {
   1510                 // Build up the rest of the message:
   1511                 if ((1 << i) & pCapabilities->supportedCompositeAlpha) {
   1512                     const char *newStr = surfaceCompositeAlphaStr((VkCompositeAlphaFlagBitsKHR)(1 << i));
   1513                     sprintf(str, "    %s\n", newStr);
   1514                     errorString += str;
   1515                 }
   1516             }
   1517             // Log the message that we've built up:
   1518             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   1519                                 reinterpret_cast<uint64_t &>(device), __LINE__, SWAPCHAIN_CREATE_SWAP_BAD_COMPOSITE_ALPHA,
   1520                                 LAYER_NAME, "%s", errorString.c_str());
   1521         }
   1522         // Validate pCreateInfo->imageArraySize against
   1523         // VkSurfaceCapabilitiesKHR::maxImageArraySize:
   1524         if ((pCreateInfo->imageArrayLayers < 1) || (pCreateInfo->imageArrayLayers > pCapabilities->maxImageArrayLayers)) {
   1525             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1526                                   SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE, "%s() called with a non-supported "
   1527                                                                             "pCreateInfo->imageArraySize (i.e. %d).  "
   1528                                                                             "Minimum value is 1, maximum value is %d.",
   1529                                   fn, pCreateInfo->imageArrayLayers, pCapabilities->maxImageArrayLayers);
   1530         }
   1531         // Validate pCreateInfo->imageUsage against
   1532         // VkSurfaceCapabilitiesKHR::supportedUsageFlags:
   1533         if (pCreateInfo->imageUsage != (pCreateInfo->imageUsage & pCapabilities->supportedUsageFlags)) {
   1534             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1535                                   SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS, "%s() called with a non-supported "
   1536                                                                              "pCreateInfo->imageUsage (i.e. 0x%08x)."
   1537                                                                              "  Supported flag bits are 0x%08x.",
   1538                                   fn, pCreateInfo->imageUsage, pCapabilities->supportedUsageFlags);
   1539         }
   1540     }
   1541 
   1542     // Validate pCreateInfo values with the results of
   1543     // vkGetPhysicalDeviceSurfaceFormatsKHR():
   1544     if (!pPhysicalDevice || !pPhysicalDevice->surfaceFormatCount) {
   1545         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
   1546                               "%s() called before calling "
   1547                               "vkGetPhysicalDeviceSurfaceFormatsKHR().",
   1548                               fn);
   1549     } else if (pCreateInfo) {
   1550         // Validate pCreateInfo->imageFormat against
   1551         // VkSurfaceFormatKHR::format:
   1552         bool foundFormat = false;
   1553         bool foundColorSpace = false;
   1554         bool foundMatch = false;
   1555         for (uint32_t i = 0; i < pPhysicalDevice->surfaceFormatCount; i++) {
   1556             if (pCreateInfo->imageFormat == pPhysicalDevice->pSurfaceFormats[i].format) {
   1557                 // Validate pCreateInfo->imageColorSpace against
   1558                 // VkSurfaceFormatKHR::colorSpace:
   1559                 foundFormat = true;
   1560                 if (pCreateInfo->imageColorSpace == pPhysicalDevice->pSurfaceFormats[i].colorSpace) {
   1561                     foundMatch = true;
   1562                     break;
   1563                 }
   1564             } else {
   1565                 if (pCreateInfo->imageColorSpace == pPhysicalDevice->pSurfaceFormats[i].colorSpace) {
   1566                     foundColorSpace = true;
   1567                 }
   1568             }
   1569         }
   1570         if (!foundMatch) {
   1571             if (!foundFormat) {
   1572                 if (!foundColorSpace) {
   1573                     skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1574                                           SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP, "%s() called with neither a "
   1575                                                                                     "supported pCreateInfo->imageFormat "
   1576                                                                                     "(i.e. %d) nor a supported "
   1577                                                                                     "pCreateInfo->imageColorSpace "
   1578                                                                                     "(i.e. %d).",
   1579                                           fn, pCreateInfo->imageFormat, pCreateInfo->imageColorSpace);
   1580                 } else {
   1581                     skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1582                                           SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT, "%s() called with a non-supported "
   1583                                                                                 "pCreateInfo->imageFormat (i.e. %d).",
   1584                                           fn, pCreateInfo->imageFormat);
   1585                 }
   1586             } else if (!foundColorSpace) {
   1587                 skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1588                                       SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE, "%s() called with a non-supported "
   1589                                                                                  "pCreateInfo->imageColorSpace (i.e. %d).",
   1590                                       fn, pCreateInfo->imageColorSpace);
   1591             }
   1592         }
   1593     }
   1594 
   1595     // Validate pCreateInfo values with the results of
   1596     // vkGetPhysicalDeviceSurfacePresentModesKHR():
   1597     if (!pPhysicalDevice || !pPhysicalDevice->presentModeCount) {
   1598         if (!pCreateInfo || (pCreateInfo->presentMode != VK_PRESENT_MODE_FIFO_KHR)) {
   1599             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
   1600                                   "%s() called before calling "
   1601                                   "vkGetPhysicalDeviceSurfacePresentModesKHR().",
   1602                                   fn);
   1603         }
   1604     } else if (pCreateInfo) {
   1605         // Validate pCreateInfo->presentMode against
   1606         // vkGetPhysicalDeviceSurfacePresentModesKHR():
   1607         bool foundMatch = false;
   1608         for (uint32_t i = 0; i < pPhysicalDevice->presentModeCount; i++) {
   1609             if (pPhysicalDevice->pPresentModes[i] == pCreateInfo->presentMode) {
   1610                 foundMatch = true;
   1611                 break;
   1612             }
   1613         }
   1614         if (!foundMatch) {
   1615             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1616                                   SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE, "%s() called with a non-supported "
   1617                                                                           "pCreateInfo->presentMode (i.e. %s).",
   1618                                   fn, presentModeStr(pCreateInfo->presentMode));
   1619         }
   1620     }
   1621 
   1622     // Validate pCreateInfo->imageSharingMode and related values:
   1623     if (pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) {
   1624         if ((pCreateInfo->queueFamilyIndexCount <= 1) || !pCreateInfo->pQueueFamilyIndices) {
   1625             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1626                                   SWAPCHAIN_CREATE_SWAP_BAD_SHARING_VALUES, "%s() called with a supported "
   1627                                                                             "pCreateInfo->sharingMode of (i.e. %s), "
   1628                                                                             "but with a bad value(s) for "
   1629                                                                             "pCreateInfo->queueFamilyIndexCount or "
   1630                                                                             "pCreateInfo->pQueueFamilyIndices).",
   1631                                   fn, sharingModeStr(pCreateInfo->imageSharingMode));
   1632         }
   1633     } else if (pCreateInfo->imageSharingMode != VK_SHARING_MODE_EXCLUSIVE) {
   1634         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_CREATE_SWAP_BAD_SHARING_MODE,
   1635                               "%s() called with a non-supported "
   1636                               "pCreateInfo->imageSharingMode (i.e. %s).",
   1637                               fn, sharingModeStr(pCreateInfo->imageSharingMode));
   1638     }
   1639 
   1640     // Validate pCreateInfo->clipped:
   1641     if (pCreateInfo && (pCreateInfo->clipped != VK_FALSE) && (pCreateInfo->clipped != VK_TRUE)) {
   1642         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_BAD_BOOL,
   1643                               "%s() called with a VkBool32 value that is "
   1644                               "neither VK_TRUE nor VK_FALSE, but has the "
   1645                               "numeric value of %d.",
   1646                               fn, pCreateInfo->clipped);
   1647     }
   1648 
   1649     // Validate pCreateInfo->oldSwapchain:
   1650     if (pCreateInfo && pCreateInfo->oldSwapchain) {
   1651         SwpSwapchain *pOldSwapchain = NULL;
   1652         {
   1653           auto it = my_data->swapchainMap.find(pCreateInfo->oldSwapchain);
   1654           pOldSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1655         }
   1656         if (pOldSwapchain) {
   1657             if (device != pOldSwapchain->pDevice->device) {
   1658                 skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1659                                       SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE, "%s() called with a different VkDevice "
   1660                                                                           "than the VkSwapchainKHR was created with.",
   1661                                       __FUNCTION__);
   1662             }
   1663             if (pCreateInfo->surface != pOldSwapchain->pSurface->surface) {
   1664                 skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
   1665                                       SWAPCHAIN_CREATE_SWAP_DIFF_SURFACE, "%s() called with pCreateInfo->oldSwapchain "
   1666                                                                           "that has a different VkSurfaceKHR than "
   1667                                                                           "pCreateInfo->surface.",
   1668                                       fn);
   1669             }
   1670         } else {
   1671             // TBD: Leave this in (not sure object_track will check this)?
   1672             skipCall |=
   1673                 LOG_ERROR_NON_VALID_OBJ(VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, pCreateInfo->oldSwapchain, "VkSwapchainKHR");
   1674         }
   1675     }
   1676 
   1677     return skipCall;
   1678 }
   1679 
   1680 VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
   1681                                                   const VkAllocationCallbacks *pAllocator,
   1682                                                   VkSwapchainKHR *pSwapchain) {
   1683     VkResult result = VK_SUCCESS;
   1684     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1685     std::unique_lock<std::mutex> lock(global_lock);
   1686     bool skipCall = validateCreateSwapchainKHR(device, pCreateInfo, pSwapchain);
   1687 
   1688     if (!skipCall) {
   1689         // Call down the call chain:
   1690         lock.unlock();
   1691         result = my_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
   1692         lock.lock();
   1693 
   1694         if (result == VK_SUCCESS) {
   1695             // Remember the swapchain's handle, and link it to the device:
   1696             SwpDevice *pDevice = NULL;
   1697             {
   1698                 auto it = my_data->deviceMap.find(device);
   1699                 pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   1700             }
   1701 
   1702             my_data->swapchainMap[*pSwapchain].swapchain = *pSwapchain;
   1703             if (pDevice) {
   1704                 pDevice->swapchains[*pSwapchain] = &my_data->swapchainMap[*pSwapchain];
   1705             }
   1706             my_data->swapchainMap[*pSwapchain].pDevice = pDevice;
   1707             my_data->swapchainMap[*pSwapchain].imageCount = 0;
   1708             my_data->swapchainMap[*pSwapchain].usedAllocatorToCreate = (pAllocator != NULL);
   1709             // Store a pointer to the surface
   1710             SwpPhysicalDevice *pPhysicalDevice = pDevice->pPhysicalDevice;
   1711             SwpInstance *pInstance = (pPhysicalDevice) ? pPhysicalDevice->pInstance : NULL;
   1712             layer_data *my_instance_data =
   1713                 ((pInstance) ? get_my_data_ptr(get_dispatch_key(pInstance->instance), layer_data_map) : NULL);
   1714             SwpSurface *pSurface = ((my_data && pCreateInfo) ? &my_instance_data->surfaceMap[pCreateInfo->surface] : NULL);
   1715             my_data->swapchainMap[*pSwapchain].pSurface = pSurface;
   1716             if (pSurface) {
   1717                 pSurface->swapchains[*pSwapchain] = &my_data->swapchainMap[*pSwapchain];
   1718             }
   1719         }
   1720         return result;
   1721     }
   1722     return VK_ERROR_VALIDATION_FAILED_EXT;
   1723 }
   1724 
   1725 VKAPI_ATTR void VKAPI_CALL
   1726 DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
   1727     // TODOs:
   1728     //
   1729     // - Implement a check for validity language that reads: All uses of
   1730     //   presentable images acquired from pname:swapchain must: have completed
   1731     //   execution
   1732     bool skipCall = false;
   1733     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1734     std::unique_lock<std::mutex> lock(global_lock);
   1735     SwpDevice *pDevice = NULL;
   1736     {
   1737         auto it = my_data->deviceMap.find(device);
   1738         pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   1739     }
   1740 
   1741     // Validate that the swapchain extension was enabled:
   1742     if (pDevice && !pDevice->swapchainExtensionEnabled) {
   1743         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1744                               "%s() called even though the %s extension was not enabled for this VkDevice.", __FUNCTION__,
   1745                               VK_KHR_SWAPCHAIN_EXTENSION_NAME);
   1746     }
   1747 
   1748     // Regardless of skipCall value, do some internal cleanup:
   1749     SwpSwapchain *pSwapchain = NULL;
   1750     {
   1751         auto it = my_data->swapchainMap.find(swapchain);
   1752         pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1753     }
   1754     if (pSwapchain) {
   1755         // Delete the SwpSwapchain associated with this swapchain:
   1756         if (pSwapchain->pDevice) {
   1757             pSwapchain->pDevice->swapchains.erase(swapchain);
   1758             if (device != pSwapchain->pDevice->device) {
   1759                 LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE,
   1760                           "%s() called with a different VkDevice than the "
   1761                           "VkSwapchainKHR was created with.",
   1762                           __FUNCTION__);
   1763             }
   1764         }
   1765         if (pSwapchain->pSurface) {
   1766             pSwapchain->pSurface->swapchains.erase(swapchain);
   1767         }
   1768         if (pSwapchain->imageCount) {
   1769             pSwapchain->images.clear();
   1770         }
   1771         if ((pAllocator != NULL) != pSwapchain->usedAllocatorToCreate) {
   1772             LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, instance, "VkInstance", SWAPCHAIN_INCOMPATIBLE_ALLOCATOR,
   1773                       "%s() called with incompatible pAllocator from when "
   1774                       "the object was created.",
   1775                       __FUNCTION__);
   1776         }
   1777         my_data->swapchainMap.erase(swapchain);
   1778     }
   1779     lock.unlock();
   1780 
   1781     if (!skipCall) {
   1782         // Call down the call chain:
   1783         my_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator);
   1784     }
   1785 }
   1786 
   1787 VKAPI_ATTR VkResult VKAPI_CALL
   1788 GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
   1789     VkResult result = VK_SUCCESS;
   1790     bool skipCall = false;
   1791     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1792     std::unique_lock<std::mutex> lock(global_lock);
   1793     SwpDevice *pDevice = NULL;
   1794     {
   1795         auto it = my_data->deviceMap.find(device);
   1796         pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   1797     }
   1798 
   1799     // Validate that the swapchain extension was enabled:
   1800     if (pDevice && !pDevice->swapchainExtensionEnabled) {
   1801         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1802                               "%s() called even though the %s extension was not enabled for this VkDevice.", __FUNCTION__,
   1803                               VK_KHR_SWAPCHAIN_EXTENSION_NAME);
   1804     }
   1805     SwpSwapchain *pSwapchain = NULL;
   1806     {
   1807         auto it = my_data->swapchainMap.find(swapchain);
   1808         pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1809     }
   1810     if (!pSwapchainImageCount) {
   1811         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pSwapchainImageCount");
   1812     } else if (pSwapchain && pSwapchainImages) {
   1813         // Compare the preliminary value of *pSwapchainImageCount with the
   1814         // value this time:
   1815         if (pSwapchain->imageCount == 0) {
   1816             // Since we haven't recorded a preliminary value of
   1817             // *pSwapchainImageCount, that likely means that the application
   1818             // didn't previously call this function with a NULL value of
   1819             // pSwapchainImages:
   1820             skipCall |= LOG_ERROR_ZERO_PRIOR_COUNT(
   1821                 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   1822                 device, "pSwapchainImageCount", "pSwapchainImages");
   1823         } else if (*pSwapchainImageCount > pSwapchain->imageCount) {
   1824             skipCall |= LOG_ERROR_INVALID_COUNT(
   1825                 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
   1826                 device, "pSwapchainImageCount", "pSwapchainImages",
   1827                 *pSwapchainImageCount, pSwapchain->imageCount);
   1828         }
   1829     }
   1830 
   1831     if (!skipCall) {
   1832         // Call down the call chain:
   1833         lock.unlock();
   1834         result = my_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
   1835         lock.lock();
   1836 
   1837         // Obtain this pointer again after locking:
   1838         {
   1839             auto it = my_data->swapchainMap.find(swapchain);
   1840             pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1841         }
   1842         if ((result == VK_SUCCESS) && pSwapchain && !pSwapchainImages && pSwapchainImageCount) {
   1843             // Record the result of this preliminary query:
   1844             pSwapchain->imageCount = *pSwapchainImageCount;
   1845         } else if ((result == VK_SUCCESS) && pSwapchain && pSwapchainImages &&
   1846                    pSwapchainImageCount && (*pSwapchainImageCount > 0)) {
   1847             // Record the images and their state:
   1848             pSwapchain->imageCount = *pSwapchainImageCount;
   1849             for (uint32_t i = 0; i < *pSwapchainImageCount; i++) {
   1850                 pSwapchain->images[i].image = pSwapchainImages[i];
   1851                 pSwapchain->images[i].pSwapchain = pSwapchain;
   1852                 pSwapchain->images[i].acquiredByApp = false;
   1853             }
   1854         }
   1855         return result;
   1856     }
   1857     return VK_ERROR_VALIDATION_FAILED_EXT;
   1858 }
   1859 
   1860 VKAPI_ATTR VkResult VKAPI_CALL AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
   1861                                                    VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
   1862     // TODOs:
   1863     //
   1864     // - Address the timeout.  Possibilities include looking at the state of the
   1865     //   swapchain's images, depending on the timeout value.
   1866     // - Implement a check for validity language that reads: If pname:semaphore is
   1867     //   not sname:VK_NULL_HANDLE it must: be unsignalled
   1868     // - Implement a check for validity language that reads: If pname:fence is not
   1869     //   sname:VK_NULL_HANDLE it must: be unsignalled and mustnot: be associated
   1870     //   with any other queue command that has not yet completed execution on that
   1871     //   queue
   1872     // - Record/update the state of the swapchain, in case an error occurs
   1873     //   (e.g. VK_ERROR_OUT_OF_DATE_KHR).
   1874     VkResult result = VK_SUCCESS;
   1875     bool skipCall = false;
   1876     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   1877     std::unique_lock<std::mutex> lock(global_lock);
   1878     SwpDevice *pDevice = NULL;
   1879     {
   1880         auto it = my_data->deviceMap.find(device);
   1881         pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   1882     }
   1883 
   1884     // Validate that the swapchain extension was enabled:
   1885     if (pDevice && !pDevice->swapchainExtensionEnabled) {
   1886         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   1887                               "%s() called even though the %s extension was not enabled for this VkDevice.", __FUNCTION__,
   1888                               VK_KHR_SWAPCHAIN_EXTENSION_NAME);
   1889     }
   1890     if ((semaphore == VK_NULL_HANDLE) && (fence == VK_NULL_HANDLE)) {
   1891         skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice", SWAPCHAIN_NO_SYNC_FOR_ACQUIRE,
   1892                               "%s() called with both the semaphore and fence parameters set to "
   1893                               "VK_NULL_HANDLE (at least one should be used).", __FUNCTION__);
   1894     }
   1895     SwpSwapchain *pSwapchain = NULL;
   1896     {
   1897         auto it = my_data->swapchainMap.find(swapchain);
   1898         pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1899     }
   1900     SwpPhysicalDevice *pPhysicalDevice = pDevice->pPhysicalDevice;
   1901     if (pSwapchain && pPhysicalDevice && pPhysicalDevice->gotSurfaceCapabilities) {
   1902         // Look to see if the application has already acquired the maximum
   1903         // number of images, and this will push it past the spec-defined
   1904         // limits:
   1905         uint32_t minImageCount = pPhysicalDevice->surfaceCapabilities.minImageCount;
   1906         uint32_t imagesAcquiredByApp = 0;
   1907         for (uint32_t i = 0; i < pSwapchain->imageCount; i++) {
   1908             if (pSwapchain->images[i].acquiredByApp) {
   1909                 imagesAcquiredByApp++;
   1910             }
   1911         }
   1912         if (imagesAcquiredByApp > (pSwapchain->imageCount - minImageCount)) {
   1913             skipCall |= LOG_ERROR(
   1914                 VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
   1915                 swapchain, "VkSwapchainKHR",
   1916                 SWAPCHAIN_APP_ACQUIRES_TOO_MANY_IMAGES,
   1917                 "%s() called when it cannot succeed.  The application has "
   1918                 "acquired %d image(s) that have not yet been presented.  The "
   1919                 "maximum number of images that the application can "
   1920                 "simultaneously acquire from this swapchain (including this "
   1921                 "call to %s()) is %d.  That value is derived by subtracting "
   1922                 "VkSurfaceCapabilitiesKHR::minImageCount (%d) from the number "
   1923                 "of images in the swapchain (%d) and adding 1.\n",
   1924                 __FUNCTION__, imagesAcquiredByApp, __FUNCTION__,
   1925                 (pSwapchain->imageCount - minImageCount + 1),
   1926                 minImageCount, pSwapchain->imageCount);
   1927         }
   1928     }
   1929     if (!pImageIndex) {
   1930         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pImageIndex");
   1931     }
   1932 
   1933     if (!skipCall) {
   1934         // Call down the call chain:
   1935         lock.unlock();
   1936         result = my_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
   1937         lock.lock();
   1938 
   1939         // Obtain this pointer again after locking:
   1940         {
   1941             auto it = my_data->swapchainMap.find(swapchain);
   1942             pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1943         }
   1944         if (((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) && pSwapchain) {
   1945             // Change the state of the image (now acquired by the application):
   1946             pSwapchain->images[*pImageIndex].acquiredByApp = true;
   1947         }
   1948         return result;
   1949     }
   1950     return VK_ERROR_VALIDATION_FAILED_EXT;
   1951 }
   1952 
   1953 VKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
   1954     // TODOs:
   1955     //
   1956     // - Implement a check for validity language that reads: Any given element of
   1957     //   sname:VkSemaphore in pname:pWaitSemaphores must: refer to a prior signal
   1958     //   of that sname:VkSemaphore that won't be consumed by any other wait on that
   1959     //   semaphore
   1960     // - Record/update the state of the swapchain, in case an error occurs
   1961     //   (e.g. VK_ERROR_OUT_OF_DATE_KHR).
   1962     VkResult result = VK_SUCCESS;
   1963     bool skipCall = false;
   1964     layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
   1965 
   1966     if (!pPresentInfo) {
   1967         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pPresentInfo");
   1968     } else {
   1969         if (pPresentInfo->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR) {
   1970             skipCall |= LOG_ERROR_WRONG_STYPE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pPresentInfo",
   1971                                               "VK_STRUCTURE_TYPE_PRESENT_INFO_KHR");
   1972         }
   1973         if (pPresentInfo->pNext != NULL) {
   1974             skipCall |= LOG_INFO_WRONG_NEXT(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pPresentInfo");
   1975         }
   1976         if (!pPresentInfo->swapchainCount) {
   1977             skipCall |= LOG_ERROR_ZERO_VALUE(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pPresentInfo->swapchainCount");
   1978         }
   1979         if (!pPresentInfo->pSwapchains) {
   1980             skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pPresentInfo->pSwapchains");
   1981         }
   1982         if (!pPresentInfo->pImageIndices) {
   1983             skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "pPresentInfo->pImageIndices");
   1984         }
   1985         // Note: pPresentInfo->pResults is allowed to be NULL
   1986     }
   1987 
   1988     std::unique_lock<std::mutex> lock(global_lock);
   1989     for (uint32_t i = 0; pPresentInfo && (i < pPresentInfo->swapchainCount); i++) {
   1990         uint32_t index = pPresentInfo->pImageIndices[i];
   1991         SwpSwapchain *pSwapchain = NULL;
   1992         {
   1993             auto it = my_data->swapchainMap.find(pPresentInfo->pSwapchains[i]);
   1994             pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   1995         }
   1996         if (pSwapchain) {
   1997             if (!pSwapchain->pDevice->swapchainExtensionEnabled) {
   1998                 skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, pSwapchain->pDevice, "VkDevice",
   1999                                       SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
   2000                                       "%s() called even though the %s extension was not enabled for this VkDevice.", __FUNCTION__,
   2001                                       VK_KHR_SWAPCHAIN_EXTENSION_NAME);
   2002             }
   2003             if (index >= pSwapchain->imageCount) {
   2004                 skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, pPresentInfo->pSwapchains[i], "VkSwapchainKHR",
   2005                                       SWAPCHAIN_INDEX_TOO_LARGE, "%s() called for an index that is too "
   2006                                                                  "large (i.e. %d).  There are only %d "
   2007                                                                  "images in this VkSwapchainKHR.\n",
   2008                                       __FUNCTION__, index, pSwapchain->imageCount);
   2009             } else {
   2010                 if (!pSwapchain->images[index].acquiredByApp) {
   2011                     skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, pPresentInfo->pSwapchains[i],
   2012                                           "VkSwapchainKHR", SWAPCHAIN_INDEX_NOT_IN_USE, "%s() returned an index (i.e. %d) "
   2013                                                                                         "for an image that is not acquired by "
   2014                                                                                         "the application.",
   2015                                           __FUNCTION__, index);
   2016                 }
   2017             }
   2018             SwpQueue *pQueue = NULL;
   2019             {
   2020                 auto it = my_data->queueMap.find(queue);
   2021                 pQueue = (it == my_data->queueMap.end()) ? NULL : &it->second;
   2022             }
   2023             SwpSurface *pSurface = pSwapchain->pSurface;
   2024             if (pQueue && pSurface && pSurface->numQueueFamilyIndexSupport) {
   2025                 uint32_t queueFamilyIndex = pQueue->queueFamilyIndex;
   2026                 // Note: the 1st test is to ensure queueFamilyIndex is in range,
   2027                 // and the 2nd test is the validation check:
   2028                 if ((pSurface->numQueueFamilyIndexSupport > queueFamilyIndex) &&
   2029                     (!pSurface->pQueueFamilyIndexSupport[queueFamilyIndex])) {
   2030                     skipCall |=
   2031                         LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, pPresentInfo->pSwapchains[i], "VkSwapchainKHR",
   2032                                   SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE, "%s() called with a swapchain whose "
   2033                                                                               "surface is not supported for "
   2034                                                                               "presention on this device with the "
   2035                                                                               "queueFamilyIndex (i.e. %d) of the "
   2036                                                                               "given queue.",
   2037                                   __FUNCTION__, queueFamilyIndex);
   2038                 }
   2039             }
   2040         }
   2041     }
   2042 
   2043     if (!skipCall) {
   2044         // Call down the call chain:
   2045         lock.unlock();
   2046         result = my_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo);
   2047         lock.lock();
   2048 
   2049         if (pPresentInfo && ((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR))) {
   2050             for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
   2051                 int index = pPresentInfo->pImageIndices[i];
   2052                 SwpSwapchain *pSwapchain = NULL;
   2053                 {
   2054                     auto it = my_data->swapchainMap.find(pPresentInfo->pSwapchains[i]);
   2055                     pSwapchain = (it == my_data->swapchainMap.end()) ? NULL : &it->second;
   2056                 }
   2057                 if (pSwapchain) {
   2058                     // Change the state of the image (no longer acquired by the
   2059                     // application):
   2060                     pSwapchain->images[index].acquiredByApp = false;
   2061                 }
   2062             }
   2063         }
   2064         return result;
   2065     }
   2066     return VK_ERROR_VALIDATION_FAILED_EXT;
   2067 }
   2068 
   2069 VKAPI_ATTR void VKAPI_CALL
   2070 GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
   2071     bool skipCall = false;
   2072     layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   2073 
   2074     if (!skipCall) {
   2075         // Call down the call chain:
   2076         my_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
   2077 
   2078         // Remember the queue's handle, and link it to the device:
   2079         std::lock_guard<std::mutex> lock(global_lock);
   2080         SwpDevice *pDevice = NULL;
   2081         {
   2082             auto it = my_data->deviceMap.find(device);
   2083             pDevice = (it == my_data->deviceMap.end()) ? NULL : &it->second;
   2084         }
   2085         my_data->queueMap[&pQueue].queue = *pQueue;
   2086         if (pDevice) {
   2087             pDevice->queues[*pQueue] = &my_data->queueMap[*pQueue];
   2088         }
   2089         my_data->queueMap[&pQueue].pDevice = pDevice;
   2090         my_data->queueMap[&pQueue].queueFamilyIndex = queueFamilyIndex;
   2091     }
   2092 }
   2093 
   2094 VKAPI_ATTR VkResult VKAPI_CALL
   2095 CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
   2096                              const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
   2097     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   2098     VkResult result =
   2099         my_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
   2100     if (VK_SUCCESS == result) {
   2101         std::lock_guard<std::mutex> lock(global_lock);
   2102         result = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback);
   2103     }
   2104     return result;
   2105 }
   2106 
   2107 VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance,
   2108                                                          VkDebugReportCallbackEXT msgCallback,
   2109                                                          const VkAllocationCallbacks *pAllocator) {
   2110     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   2111     my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
   2112     std::lock_guard<std::mutex> lock(global_lock);
   2113     layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);
   2114 }
   2115 
   2116 VKAPI_ATTR void VKAPI_CALL
   2117 DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
   2118                       size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
   2119     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   2120     my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
   2121                                                             pMsg);
   2122 }
   2123 
   2124 VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
   2125                                                                   const char *pLayerName, uint32_t *pCount,
   2126                                                                   VkExtensionProperties *pProperties) {
   2127     if (pLayerName && !strcmp(pLayerName, swapchain_layer.layerName))
   2128         return util_GetExtensionProperties(0, nullptr, pCount, pProperties);
   2129 
   2130     assert(physicalDevice);
   2131 
   2132     dispatch_key key = get_dispatch_key(physicalDevice);
   2133     layer_data *my_data = get_my_data_ptr(key, layer_data_map);
   2134     return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
   2135 }
   2136 
   2137 static PFN_vkVoidFunction
   2138 intercept_core_instance_command(const char *name);
   2139 
   2140 static PFN_vkVoidFunction
   2141 intercept_khr_surface_command(const char *name, VkInstance instance);
   2142 
   2143 static PFN_vkVoidFunction
   2144 intercept_core_device_command(const char *name);
   2145 
   2146 static PFN_vkVoidFunction
   2147 intercept_khr_swapchain_command(const char *name, VkDevice dev);
   2148 
   2149 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
   2150     PFN_vkVoidFunction proc = intercept_core_device_command(funcName);
   2151     if (proc)
   2152         return proc;
   2153 
   2154     assert(device);
   2155 
   2156     layer_data *my_data;
   2157 
   2158     my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
   2159     VkLayerDispatchTable *pDisp =  my_data->device_dispatch_table;
   2160 
   2161     proc = intercept_khr_swapchain_command(funcName, device);
   2162     if (proc)
   2163         return proc;
   2164 
   2165     if (pDisp->GetDeviceProcAddr == NULL)
   2166         return NULL;
   2167     return pDisp->GetDeviceProcAddr(device, funcName);
   2168 }
   2169 
   2170 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
   2171     PFN_vkVoidFunction proc = intercept_core_instance_command(funcName);
   2172     if (!proc)
   2173         proc = intercept_core_device_command(funcName);
   2174     if (!proc)
   2175         proc = intercept_khr_swapchain_command(funcName, VK_NULL_HANDLE);
   2176     if (proc)
   2177         return proc;
   2178 
   2179     assert(instance);
   2180 
   2181     layer_data *my_data;
   2182     my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
   2183     VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
   2184 
   2185     proc = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
   2186     if (!proc)
   2187         proc = intercept_khr_surface_command(funcName, instance);
   2188     if (proc)
   2189         return proc;
   2190 
   2191     if (pTable->GetInstanceProcAddr == NULL)
   2192         return NULL;
   2193     return pTable->GetInstanceProcAddr(instance, funcName);
   2194 }
   2195 
   2196 static PFN_vkVoidFunction
   2197 intercept_core_instance_command(const char *name) {
   2198     static const struct {
   2199         const char *name;
   2200         PFN_vkVoidFunction proc;
   2201     } core_instance_commands[] = {
   2202         { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
   2203         { "vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance) },
   2204         { "vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance) },
   2205         { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
   2206         { "vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices) },
   2207         { "vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties) },
   2208         { "vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties) },
   2209     };
   2210 
   2211     // we should never be queried for these commands
   2212     assert(strcmp(name, "vkEnumerateInstanceLayerProperties") &&
   2213            strcmp(name, "vkEnumerateInstanceExtensionProperties") &&
   2214            strcmp(name, "vkEnumerateDeviceLayerProperties"));
   2215 
   2216     for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++) {
   2217         if (!strcmp(core_instance_commands[i].name, name))
   2218             return core_instance_commands[i].proc;
   2219     }
   2220 
   2221     return nullptr;
   2222 }
   2223 
   2224 static PFN_vkVoidFunction
   2225 intercept_khr_surface_command(const char *name, VkInstance instance) {
   2226     static const struct {
   2227         const char *name;
   2228         PFN_vkVoidFunction proc;
   2229     } khr_surface_commands[] = {
   2230 #ifdef VK_USE_PLATFORM_ANDROID_KHR
   2231         { "vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR) },
   2232 #endif // VK_USE_PLATFORM_ANDROID_KHR
   2233 #ifdef VK_USE_PLATFORM_MIR_KHR
   2234         { "vkCreateMirSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateMirSurfaceKHR) },
   2235         { "vkGetPhysicalDeviceMirPresentationSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceMirPresentationSupportKHR) },
   2236 #endif // VK_USE_PLATFORM_MIR_KHR
   2237 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
   2238         { "vkCreateWaylandSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWaylandSurfaceKHR) },
   2239         { "vkGetPhysicalDeviceWaylandPresentationSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceWaylandPresentationSupportKHR) },
   2240 #endif // VK_USE_PLATFORM_WAYLAND_KHR
   2241 #ifdef VK_USE_PLATFORM_WIN32_KHR
   2242         { "vkCreateWin32SurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateWin32SurfaceKHR) },
   2243         { "vkGetPhysicalDeviceWin32PresentationSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceWin32PresentationSupportKHR) },
   2244 #endif // VK_USE_PLATFORM_WIN32_KHR
   2245 #ifdef VK_USE_PLATFORM_XCB_KHR
   2246         { "vkCreateXcbSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXcbSurfaceKHR) },
   2247         { "vkGetPhysicalDeviceXcbPresentationSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceXcbPresentationSupportKHR) },
   2248 #endif // VK_USE_PLATFORM_XCB_KHR
   2249 #ifdef VK_USE_PLATFORM_XLIB_KHR
   2250         { "vkCreateXlibSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateXlibSurfaceKHR) },
   2251         { "vkGetPhysicalDeviceXlibPresentationSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceXlibPresentationSupportKHR) },
   2252 #endif // VK_USE_PLATFORM_XLIB_KHR
   2253         { "vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR) },
   2254         { "vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR) },
   2255         { "vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR) },
   2256         { "vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR) },
   2257         { "vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR) },
   2258     };
   2259 
   2260     // do not check if VK_KHR_*_surface is enabled (why?)
   2261 
   2262     for (size_t i = 0; i < ARRAY_SIZE(khr_surface_commands); i++) {
   2263         if (!strcmp(khr_surface_commands[i].name, name))
   2264             return khr_surface_commands[i].proc;
   2265     }
   2266 
   2267     return nullptr;
   2268 }
   2269 
   2270 static PFN_vkVoidFunction
   2271 intercept_core_device_command(const char *name) {
   2272     static const struct {
   2273         const char *name;
   2274         PFN_vkVoidFunction proc;
   2275     } core_device_commands[] = {
   2276         { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
   2277         { "vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice) },
   2278         { "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
   2279     };
   2280 
   2281     for (size_t i = 0; i < ARRAY_SIZE(core_device_commands); i++) {
   2282         if (!strcmp(core_device_commands[i].name, name))
   2283             return core_device_commands[i].proc;
   2284     }
   2285 
   2286     return nullptr;
   2287 }
   2288 
   2289 static PFN_vkVoidFunction
   2290 intercept_khr_swapchain_command(const char *name, VkDevice dev) {
   2291     static const struct {
   2292         const char *name;
   2293         PFN_vkVoidFunction proc;
   2294     } khr_swapchain_commands[] = {
   2295         { "vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR) },
   2296         { "vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR) },
   2297         { "vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR) },
   2298         { "vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR) },
   2299         { "vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR) },
   2300     };
   2301 
   2302     // do not check if VK_KHR_swapchain is enabled (why?)
   2303 
   2304     for (size_t i = 0; i < ARRAY_SIZE(khr_swapchain_commands); i++) {
   2305         if (!strcmp(khr_swapchain_commands[i].name, name))
   2306             return khr_swapchain_commands[i].proc;
   2307     }
   2308 
   2309     return nullptr;
   2310 }
   2311 
   2312 } // namespace swapchain
   2313 
   2314 // vk_layer_logging.h expects these to be defined
   2315 
   2316 VKAPI_ATTR VkResult VKAPI_CALL
   2317 vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
   2318                                const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
   2319     return swapchain::CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
   2320 }
   2321 
   2322 VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance,
   2323                                                                            VkDebugReportCallbackEXT msgCallback,
   2324                                                                            const VkAllocationCallbacks *pAllocator) {
   2325     swapchain::DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
   2326 }
   2327 
   2328 VKAPI_ATTR void VKAPI_CALL
   2329 vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
   2330                         size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
   2331     swapchain::DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
   2332 }
   2333 
   2334 // loader-layer interface v0
   2335 
   2336 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   2337 vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
   2338     return util_GetExtensionProperties(ARRAY_SIZE(swapchain::instance_extensions), swapchain::instance_extensions, pCount, pProperties);
   2339 }
   2340 
   2341 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   2342 vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
   2343     return util_GetLayerProperties(1, &swapchain::swapchain_layer, pCount, pProperties);
   2344 }
   2345 
   2346 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
   2347 vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
   2348     return util_GetLayerProperties(1, &swapchain::swapchain_layer, pCount, pProperties);
   2349 }
   2350 
   2351 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
   2352                                                                                     const char *pLayerName, uint32_t *pCount,
   2353                                                                                     VkExtensionProperties *pProperties) {
   2354     // the layer command handles VK_NULL_HANDLE just fine
   2355     return swapchain::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
   2356 }
   2357 
   2358 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
   2359     return swapchain::GetDeviceProcAddr(dev, funcName);
   2360 }
   2361 
   2362 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
   2363     if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties"))
   2364         return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceLayerProperties);
   2365     if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties"))
   2366         return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateDeviceLayerProperties);
   2367     if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties"))
   2368         return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceExtensionProperties);
   2369     if (!strcmp(funcName, "vkGetInstanceProcAddr"))
   2370         return reinterpret_cast<PFN_vkVoidFunction>(vkGetInstanceProcAddr);
   2371 
   2372     return swapchain::GetInstanceProcAddr(instance, funcName);
   2373 }
   2374