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