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: Tobin Ehlis <tobine (at) google.com> 19 */ 20 21 #include "vk_loader_platform.h" 22 #include "vulkan/vulkan.h" 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <cinttypes> 28 29 #include <unordered_map> 30 #include <vector> 31 #include <mutex> 32 33 #include "vulkan/vk_layer.h" 34 #include "vk_layer_config.h" 35 #include "vk_layer_table.h" 36 #include "vk_layer_data.h" 37 #include "vk_layer_logging.h" 38 #include "vk_layer_extension_utils.h" 39 #include "vk_safe_struct.h" 40 #include "vk_layer_utils.h" 41 42 namespace unique_objects { 43 44 // All increments must be guarded by global_lock 45 static uint64_t global_unique_id = 1; 46 47 struct layer_data { 48 VkInstance instance; 49 50 bool wsi_enabled; 51 std::unordered_map<uint64_t, uint64_t> unique_id_mapping; // Map uniqueID to actual object handle 52 VkPhysicalDevice gpu; 53 54 layer_data() : wsi_enabled(false), gpu(VK_NULL_HANDLE){}; 55 }; 56 57 struct instExts { 58 bool wsi_enabled; 59 bool xlib_enabled; 60 bool xcb_enabled; 61 bool wayland_enabled; 62 bool mir_enabled; 63 bool android_enabled; 64 bool win32_enabled; 65 }; 66 67 static std::unordered_map<void *, struct instExts> instanceExtMap; 68 static std::unordered_map<void *, layer_data *> layer_data_map; 69 static device_table_map unique_objects_device_table_map; 70 static instance_table_map unique_objects_instance_table_map; 71 static std::mutex global_lock; // Protect map accesses and unique_id increments 72 73 // Handle CreateInstance 74 static void createInstanceRegisterExtensions(const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) { 75 uint32_t i; 76 VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(unique_objects_instance_table_map, instance); 77 PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr; 78 79 pDisp->DestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)gpa(instance, "vkDestroySurfaceKHR"); 80 pDisp->GetPhysicalDeviceSurfaceSupportKHR = 81 (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"); 82 pDisp->GetPhysicalDeviceSurfaceCapabilitiesKHR = 83 (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); 84 pDisp->GetPhysicalDeviceSurfaceFormatsKHR = 85 (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)gpa(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"); 86 pDisp->GetPhysicalDeviceSurfacePresentModesKHR = 87 (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)gpa(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"); 88 #ifdef VK_USE_PLATFORM_WIN32_KHR 89 pDisp->CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)gpa(instance, "vkCreateWin32SurfaceKHR"); 90 pDisp->GetPhysicalDeviceWin32PresentationSupportKHR = 91 (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); 92 #endif // VK_USE_PLATFORM_WIN32_KHR 93 #ifdef VK_USE_PLATFORM_XCB_KHR 94 pDisp->CreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)gpa(instance, "vkCreateXcbSurfaceKHR"); 95 pDisp->GetPhysicalDeviceXcbPresentationSupportKHR = 96 (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); 97 #endif // VK_USE_PLATFORM_XCB_KHR 98 #ifdef VK_USE_PLATFORM_XLIB_KHR 99 pDisp->CreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)gpa(instance, "vkCreateXlibSurfaceKHR"); 100 pDisp->GetPhysicalDeviceXlibPresentationSupportKHR = 101 (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); 102 #endif // VK_USE_PLATFORM_XLIB_KHR 103 #ifdef VK_USE_PLATFORM_MIR_KHR 104 pDisp->CreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)gpa(instance, "vkCreateMirSurfaceKHR"); 105 pDisp->GetPhysicalDeviceMirPresentationSupportKHR = 106 (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); 107 #endif // VK_USE_PLATFORM_MIR_KHR 108 #ifdef VK_USE_PLATFORM_WAYLAND_KHR 109 pDisp->CreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)gpa(instance, "vkCreateWaylandSurfaceKHR"); 110 pDisp->GetPhysicalDeviceWaylandPresentationSupportKHR = 111 (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)gpa(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); 112 #endif // VK_USE_PLATFORM_WAYLAND_KHR 113 #ifdef VK_USE_PLATFORM_ANDROID_KHR 114 pDisp->CreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)gpa(instance, "vkCreateAndroidSurfaceKHR"); 115 #endif // VK_USE_PLATFORM_ANDROID_KHR 116 117 instanceExtMap[pDisp] = {}; 118 for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 119 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME) == 0) 120 instanceExtMap[pDisp].wsi_enabled = true; 121 #ifdef VK_USE_PLATFORM_XLIB_KHR 122 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) 123 instanceExtMap[pDisp].xlib_enabled = true; 124 #endif 125 #ifdef VK_USE_PLATFORM_XCB_KHR 126 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) 127 instanceExtMap[pDisp].xcb_enabled = true; 128 #endif 129 #ifdef VK_USE_PLATFORM_WAYLAND_KHR 130 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) 131 instanceExtMap[pDisp].wayland_enabled = true; 132 #endif 133 #ifdef VK_USE_PLATFORM_MIR_KHR 134 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MIR_SURFACE_EXTENSION_NAME) == 0) 135 instanceExtMap[pDisp].mir_enabled = true; 136 #endif 137 #ifdef VK_USE_PLATFORM_ANDROID_KHR 138 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) 139 instanceExtMap[pDisp].android_enabled = true; 140 #endif 141 #ifdef VK_USE_PLATFORM_WIN32_KHR 142 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) 143 instanceExtMap[pDisp].win32_enabled = true; 144 #endif 145 } 146 } 147 148 VkResult explicit_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 149 VkInstance *pInstance) { 150 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 151 152 assert(chain_info->u.pLayerInfo); 153 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 154 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); 155 if (fpCreateInstance == NULL) { 156 return VK_ERROR_INITIALIZATION_FAILED; 157 } 158 159 // Advance the link info for the next element on the chain 160 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 161 162 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); 163 if (result != VK_SUCCESS) { 164 return result; 165 } 166 167 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); 168 my_data->instance = *pInstance; 169 initInstanceTable(*pInstance, fpGetInstanceProcAddr, unique_objects_instance_table_map); 170 171 createInstanceRegisterExtensions(pCreateInfo, *pInstance); 172 173 return result; 174 } 175 176 void explicit_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { 177 dispatch_key key = get_dispatch_key(instance); 178 get_dispatch_table(unique_objects_instance_table_map, instance)->DestroyInstance(instance, pAllocator); 179 layer_data_map.erase(key); 180 } 181 182 // Handle CreateDevice 183 static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) { 184 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 185 VkLayerDispatchTable *pDisp = get_dispatch_table(unique_objects_device_table_map, device); 186 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr; 187 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR"); 188 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR"); 189 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR"); 190 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR"); 191 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR"); 192 my_device_data->wsi_enabled = false; 193 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 194 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) 195 my_device_data->wsi_enabled = true; 196 } 197 } 198 199 VkResult explicit_CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 200 VkDevice *pDevice) { 201 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); 202 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 203 204 assert(chain_info->u.pLayerInfo); 205 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 206 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; 207 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(my_instance_data->instance, "vkCreateDevice"); 208 if (fpCreateDevice == NULL) { 209 return VK_ERROR_INITIALIZATION_FAILED; 210 } 211 212 // Advance the link info for the next element on the chain 213 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 214 215 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice); 216 if (result != VK_SUCCESS) { 217 return result; 218 } 219 220 // Setup layer's device dispatch table 221 initDeviceTable(*pDevice, fpGetDeviceProcAddr, unique_objects_device_table_map); 222 223 createDeviceRegisterExtensions(pCreateInfo, *pDevice); 224 // Set gpu for this device in order to get at any objects mapped at instance level 225 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); 226 my_device_data->gpu = gpu; 227 228 return result; 229 } 230 231 void explicit_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) { 232 dispatch_key key = get_dispatch_key(device); 233 get_dispatch_table(unique_objects_device_table_map, device)->DestroyDevice(device, pAllocator); 234 layer_data_map.erase(key); 235 } 236 237 VkResult explicit_CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 238 const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, 239 VkPipeline *pPipelines) { 240 // STRUCT USES:{'pipelineCache': 'VkPipelineCache', 'pCreateInfos[createInfoCount]': {'stage': {'module': 'VkShaderModule'}, 241 // 'layout': 'VkPipelineLayout', 'basePipelineHandle': 'VkPipeline'}} 242 // LOCAL DECLS:{'pCreateInfos': 'VkComputePipelineCreateInfo*'} 243 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 244 safe_VkComputePipelineCreateInfo *local_pCreateInfos = NULL; 245 if (pCreateInfos) { 246 std::lock_guard<std::mutex> lock(global_lock); 247 local_pCreateInfos = new safe_VkComputePipelineCreateInfo[createInfoCount]; 248 for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) { 249 local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]); 250 if (pCreateInfos[idx0].basePipelineHandle) { 251 local_pCreateInfos[idx0].basePipelineHandle = 252 (VkPipeline)my_device_data 253 ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].basePipelineHandle)]; 254 } 255 if (pCreateInfos[idx0].layout) { 256 local_pCreateInfos[idx0].layout = 257 (VkPipelineLayout) 258 my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].layout)]; 259 } 260 if (pCreateInfos[idx0].stage.module) { 261 local_pCreateInfos[idx0].stage.module = 262 (VkShaderModule) 263 my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].stage.module)]; 264 } 265 } 266 } 267 if (pipelineCache) { 268 std::lock_guard<std::mutex> lock(global_lock); 269 pipelineCache = (VkPipelineCache)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(pipelineCache)]; 270 } 271 272 VkResult result = get_dispatch_table(unique_objects_device_table_map, device) 273 ->CreateComputePipelines(device, pipelineCache, createInfoCount, 274 (const VkComputePipelineCreateInfo *)local_pCreateInfos, pAllocator, pPipelines); 275 delete[] local_pCreateInfos; 276 if (VK_SUCCESS == result) { 277 uint64_t unique_id = 0; 278 std::lock_guard<std::mutex> lock(global_lock); 279 for (uint32_t i = 0; i < createInfoCount; ++i) { 280 unique_id = global_unique_id++; 281 my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pPipelines[i]); 282 pPipelines[i] = reinterpret_cast<VkPipeline &>(unique_id); 283 } 284 } 285 return result; 286 } 287 288 VkResult explicit_CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 289 const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, 290 VkPipeline *pPipelines) { 291 // STRUCT USES:{'pipelineCache': 'VkPipelineCache', 'pCreateInfos[createInfoCount]': {'layout': 'VkPipelineLayout', 292 // 'pStages[stageCount]': {'module': 'VkShaderModule'}, 'renderPass': 'VkRenderPass', 'basePipelineHandle': 'VkPipeline'}} 293 // LOCAL DECLS:{'pCreateInfos': 'VkGraphicsPipelineCreateInfo*'} 294 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 295 safe_VkGraphicsPipelineCreateInfo *local_pCreateInfos = NULL; 296 if (pCreateInfos) { 297 local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount]; 298 std::lock_guard<std::mutex> lock(global_lock); 299 for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) { 300 local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]); 301 if (pCreateInfos[idx0].basePipelineHandle) { 302 local_pCreateInfos[idx0].basePipelineHandle = 303 (VkPipeline)my_device_data 304 ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].basePipelineHandle)]; 305 } 306 if (pCreateInfos[idx0].layout) { 307 local_pCreateInfos[idx0].layout = 308 (VkPipelineLayout) 309 my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].layout)]; 310 } 311 if (pCreateInfos[idx0].pStages) { 312 for (uint32_t idx1 = 0; idx1 < pCreateInfos[idx0].stageCount; ++idx1) { 313 if (pCreateInfos[idx0].pStages[idx1].module) { 314 local_pCreateInfos[idx0].pStages[idx1].module = 315 (VkShaderModule)my_device_data 316 ->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].pStages[idx1].module)]; 317 } 318 } 319 } 320 if (pCreateInfos[idx0].renderPass) { 321 local_pCreateInfos[idx0].renderPass = 322 (VkRenderPass) 323 my_device_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfos[idx0].renderPass)]; 324 } 325 } 326 } 327 if (pipelineCache) { 328 std::lock_guard<std::mutex> lock(global_lock); 329 pipelineCache = (VkPipelineCache)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(pipelineCache)]; 330 } 331 332 VkResult result = 333 get_dispatch_table(unique_objects_device_table_map, device) 334 ->CreateGraphicsPipelines(device, pipelineCache, createInfoCount, 335 (const VkGraphicsPipelineCreateInfo *)local_pCreateInfos, pAllocator, pPipelines); 336 delete[] local_pCreateInfos; 337 if (VK_SUCCESS == result) { 338 uint64_t unique_id = 0; 339 std::lock_guard<std::mutex> lock(global_lock); 340 for (uint32_t i = 0; i < createInfoCount; ++i) { 341 unique_id = global_unique_id++; 342 my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pPipelines[i]); 343 pPipelines[i] = reinterpret_cast<VkPipeline &>(unique_id); 344 } 345 } 346 return result; 347 } 348 349 VkResult explicit_CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, 350 const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) { 351 layer_data *my_map_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 352 353 safe_VkSwapchainCreateInfoKHR *local_pCreateInfo = NULL; 354 if (pCreateInfo) { 355 std::lock_guard<std::mutex> lock(global_lock); 356 local_pCreateInfo = new safe_VkSwapchainCreateInfoKHR(pCreateInfo); 357 local_pCreateInfo->oldSwapchain = 358 (VkSwapchainKHR)my_map_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfo->oldSwapchain)]; 359 // Need to pull surface mapping from the instance-level map 360 layer_data *instance_data = get_my_data_ptr(get_dispatch_key(my_map_data->gpu), layer_data_map); 361 local_pCreateInfo->surface = 362 (VkSurfaceKHR)instance_data->unique_id_mapping[reinterpret_cast<const uint64_t &>(pCreateInfo->surface)]; 363 } 364 365 VkResult result = get_dispatch_table(unique_objects_device_table_map, device) 366 ->CreateSwapchainKHR(device, (const VkSwapchainCreateInfoKHR *)local_pCreateInfo, pAllocator, pSwapchain); 367 if (local_pCreateInfo) 368 delete local_pCreateInfo; 369 if (VK_SUCCESS == result) { 370 std::lock_guard<std::mutex> lock(global_lock); 371 uint64_t unique_id =global_unique_id++; 372 my_map_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(*pSwapchain); 373 *pSwapchain = reinterpret_cast<VkSwapchainKHR &>(unique_id); 374 } 375 return result; 376 } 377 378 VkResult explicit_GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, 379 VkImage *pSwapchainImages) { 380 // UNWRAP USES: 381 // 0 : swapchain,VkSwapchainKHR, pSwapchainImages,VkImage 382 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); 383 if (VK_NULL_HANDLE != swapchain) { 384 std::lock_guard<std::mutex> lock(global_lock); 385 swapchain = (VkSwapchainKHR)my_device_data->unique_id_mapping[reinterpret_cast<uint64_t &>(swapchain)]; 386 } 387 VkResult result = get_dispatch_table(unique_objects_device_table_map, device) 388 ->GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); 389 // TODO : Need to add corresponding code to delete these images 390 if (VK_SUCCESS == result) { 391 if ((*pSwapchainImageCount > 0) && pSwapchainImages) { 392 uint64_t unique_id = 0; 393 std::lock_guard<std::mutex> lock(global_lock); 394 for (uint32_t i = 0; i < *pSwapchainImageCount; ++i) { 395 unique_id = global_unique_id++; 396 my_device_data->unique_id_mapping[unique_id] = reinterpret_cast<uint64_t &>(pSwapchainImages[i]); 397 pSwapchainImages[i] = reinterpret_cast<VkImage &>(unique_id); 398 } 399 } 400 } 401 return result; 402 } 403 404 } // namespace unique_objects 405