loader.c revision 5c13d4d87fd0356003a3441e887a172b991e880f
10fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod/*
20fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
30fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Copyright (c) 2014-2016 The Khronos Group Inc.
40fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Copyright (c) 2014-2016 Valve Corporation
50fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Copyright (c) 2014-2016 LunarG, Inc.
60fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Copyright (C) 2015 Google Inc.
70fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
80fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Permission is hereby granted, free of charge, to any person obtaining a copy
90fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * of this software and/or associated documentation files (the "Materials"), to
100fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * deal in the Materials without restriction, including without limitation the
110fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
120fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * sell copies of the Materials, and to permit persons to whom the Materials are
130fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * furnished to do so, subject to the following conditions:
140fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
150fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * The above copyright notice(s) and this permission notice shall be included in
160fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * all copies or substantial portions of the Materials.
170fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
180fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
190fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
200fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
210fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
220fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
230fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
240fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
250fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * USE OR OTHER DEALINGS IN THE MATERIALS.
260fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
270fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Author: Jon Ashburn <jon@lunarg.com>
280fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
290fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod *
300fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod */
310fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
320fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#define _GNU_SOURCE
330fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <stdio.h>
340fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <stdlib.h>
350fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <stdarg.h>
360fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <stdbool.h>
370fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <string.h>
380fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
390fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <sys/types.h>
400fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#if defined(_WIN32)
410fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "dirent_on_windows.h"
420fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#else // _WIN32
430fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include <dirent.h>
440fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif // _WIN32
450fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "vk_loader_platform.h"
460fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "loader.h"
470fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "gpa_helper.h"
480fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "table_ops.h"
490fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "debug_report.h"
500fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "wsi.h"
510fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "vulkan/vk_icd.h"
520fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "cJSON.h"
530fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#include "murmurhash.h"
540fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
550fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic loader_platform_dl_handle
560fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodloader_add_layer_lib(const struct loader_instance *inst, const char *chain_type,
570fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                     struct loader_layer_properties *layer_prop);
580fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
590fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic void loader_remove_layer_lib(struct loader_instance *inst,
600fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                    struct loader_layer_properties *layer_prop);
610fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
620fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstruct loader_struct loader = {0};
630fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// TLS for instance for alloc/free callbacks
640fbb2dc83132a89201ad8b56c6909610437d2da0Behdad EsfahbodTHREAD_LOCAL_DECL struct loader_instance *tls_instance;
650fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
660fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic bool loader_init_generic_list(const struct loader_instance *inst,
670fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                     struct loader_generic_list *list_info,
680fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                     size_t element_size);
690fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
700fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic size_t loader_platform_combine_path(char *dest, size_t len, ...);
710fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
720fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstruct loader_phys_dev_per_icd {
730fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    uint32_t count;
7402aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    VkPhysicalDevice *phys_devs;
750fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod};
760fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
770fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodenum loader_debug {
7802aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    LOADER_INFO_BIT = 0x01,
7902aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    LOADER_WARN_BIT = 0x02,
800fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    LOADER_PERF_BIT = 0x04,
8102aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    LOADER_ERROR_BIT = 0x08,
8202aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    LOADER_DEBUG_BIT = 0x10,
830fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod};
840fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
8502aeca985b570763342c35e99af90025bfa088d5Behdad Esfahboduint32_t g_loader_debug = 0;
8602aeca985b570763342c35e99af90025bfa088d5Behdad Esfahboduint32_t g_loader_log_msgs = 0;
870fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
880fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// thread safety lock for accessing global data structures such as "loader"
890fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// all entrypoints on the instance chain need to be locked except GPA
900fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// additionally CreateDevice and DestroyDevice needs to be locked
910fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodloader_platform_thread_mutex loader_lock;
920fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodloader_platform_thread_mutex loader_json_lock;
930fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
940fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// This table contains the loader's instance dispatch table, which contains
950fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// default functions if no instance layers are activated.  This contains
960fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod// pointers to "terminator functions".
970fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodconst VkLayerInstanceDispatchTable instance_disp = {
980fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetInstanceProcAddr = vkGetInstanceProcAddr,
990fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .DestroyInstance = loader_DestroyInstance,
1000fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
1010fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
1020fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceFormatProperties =
1030fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceFormatProperties,
1040fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceImageFormatProperties =
1050fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceImageFormatProperties,
1060fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
1070fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceQueueFamilyProperties =
1080fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceQueueFamilyProperties,
1090fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceMemoryProperties =
1100fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceMemoryProperties,
1110fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .EnumerateDeviceExtensionProperties =
1120fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_EnumerateDeviceExtensionProperties,
1130fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .EnumerateDeviceLayerProperties = loader_EnumerateDeviceLayerProperties,
1140fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceSparseImageFormatProperties =
1150fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceSparseImageFormatProperties,
1160fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .DestroySurfaceKHR = loader_DestroySurfaceKHR,
1170fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceSurfaceSupportKHR =
1180fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceSurfaceSupportKHR,
1190fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceSurfaceCapabilitiesKHR =
1200fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceSurfaceCapabilitiesKHR,
1210fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceSurfaceFormatsKHR =
1220fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceSurfaceFormatsKHR,
1230fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceSurfacePresentModesKHR =
1240fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceSurfacePresentModesKHR,
1250fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateDebugReportCallbackEXT = loader_CreateDebugReportCallback,
1260fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .DestroyDebugReportCallbackEXT = loader_DestroyDebugReportCallback,
1270fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .DebugReportMessageEXT = loader_DebugReportMessage,
1280fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#ifdef VK_USE_PLATFORM_MIR_KHR
1290fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateMirSurfaceKHR = loader_CreateMirSurfaceKHR,
1300fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceMirPresentationSupportKHR =
1310fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceMirPresentationSupportKHR,
1320fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
1330fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#ifdef VK_USE_PLATFORM_WAYLAND_KHR
1340fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateWaylandSurfaceKHR = loader_CreateWaylandSurfaceKHR,
13502aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    .GetPhysicalDeviceWaylandPresentationSupportKHR =
1360fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceWaylandPresentationSupportKHR,
1370fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
13802aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod#ifdef VK_USE_PLATFORM_WIN32_KHR
1390fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateWin32SurfaceKHR = loader_CreateWin32SurfaceKHR,
1400fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceWin32PresentationSupportKHR =
1410fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceWin32PresentationSupportKHR,
1420fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
1430fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#ifdef VK_USE_PLATFORM_XCB_KHR
1440fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateXcbSurfaceKHR = loader_CreateXcbSurfaceKHR,
1450fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceXcbPresentationSupportKHR =
1460fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceXcbPresentationSupportKHR,
1470fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
1480fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#ifdef VK_USE_PLATFORM_XLIB_KHR
1490fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateXlibSurfaceKHR = loader_CreateXlibSurfaceKHR,
1500fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .GetPhysicalDeviceXlibPresentationSupportKHR =
1510fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_GetPhysicalDeviceXlibPresentationSupportKHR,
1520fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
1530fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#ifdef VK_USE_PLATFORM_ANDROID_KHR
1540fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    .CreateAndroidSurfaceKHR = loader_CreateAndroidSurfaceKHR,
1550fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
1560fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod};
1570fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
1580fbb2dc83132a89201ad8b56c6909610437d2da0Behdad EsfahbodLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
1590fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
1600fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodvoid *loader_heap_alloc(const struct loader_instance *instance, size_t size,
16102aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod                        VkSystemAllocationScope alloc_scope) {
1620fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (instance && instance->alloc_callbacks.pfnAllocation) {
1630fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        /* TODO: What should default alignment be? 1, 4, 8, other? */
1640fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return instance->alloc_callbacks.pfnAllocation(
1650fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            instance->alloc_callbacks.pUserData, size, sizeof(int),
1660fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            alloc_scope);
1670fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
1680fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    return malloc(size);
1690fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod}
1700fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
1710fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodvoid loader_heap_free(const struct loader_instance *instance, void *pMemory) {
1720fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (pMemory == NULL)
1730fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return;
1740fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (instance && instance->alloc_callbacks.pfnFree) {
17502aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod        instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData,
17602aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod                                          pMemory);
1770fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return;
1780fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
1790fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    free(pMemory);
18002aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod}
18102aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod
1820fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodvoid *loader_heap_realloc(const struct loader_instance *instance, void *pMemory,
1830fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                          size_t orig_size, size_t size,
1840fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                          VkSystemAllocationScope alloc_scope) {
1850fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (pMemory == NULL || orig_size == 0)
1860fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return loader_heap_alloc(instance, size, alloc_scope);
1870fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (size == 0) {
1880fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        loader_heap_free(instance, pMemory);
1890fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return NULL;
1900fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
1910fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    // TODO use the callback realloc function
1920fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (instance && instance->alloc_callbacks.pfnAllocation) {
1930fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        if (size <= orig_size) {
1940fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            memset(((uint8_t *)pMemory) + size, 0, orig_size - size);
1950fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            return pMemory;
1960fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        }
1970fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        /* TODO: What should default alignment be? 1, 4, 8, other? */
1980fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        void *new_ptr = instance->alloc_callbacks.pfnAllocation(
1990fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            instance->alloc_callbacks.pUserData, size, sizeof(int),
2000fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            alloc_scope);
2010fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        if (!new_ptr)
2020fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            return NULL;
2030fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        memcpy(new_ptr, pMemory, orig_size);
2040fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData,
2050fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                          pMemory);
2060fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return new_ptr;
2070fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
2080fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    return realloc(pMemory, size);
2090fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod}
2100fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2110fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodvoid *loader_tls_heap_alloc(size_t size) {
2120fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    return loader_heap_alloc(tls_instance, size,
2130fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                             VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2140fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod}
2150fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2160fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodvoid loader_tls_heap_free(void *pMemory) {
2170fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    loader_heap_free(tls_instance, pMemory);
2180fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod}
2190fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2200fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic void loader_log(const struct loader_instance *inst, VkFlags msg_type,
2210fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                       int32_t msg_code, const char *format, ...) {
2220fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    char msg[512];
22302aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    va_list ap;
2240fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    int ret;
2250fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2260fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    va_start(ap, format);
2270fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    ret = vsnprintf(msg, sizeof(msg), format, ap);
22802aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    if ((ret >= (int)sizeof(msg)) || ret < 0) {
2290fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        msg[sizeof(msg) - 1] = '\0';
2300fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
2310fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    va_end(ap);
23202aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod
2330fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (inst) {
2340fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        util_DebugReportMessage(inst, msg_type,
2350fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
2360fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                (uint64_t)inst, 0, msg_code, "loader", msg);
2370fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
2380fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2390fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    if (!(msg_type & g_loader_log_msgs)) {
2400fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        return;
2410fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    }
2420fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2430fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#if defined(WIN32)
2440fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    OutputDebugString(msg);
2450fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    OutputDebugString("\n");
2460fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#endif
2470fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    fputs(msg, stderr);
2480fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    fputc('\n', stderr);
2490fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod}
2500fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2510fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod#if defined(WIN32)
2520fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic char *loader_get_next_path(char *path);
2530fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod/**
25402aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod* Find the list of registry files (names within a key) in key "location".
2550fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod*
2560fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
2570fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod*given in "location"
2580fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* for a list or name/values which are added to a returned list (function return
2590fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod*value).
2600fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* The DWORD values within the key must be 0 or they are skipped.
2610fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* Function return is a string with a ';'  separated list of filenames.
2620fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* Function return is NULL if no valid name/value pairs  are found in the key,
2630fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* or the key is not found.
2640fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod*
2650fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* \returns
2660fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* A string list of filenames as pointer.
2670fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod* When done using the returned string list, pointer should be freed.
2680fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod*/
2690fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbodstatic char *loader_get_registry_files(const struct loader_instance *inst,
2700fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                       char *location) {
2710fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    LONG rtn_value;
2720fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    HKEY hive, key;
2730fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    DWORD access_flags;
2740fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    char name[2048];
2750fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    char *out = NULL;
2760fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    char *loc = location;
2770fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    char *next;
27802aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    DWORD idx = 0;
2790fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    DWORD name_size = sizeof(name);
28002aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod    DWORD value;
2810fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    DWORD total_size = 4096;
2820fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    DWORD value_size = sizeof(value);
2830fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2840fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod    while (*loc) {
2850fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        next = loader_get_next_path(loc);
2860fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        hive = DEFAULT_VK_REGISTRY_HIVE;
2870fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        access_flags = KEY_QUERY_VALUE;
2880fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
2890fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        if (rtn_value != ERROR_SUCCESS) {
2900fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            // We still couldn't find the key, so give up:
2910fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            loc = next;
2920fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            continue;
2930fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        }
2940fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod
2950fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod        while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL,
2960fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                                         NULL, (LPBYTE)&value, &value_size)) ==
2970fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod               ERROR_SUCCESS) {
2980fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod            if (value_size == sizeof(value) && value == 0) {
2990fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                if (out == NULL) {
3000fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                    out = loader_heap_alloc(
3010fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                        inst, total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3020fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                    out[0] = '\0';
3030fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                } else if (strlen(out) + name_size + 1 > total_size) {
3040fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                    out = loader_heap_realloc(
3050fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                        inst, out, total_size, total_size * 2,
3060fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3070fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                    total_size *= 2;
3080fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                }
3090fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                if (out == NULL) {
31002aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod                    loader_log(
3110fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                        inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3120fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                        "Out of memory, failed loader_get_registry_files");
3130fbb2dc83132a89201ad8b56c6909610437d2da0Behdad Esfahbod                    return NULL;
314                }
315                if (strlen(out) == 0)
316                    snprintf(out, name_size + 1, "%s", name);
317                else
318                    snprintf(out + strlen(out), name_size + 2, "%c%s",
319                             PATH_SEPERATOR, name);
320            }
321            name_size = 2048;
322        }
323        loc = next;
324    }
325
326    return out;
327}
328
329#endif // WIN32
330
331/**
332 * Combine path elements, separating each element with the platform-specific
333 * directory separator, and save the combined string to a destination buffer,
334 * not exceeding the given length. Path elements are given as variadic args,
335 * with a NULL element terminating the list.
336 *
337 * \returns the total length of the combined string, not including an ASCII
338 * NUL termination character. This length may exceed the available storage:
339 * in this case, the written string will be truncated to avoid a buffer
340 * overrun, and the return value will greater than or equal to the storage
341 * size. A NULL argument may be provided as the destination buffer in order
342 * to determine the required string length without actually writing a string.
343 */
344
345static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
346    size_t required_len = 0;
347    va_list ap;
348    const char *component;
349
350    va_start(ap, len);
351
352    while ((component = va_arg(ap, const char *))) {
353        if (required_len > 0) {
354            // This path element is not the first non-empty element; prepend
355            // a directory separator if space allows
356            if (dest && required_len + 1 < len) {
357                snprintf(dest + required_len, len - required_len, "%c",
358                         DIRECTORY_SYMBOL);
359            }
360            required_len++;
361        }
362
363        if (dest && required_len < len) {
364            strncpy(dest + required_len, component, len - required_len);
365        }
366        required_len += strlen(component);
367    }
368
369    va_end(ap);
370
371    // strncpy(3) won't add a NUL terminating byte in the event of truncation.
372    if (dest && required_len >= len) {
373        dest[len - 1] = '\0';
374    }
375
376    return required_len;
377}
378
379/**
380 * Given string of three part form "maj.min.pat" convert to a vulkan version
381 * number.
382 */
383static uint32_t loader_make_version(const char *vers_str) {
384    uint32_t vers = 0, major = 0, minor = 0, patch = 0;
385    char *minor_str = NULL;
386    char *patch_str = NULL;
387    char *cstr;
388    char *str;
389
390    if (!vers_str)
391        return vers;
392    cstr = loader_stack_alloc(strlen(vers_str) + 1);
393    strcpy(cstr, vers_str);
394    while ((str = strchr(cstr, '.')) != NULL) {
395        if (minor_str == NULL) {
396            minor_str = str + 1;
397            *str = '\0';
398            major = atoi(cstr);
399        } else if (patch_str == NULL) {
400            patch_str = str + 1;
401            *str = '\0';
402            minor = atoi(minor_str);
403        } else {
404            return vers;
405        }
406        cstr = str + 1;
407    }
408    patch = atoi(patch_str);
409
410    return VK_MAKE_VERSION(major, minor, patch);
411}
412
413bool compare_vk_extension_properties(const VkExtensionProperties *op1,
414                                     const VkExtensionProperties *op2) {
415    return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
416}
417
418/**
419 * Search the given ext_array for an extension
420 * matching the given vk_ext_prop
421 */
422bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop,
423                                     const uint32_t count,
424                                     const VkExtensionProperties *ext_array) {
425    for (uint32_t i = 0; i < count; i++) {
426        if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
427            return true;
428    }
429    return false;
430}
431
432/**
433 * Search the given ext_list for an extension
434 * matching the given vk_ext_prop
435 */
436bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop,
437                               const struct loader_extension_list *ext_list) {
438    for (uint32_t i = 0; i < ext_list->count; i++) {
439        if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop))
440            return true;
441    }
442    return false;
443}
444
445static inline bool loader_is_layer_type_device(const enum layer_type type) {
446    if ((type & VK_LAYER_TYPE_DEVICE_EXPLICIT) ||
447        (type & VK_LAYER_TYPE_DEVICE_IMPLICIT))
448        return true;
449    return false;
450}
451
452/*
453 * Search the given layer list for a layer matching the given layer name
454 */
455static struct loader_layer_properties *
456loader_get_layer_property(const char *name,
457                          const struct loader_layer_list *layer_list) {
458    for (uint32_t i = 0; i < layer_list->count; i++) {
459        const VkLayerProperties *item = &layer_list->list[i].info;
460        if (strcmp(name, item->layerName) == 0)
461            return &layer_list->list[i];
462    }
463    return NULL;
464}
465
466/**
467 * Get the next unused layer property in the list. Init the property to zero.
468 */
469static struct loader_layer_properties *
470loader_get_next_layer_property(const struct loader_instance *inst,
471                               struct loader_layer_list *layer_list) {
472    if (layer_list->capacity == 0) {
473        layer_list->list =
474            loader_heap_alloc(inst, sizeof(struct loader_layer_properties) * 64,
475                              VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
476        if (layer_list->list == NULL) {
477            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
478                       "Out of memory can't add any layer properties to list");
479            return NULL;
480        }
481        memset(layer_list->list, 0,
482               sizeof(struct loader_layer_properties) * 64);
483        layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
484    }
485
486    // ensure enough room to add an entry
487    if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) >
488        layer_list->capacity) {
489        layer_list->list = loader_heap_realloc(
490            inst, layer_list->list, layer_list->capacity,
491            layer_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
492        if (layer_list->list == NULL) {
493            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
494                       "realloc failed for layer list");
495        }
496        layer_list->capacity *= 2;
497    }
498
499    layer_list->count++;
500    return &(layer_list->list[layer_list->count - 1]);
501}
502
503/**
504 * Remove all layer properties entrys from the list
505 */
506void loader_delete_layer_properties(const struct loader_instance *inst,
507                                    struct loader_layer_list *layer_list) {
508    uint32_t i, j;
509    struct loader_device_extension_list *dev_ext_list;
510    if (!layer_list)
511        return;
512
513    for (i = 0; i < layer_list->count; i++) {
514        loader_destroy_generic_list(
515            inst, (struct loader_generic_list *)&layer_list->list[i]
516                      .instance_extension_list);
517        dev_ext_list = &layer_list->list[i].device_extension_list;
518        if (dev_ext_list->capacity > 0 &&
519            dev_ext_list->list->entrypoint_count > 0) {
520            for (j = 0; j < dev_ext_list->list->entrypoint_count; j++) {
521                loader_heap_free(inst, dev_ext_list->list->entrypoints[j]);
522            }
523            loader_heap_free(inst, dev_ext_list->list->entrypoints);
524        }
525        loader_destroy_generic_list(inst,
526                                    (struct loader_generic_list *)dev_ext_list);
527    }
528    layer_list->count = 0;
529
530    if (layer_list->capacity > 0) {
531        layer_list->capacity = 0;
532        loader_heap_free(inst, layer_list->list);
533    }
534}
535
536static void loader_add_instance_extensions(
537    const struct loader_instance *inst,
538    const PFN_vkEnumerateInstanceExtensionProperties fp_get_props,
539    const char *lib_name, struct loader_extension_list *ext_list) {
540    uint32_t i, count = 0;
541    VkExtensionProperties *ext_props;
542    VkResult res;
543
544    if (!fp_get_props) {
545        /* No EnumerateInstanceExtensionProperties defined */
546        return;
547    }
548
549    res = fp_get_props(NULL, &count, NULL);
550    if (res != VK_SUCCESS) {
551        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
552                   "Error getting Instance extension count from %s", lib_name);
553        return;
554    }
555
556    if (count == 0) {
557        /* No ExtensionProperties to report */
558        return;
559    }
560
561    ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
562
563    res = fp_get_props(NULL, &count, ext_props);
564    if (res != VK_SUCCESS) {
565        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
566                   "Error getting Instance extensions from %s", lib_name);
567        return;
568    }
569
570    for (i = 0; i < count; i++) {
571        char spec_version[64];
572
573        snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
574                 VK_MAJOR(ext_props[i].specVersion),
575                 VK_MINOR(ext_props[i].specVersion),
576                 VK_PATCH(ext_props[i].specVersion));
577        loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
578                   "Instance Extension: %s (%s) version %s",
579                   ext_props[i].extensionName, lib_name, spec_version);
580        loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
581    }
582
583    return;
584}
585
586/*
587 * Initialize ext_list with the physical device extensions.
588 * The extension properties are passed as inputs in count and ext_props.
589 */
590static VkResult
591loader_init_device_extensions(const struct loader_instance *inst,
592                              struct loader_physical_device *phys_dev,
593                              uint32_t count, VkExtensionProperties *ext_props,
594                              struct loader_extension_list *ext_list) {
595    VkResult res;
596    uint32_t i;
597
598    if (!loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
599                                  sizeof(VkExtensionProperties))) {
600        return VK_ERROR_OUT_OF_HOST_MEMORY;
601    }
602
603    for (i = 0; i < count; i++) {
604        char spec_version[64];
605
606        snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
607                 VK_MAJOR(ext_props[i].specVersion),
608                 VK_MINOR(ext_props[i].specVersion),
609                 VK_PATCH(ext_props[i].specVersion));
610        loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
611                   "Device Extension: %s (%s) version %s",
612                   ext_props[i].extensionName,
613                   phys_dev->this_icd->this_icd_lib->lib_name, spec_version);
614        res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
615        if (res != VK_SUCCESS)
616            return res;
617    }
618
619    return VK_SUCCESS;
620}
621
622static VkResult loader_add_device_extensions(
623    const struct loader_instance *inst, struct loader_icd *icd,
624    VkPhysicalDevice physical_device, const char *lib_name,
625    struct loader_extension_list *ext_list) {
626    uint32_t i, count;
627    VkResult res;
628    VkExtensionProperties *ext_props;
629
630    res = icd->EnumerateDeviceExtensionProperties(physical_device, NULL, &count,
631                                                  NULL);
632    if (res == VK_SUCCESS && count > 0) {
633        ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
634        if (!ext_props)
635            return VK_ERROR_OUT_OF_HOST_MEMORY;
636        res = icd->EnumerateDeviceExtensionProperties(physical_device, NULL,
637                                                      &count, ext_props);
638        if (res != VK_SUCCESS)
639            return res;
640        for (i = 0; i < count; i++) {
641            char spec_version[64];
642
643            snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
644                     VK_MAJOR(ext_props[i].specVersion),
645                     VK_MINOR(ext_props[i].specVersion),
646                     VK_PATCH(ext_props[i].specVersion));
647            loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
648                       "Device Extension: %s (%s) version %s",
649                       ext_props[i].extensionName, lib_name, spec_version);
650            res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
651            if (res != VK_SUCCESS)
652                return res;
653        }
654    } else {
655        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
656                   "Error getting physical device extension info count from "
657                   "library %s",
658                   lib_name);
659        return res;
660    }
661
662    return VK_SUCCESS;
663}
664
665static bool loader_init_generic_list(const struct loader_instance *inst,
666                                     struct loader_generic_list *list_info,
667                                     size_t element_size) {
668    list_info->capacity = 32 * element_size;
669    list_info->list = loader_heap_alloc(inst, list_info->capacity,
670                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
671    if (list_info->list == NULL) {
672        return false;
673    }
674    memset(list_info->list, 0, list_info->capacity);
675    list_info->count = 0;
676    return true;
677}
678
679void loader_destroy_generic_list(const struct loader_instance *inst,
680                                 struct loader_generic_list *list) {
681    loader_heap_free(inst, list->list);
682    list->count = 0;
683    list->capacity = 0;
684}
685
686/*
687 * Append non-duplicate extension properties defined in props
688 * to the given ext_list.
689 * Return
690 *  Vk_SUCCESS on success
691 */
692VkResult loader_add_to_ext_list(const struct loader_instance *inst,
693                                struct loader_extension_list *ext_list,
694                                uint32_t prop_list_count,
695                                const VkExtensionProperties *props) {
696    uint32_t i;
697    const VkExtensionProperties *cur_ext;
698
699    if (ext_list->list == NULL || ext_list->capacity == 0) {
700        loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
701                                 sizeof(VkExtensionProperties));
702    }
703
704    if (ext_list->list == NULL)
705        return VK_ERROR_OUT_OF_HOST_MEMORY;
706
707    for (i = 0; i < prop_list_count; i++) {
708        cur_ext = &props[i];
709
710        // look for duplicates
711        if (has_vk_extension_property(cur_ext, ext_list)) {
712            continue;
713        }
714
715        // add to list at end
716        // check for enough capacity
717        if (ext_list->count * sizeof(VkExtensionProperties) >=
718            ext_list->capacity) {
719
720            ext_list->list = loader_heap_realloc(
721                inst, ext_list->list, ext_list->capacity,
722                ext_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
723
724            if (ext_list->list == NULL)
725                return VK_ERROR_OUT_OF_HOST_MEMORY;
726
727            // double capacity
728            ext_list->capacity *= 2;
729        }
730
731        memcpy(&ext_list->list[ext_list->count], cur_ext,
732               sizeof(VkExtensionProperties));
733        ext_list->count++;
734    }
735    return VK_SUCCESS;
736}
737
738/*
739 * Append one extension property defined in props with entrypoints
740 * defined in entrys to the given ext_list.
741 * Return
742 *  Vk_SUCCESS on success
743 */
744VkResult
745loader_add_to_dev_ext_list(const struct loader_instance *inst,
746                           struct loader_device_extension_list *ext_list,
747                           const VkExtensionProperties *props,
748                           uint32_t entry_count, char **entrys) {
749    uint32_t idx;
750    if (ext_list->list == NULL || ext_list->capacity == 0) {
751        loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
752                                 sizeof(struct loader_dev_ext_props));
753    }
754
755    if (ext_list->list == NULL)
756        return VK_ERROR_OUT_OF_HOST_MEMORY;
757
758    idx = ext_list->count;
759    // add to list at end
760    // check for enough capacity
761    if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
762
763        ext_list->list = loader_heap_realloc(
764            inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
765            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
766
767        if (ext_list->list == NULL)
768            return VK_ERROR_OUT_OF_HOST_MEMORY;
769
770        // double capacity
771        ext_list->capacity *= 2;
772    }
773
774    memcpy(&ext_list->list[idx].props, props,
775           sizeof(struct loader_dev_ext_props));
776    ext_list->list[idx].entrypoint_count = entry_count;
777    ext_list->list[idx].entrypoints =
778        loader_heap_alloc(inst, sizeof(char *) * entry_count,
779                          VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
780    if (ext_list->list[idx].entrypoints == NULL)
781        return VK_ERROR_OUT_OF_HOST_MEMORY;
782    for (uint32_t i = 0; i < entry_count; i++) {
783        ext_list->list[idx].entrypoints[i] = loader_heap_alloc(
784            inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
785        if (ext_list->list[idx].entrypoints[i] == NULL)
786            return VK_ERROR_OUT_OF_HOST_MEMORY;
787        strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
788    }
789    ext_list->count++;
790
791    return VK_SUCCESS;
792}
793
794/**
795 * Search the given search_list for any layers in the props list.
796 * Add these to the output layer_list.  Don't add duplicates to the output
797 * layer_list.
798 */
799static VkResult
800loader_add_layer_names_to_list(const struct loader_instance *inst,
801                               struct loader_layer_list *output_list,
802                               uint32_t name_count, const char *const *names,
803                               const struct loader_layer_list *search_list) {
804    struct loader_layer_properties *layer_prop;
805    VkResult err = VK_SUCCESS;
806
807    for (uint32_t i = 0; i < name_count; i++) {
808        const char *search_target = names[i];
809        layer_prop = loader_get_layer_property(search_target, search_list);
810        if (!layer_prop) {
811            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
812                       "Unable to find layer %s", search_target);
813            err = VK_ERROR_LAYER_NOT_PRESENT;
814            continue;
815        }
816
817        loader_add_to_layer_list(inst, output_list, 1, layer_prop);
818    }
819
820    return err;
821}
822
823/*
824 * Manage lists of VkLayerProperties
825 */
826static bool loader_init_layer_list(const struct loader_instance *inst,
827                                   struct loader_layer_list *list) {
828    list->capacity = 32 * sizeof(struct loader_layer_properties);
829    list->list = loader_heap_alloc(inst, list->capacity,
830                                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
831    if (list->list == NULL) {
832        return false;
833    }
834    memset(list->list, 0, list->capacity);
835    list->count = 0;
836    return true;
837}
838
839void loader_destroy_layer_list(const struct loader_instance *inst,
840                               struct loader_layer_list *layer_list) {
841    loader_heap_free(inst, layer_list->list);
842    layer_list->count = 0;
843    layer_list->capacity = 0;
844}
845
846/*
847 * Manage list of layer libraries (loader_lib_info)
848 */
849static bool
850loader_init_layer_library_list(const struct loader_instance *inst,
851                               struct loader_layer_library_list *list) {
852    list->capacity = 32 * sizeof(struct loader_lib_info);
853    list->list = loader_heap_alloc(inst, list->capacity,
854                                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
855    if (list->list == NULL) {
856        return false;
857    }
858    memset(list->list, 0, list->capacity);
859    list->count = 0;
860    return true;
861}
862
863void loader_destroy_layer_library_list(const struct loader_instance *inst,
864                                       struct loader_layer_library_list *list) {
865    for (uint32_t i = 0; i < list->count; i++) {
866        loader_heap_free(inst, list->list[i].lib_name);
867    }
868    loader_heap_free(inst, list->list);
869    list->count = 0;
870    list->capacity = 0;
871}
872
873void loader_add_to_layer_library_list(const struct loader_instance *inst,
874                                      struct loader_layer_library_list *list,
875                                      uint32_t item_count,
876                                      const struct loader_lib_info *new_items) {
877    uint32_t i;
878    struct loader_lib_info *item;
879
880    if (list->list == NULL || list->capacity == 0) {
881        loader_init_layer_library_list(inst, list);
882    }
883
884    if (list->list == NULL)
885        return;
886
887    for (i = 0; i < item_count; i++) {
888        item = (struct loader_lib_info *)&new_items[i];
889
890        // look for duplicates
891        for (uint32_t j = 0; j < list->count; j++) {
892            if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
893                continue;
894            }
895        }
896
897        // add to list at end
898        // check for enough capacity
899        if (list->count * sizeof(struct loader_lib_info) >= list->capacity) {
900
901            list->list = loader_heap_realloc(
902                inst, list->list, list->capacity, list->capacity * 2,
903                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
904            // double capacity
905            list->capacity *= 2;
906        }
907
908        memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
909        list->count++;
910    }
911}
912
913/*
914 * Search the given layer list for a list
915 * matching the given VkLayerProperties
916 */
917bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop,
918                           const struct loader_layer_list *list) {
919    for (uint32_t i = 0; i < list->count; i++) {
920        if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
921            return true;
922    }
923    return false;
924}
925
926/*
927 * Search the given layer list for a layer
928 * matching the given name
929 */
930bool has_layer_name(const char *name, const struct loader_layer_list *list) {
931    for (uint32_t i = 0; i < list->count; i++) {
932        if (strcmp(name, list->list[i].info.layerName) == 0)
933            return true;
934    }
935    return false;
936}
937
938/*
939 * Append non-duplicate layer properties defined in prop_list
940 * to the given layer_info list
941 */
942void loader_add_to_layer_list(const struct loader_instance *inst,
943                              struct loader_layer_list *list,
944                              uint32_t prop_list_count,
945                              const struct loader_layer_properties *props) {
946    uint32_t i;
947    struct loader_layer_properties *layer;
948
949    if (list->list == NULL || list->capacity == 0) {
950        loader_init_layer_list(inst, list);
951    }
952
953    if (list->list == NULL)
954        return;
955
956    for (i = 0; i < prop_list_count; i++) {
957        layer = (struct loader_layer_properties *)&props[i];
958
959        // look for duplicates
960        if (has_vk_layer_property(&layer->info, list)) {
961            continue;
962        }
963
964        // add to list at end
965        // check for enough capacity
966        if (list->count * sizeof(struct loader_layer_properties) >=
967            list->capacity) {
968
969            list->list = loader_heap_realloc(
970                inst, list->list, list->capacity, list->capacity * 2,
971                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
972            // double capacity
973            list->capacity *= 2;
974        }
975
976        memcpy(&list->list[list->count], layer,
977               sizeof(struct loader_layer_properties));
978        list->count++;
979    }
980}
981
982/**
983 * Search the search_list for any layer with a name
984 * that matches the given name and a type that matches the given type
985 * Add all matching layers to the found_list
986 * Do not add if found loader_layer_properties is already
987 * on the found_list.
988 */
989static void
990loader_find_layer_name_add_list(const struct loader_instance *inst,
991                                const char *name, const enum layer_type type,
992                                const struct loader_layer_list *search_list,
993                                struct loader_layer_list *found_list) {
994    bool found = false;
995    for (uint32_t i = 0; i < search_list->count; i++) {
996        struct loader_layer_properties *layer_prop = &search_list->list[i];
997        if (0 == strcmp(layer_prop->info.layerName, name) &&
998            (layer_prop->type & type)) {
999            /* Found a layer with the same name, add to found_list */
1000            loader_add_to_layer_list(inst, found_list, 1, layer_prop);
1001            found = true;
1002        }
1003    }
1004    if (!found) {
1005        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1006                   "Warning, couldn't find layer name %s to activate", name);
1007    }
1008}
1009
1010static VkExtensionProperties *
1011get_extension_property(const char *name,
1012                       const struct loader_extension_list *list) {
1013    for (uint32_t i = 0; i < list->count; i++) {
1014        if (strcmp(name, list->list[i].extensionName) == 0)
1015            return &list->list[i];
1016    }
1017    return NULL;
1018}
1019
1020static VkExtensionProperties *
1021get_dev_extension_property(const char *name,
1022                           const struct loader_device_extension_list *list) {
1023    for (uint32_t i = 0; i < list->count; i++) {
1024        if (strcmp(name, list->list[i].props.extensionName) == 0)
1025            return &list->list[i].props;
1026    }
1027    return NULL;
1028}
1029
1030/*
1031 * This function will return the pNext pointer of any
1032 * CreateInfo extensions that are not loader extensions.
1033 * This is used to skip past the loader extensions prepended
1034 * to the list during CreateInstance and CreateDevice.
1035 */
1036void *loader_strip_create_extensions(const void *pNext) {
1037    VkLayerInstanceCreateInfo *create_info = (VkLayerInstanceCreateInfo *)pNext;
1038
1039    while (
1040        create_info &&
1041        (create_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
1042         create_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)) {
1043        create_info = (VkLayerInstanceCreateInfo *)create_info->pNext;
1044    }
1045
1046    return create_info;
1047}
1048
1049/*
1050 * For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1051 * the extension must provide two entry points for the loader to use:
1052 * - "trampoline" entry point - this is the address returned by GetProcAddr
1053 * and will always do what's necessary to support a global call.
1054 * - "terminator" function - this function will be put at the end of the
1055 * instance chain and will contain the necessary logic to call / process
1056 * the extension for the appropriate ICDs that are available.
1057 * There is no generic mechanism for including these functions, the references
1058 * must be placed into the appropriate loader entry points.
1059 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for
1060 * GetProcAddr requests
1061 * loader_coalesce_extensions(void) - add extension records to the list of
1062 * global
1063 * extension available to the app.
1064 * instance_disp - add function pointer for terminator function to this array.
1065 * The extension itself should be in a separate file that will be
1066 * linked directly with the loader.
1067 */
1068
1069void loader_get_icd_loader_instance_extensions(
1070    const struct loader_instance *inst, struct loader_icd_libs *icd_libs,
1071    struct loader_extension_list *inst_exts) {
1072    struct loader_extension_list icd_exts;
1073    loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
1074               "Build ICD instance extension list");
1075    // traverse scanned icd list adding non-duplicate extensions to the list
1076    for (uint32_t i = 0; i < icd_libs->count; i++) {
1077        loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts,
1078                                 sizeof(VkExtensionProperties));
1079        loader_add_instance_extensions(
1080            inst, icd_libs->list[i].EnumerateInstanceExtensionProperties,
1081            icd_libs->list[i].lib_name, &icd_exts);
1082        loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list);
1083        loader_destroy_generic_list(inst,
1084                                    (struct loader_generic_list *)&icd_exts);
1085    };
1086
1087    // Traverse loader's extensions, adding non-duplicate extensions to the list
1088    wsi_add_instance_extensions(inst, inst_exts);
1089    debug_report_add_instance_extensions(inst, inst_exts);
1090}
1091
1092struct loader_physical_device *
1093loader_get_physical_device(const VkPhysicalDevice physdev) {
1094    uint32_t i;
1095    for (struct loader_instance *inst = loader.instances; inst;
1096         inst = inst->next) {
1097        for (i = 0; i < inst->total_gpu_count; i++) {
1098            // TODO this aliases physDevices within instances, need for this
1099            // function to go away
1100            if (inst->phys_devs[i].disp ==
1101                loader_get_instance_dispatch(physdev)) {
1102                return &inst->phys_devs[i];
1103            }
1104        }
1105    }
1106    return NULL;
1107}
1108
1109struct loader_icd *loader_get_icd_and_device(const VkDevice device,
1110                                             struct loader_device **found_dev) {
1111    *found_dev = NULL;
1112    for (struct loader_instance *inst = loader.instances; inst;
1113         inst = inst->next) {
1114        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1115            for (struct loader_device *dev = icd->logical_device_list; dev;
1116                 dev = dev->next)
1117                /* Value comparison of device prevents object wrapping by layers
1118                 */
1119                if (loader_get_dispatch(dev->device) ==
1120                    loader_get_dispatch(device)) {
1121                    *found_dev = dev;
1122                    return icd;
1123                }
1124        }
1125    }
1126    return NULL;
1127}
1128
1129static void loader_destroy_logical_device(const struct loader_instance *inst,
1130                                          struct loader_device *dev) {
1131    loader_heap_free(inst, dev->app_extension_props);
1132    loader_destroy_layer_list(inst, &dev->activated_layer_list);
1133    loader_heap_free(inst, dev);
1134}
1135
1136static struct loader_device *
1137loader_add_logical_device(const struct loader_instance *inst,
1138                          struct loader_device **device_list) {
1139    struct loader_device *new_dev;
1140
1141    new_dev = loader_heap_alloc(inst, sizeof(struct loader_device),
1142                                VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1143    if (!new_dev) {
1144        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1145                   "Failed to alloc struct loader-device");
1146        return NULL;
1147    }
1148
1149    memset(new_dev, 0, sizeof(struct loader_device));
1150
1151    new_dev->next = *device_list;
1152    *device_list = new_dev;
1153    return new_dev;
1154}
1155
1156void loader_remove_logical_device(const struct loader_instance *inst,
1157                                  struct loader_icd *icd,
1158                                  struct loader_device *found_dev) {
1159    struct loader_device *dev, *prev_dev;
1160
1161    if (!icd || !found_dev)
1162        return;
1163
1164    prev_dev = NULL;
1165    dev = icd->logical_device_list;
1166    while (dev && dev != found_dev) {
1167        prev_dev = dev;
1168        dev = dev->next;
1169    }
1170
1171    if (prev_dev)
1172        prev_dev->next = found_dev->next;
1173    else
1174        icd->logical_device_list = found_dev->next;
1175    loader_destroy_logical_device(inst, found_dev);
1176}
1177
1178static void loader_icd_destroy(struct loader_instance *ptr_inst,
1179                               struct loader_icd *icd) {
1180    ptr_inst->total_icd_count--;
1181    for (struct loader_device *dev = icd->logical_device_list; dev;) {
1182        struct loader_device *next_dev = dev->next;
1183        loader_destroy_logical_device(ptr_inst, dev);
1184        dev = next_dev;
1185    }
1186
1187    loader_heap_free(ptr_inst, icd);
1188}
1189
1190static struct loader_icd *
1191loader_icd_create(const struct loader_instance *inst) {
1192    struct loader_icd *icd;
1193
1194    icd = loader_heap_alloc(inst, sizeof(*icd),
1195                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1196    if (!icd)
1197        return NULL;
1198
1199    memset(icd, 0, sizeof(*icd));
1200
1201    return icd;
1202}
1203
1204static struct loader_icd *
1205loader_icd_add(struct loader_instance *ptr_inst,
1206               const struct loader_scanned_icds *icd_lib) {
1207    struct loader_icd *icd;
1208
1209    icd = loader_icd_create(ptr_inst);
1210    if (!icd)
1211        return NULL;
1212
1213    icd->this_icd_lib = icd_lib;
1214    icd->this_instance = ptr_inst;
1215
1216    /* prepend to the list */
1217    icd->next = ptr_inst->icds;
1218    ptr_inst->icds = icd;
1219    ptr_inst->total_icd_count++;
1220
1221    return icd;
1222}
1223
1224void loader_scanned_icd_clear(const struct loader_instance *inst,
1225                              struct loader_icd_libs *icd_libs) {
1226    if (icd_libs->capacity == 0)
1227        return;
1228    for (uint32_t i = 0; i < icd_libs->count; i++) {
1229        loader_platform_close_library(icd_libs->list[i].handle);
1230        loader_heap_free(inst, icd_libs->list[i].lib_name);
1231    }
1232    loader_heap_free(inst, icd_libs->list);
1233    icd_libs->capacity = 0;
1234    icd_libs->count = 0;
1235    icd_libs->list = NULL;
1236}
1237
1238static void loader_scanned_icd_init(const struct loader_instance *inst,
1239                                    struct loader_icd_libs *icd_libs) {
1240    loader_scanned_icd_clear(inst, icd_libs);
1241    icd_libs->capacity = 8 * sizeof(struct loader_scanned_icds);
1242    icd_libs->list = loader_heap_alloc(inst, icd_libs->capacity,
1243                                       VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1244}
1245
1246static void loader_scanned_icd_add(const struct loader_instance *inst,
1247                                   struct loader_icd_libs *icd_libs,
1248                                   const char *filename, uint32_t api_version) {
1249    loader_platform_dl_handle handle;
1250    PFN_vkCreateInstance fp_create_inst;
1251    PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
1252    PFN_vkGetInstanceProcAddr fp_get_proc_addr;
1253    struct loader_scanned_icds *new_node;
1254
1255    /* TODO implement ref counting of libraries, for now this function leaves
1256       libraries open and the scanned_icd_clear closes them */
1257    // Used to call: dlopen(filename, RTLD_LAZY);
1258    handle = loader_platform_open_library(filename);
1259    if (!handle) {
1260        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1261                   loader_platform_open_library_error(filename));
1262        return;
1263    }
1264
1265    fp_get_proc_addr =
1266        loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
1267    if (!fp_get_proc_addr) {
1268        // Use deprecated interface
1269        fp_get_proc_addr =
1270            loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
1271        if (!fp_get_proc_addr) {
1272            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1273                       loader_platform_get_proc_address_error(
1274                           "vk_icdGetInstanceProcAddr"));
1275            return;
1276        } else {
1277            loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1278                       "Using deprecated ICD interface of "
1279                       "vkGetInstanceProcAddr instead of "
1280                       "vk_icdGetInstanceProcAddr");
1281        }
1282        fp_create_inst =
1283            loader_platform_get_proc_address(handle, "vkCreateInstance");
1284        if (!fp_create_inst) {
1285            loader_log(
1286                inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1287                "Couldn't get vkCreateInstance via dlsym/loadlibrary from ICD");
1288            return;
1289        }
1290        fp_get_inst_ext_props = loader_platform_get_proc_address(
1291            handle, "vkEnumerateInstanceExtensionProperties");
1292        if (!fp_get_inst_ext_props) {
1293            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1294                       "Couldn't get vkEnumerateInstanceExtensionProperties "
1295                       "via dlsym/loadlibrary from ICD");
1296            return;
1297        }
1298    } else {
1299        // Use newer interface
1300        fp_create_inst =
1301            (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
1302        if (!fp_create_inst) {
1303            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1304                       "Couldn't get vkCreateInstance via "
1305                       "vk_icdGetInstanceProcAddr from ICD");
1306            return;
1307        }
1308        fp_get_inst_ext_props =
1309            (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(
1310                NULL, "vkEnumerateInstanceExtensionProperties");
1311        if (!fp_get_inst_ext_props) {
1312            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1313                       "Couldn't get vkEnumerateInstanceExtensionProperties "
1314                       "via vk_icdGetInstanceProcAddr from ICD");
1315            return;
1316        }
1317    }
1318
1319    // check for enough capacity
1320    if ((icd_libs->count * sizeof(struct loader_scanned_icds)) >=
1321        icd_libs->capacity) {
1322
1323        icd_libs->list = loader_heap_realloc(
1324            inst, icd_libs->list, icd_libs->capacity, icd_libs->capacity * 2,
1325            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1326        // double capacity
1327        icd_libs->capacity *= 2;
1328    }
1329    new_node = &(icd_libs->list[icd_libs->count]);
1330
1331    new_node->handle = handle;
1332    new_node->api_version = api_version;
1333    new_node->GetInstanceProcAddr = fp_get_proc_addr;
1334    new_node->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
1335    new_node->CreateInstance = fp_create_inst;
1336
1337    new_node->lib_name = (char *)loader_heap_alloc(
1338        inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1339    if (!new_node->lib_name) {
1340        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1341                   "Out of memory can't add icd");
1342        return;
1343    }
1344    strcpy(new_node->lib_name, filename);
1345    icd_libs->count++;
1346}
1347
1348static bool loader_icd_init_entrys(struct loader_icd *icd, VkInstance inst,
1349                                   const PFN_vkGetInstanceProcAddr fp_gipa) {
1350/* initialize entrypoint function pointers */
1351
1352#define LOOKUP_GIPA(func, required)                                            \
1353    do {                                                                       \
1354        icd->func = (PFN_vk##func)fp_gipa(inst, "vk" #func);                   \
1355        if (!icd->func && required) {                                          \
1356            loader_log((struct loader_instance *)inst,                         \
1357                       VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,                        \
1358                       loader_platform_get_proc_address_error("vk" #func));    \
1359            return false;                                                      \
1360        }                                                                      \
1361    } while (0)
1362
1363    LOOKUP_GIPA(GetDeviceProcAddr, true);
1364    LOOKUP_GIPA(DestroyInstance, true);
1365    LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1366    LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1367    LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
1368    LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
1369    LOOKUP_GIPA(CreateDevice, true);
1370    LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1371    LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
1372    LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
1373    LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
1374    LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
1375    LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
1376    LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
1377    LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
1378    LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
1379    LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
1380    LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
1381#ifdef VK_USE_PLATFORM_WIN32_KHR
1382    LOOKUP_GIPA(GetPhysicalDeviceWin32PresentationSupportKHR, false);
1383#endif
1384#ifdef VK_USE_PLATFORM_XCB_KHR
1385    LOOKUP_GIPA(GetPhysicalDeviceXcbPresentationSupportKHR, false);
1386#endif
1387
1388#undef LOOKUP_GIPA
1389
1390    return true;
1391}
1392
1393static void loader_debug_init(void) {
1394    const char *env, *orig;
1395
1396    if (g_loader_debug > 0)
1397        return;
1398
1399    g_loader_debug = 0;
1400
1401    /* parse comma-separated debug options */
1402    orig = env = loader_getenv("VK_LOADER_DEBUG");
1403    while (env) {
1404        const char *p = strchr(env, ',');
1405        size_t len;
1406
1407        if (p)
1408            len = p - env;
1409        else
1410            len = strlen(env);
1411
1412        if (len > 0) {
1413            if (strncmp(env, "all", len) == 0) {
1414                g_loader_debug = ~0u;
1415                g_loader_log_msgs = ~0u;
1416            } else if (strncmp(env, "warn", len) == 0) {
1417                g_loader_debug |= LOADER_WARN_BIT;
1418                g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
1419            } else if (strncmp(env, "info", len) == 0) {
1420                g_loader_debug |= LOADER_INFO_BIT;
1421                g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
1422            } else if (strncmp(env, "perf", len) == 0) {
1423                g_loader_debug |= LOADER_PERF_BIT;
1424                g_loader_log_msgs |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
1425            } else if (strncmp(env, "error", len) == 0) {
1426                g_loader_debug |= LOADER_ERROR_BIT;
1427                g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
1428            } else if (strncmp(env, "debug", len) == 0) {
1429                g_loader_debug |= LOADER_DEBUG_BIT;
1430                g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
1431            }
1432        }
1433
1434        if (!p)
1435            break;
1436
1437        env = p + 1;
1438    }
1439
1440    loader_free_getenv(orig);
1441}
1442
1443void loader_initialize(void) {
1444    // initialize mutexs
1445    loader_platform_thread_create_mutex(&loader_lock);
1446    loader_platform_thread_create_mutex(&loader_json_lock);
1447
1448    // initialize logging
1449    loader_debug_init();
1450
1451    // initial cJSON to use alloc callbacks
1452    cJSON_Hooks alloc_fns = {
1453        .malloc_fn = loader_tls_heap_alloc, .free_fn = loader_tls_heap_free,
1454    };
1455    cJSON_InitHooks(&alloc_fns);
1456}
1457
1458struct loader_manifest_files {
1459    uint32_t count;
1460    char **filename_list;
1461};
1462
1463/**
1464 * Get next file or dirname given a string list or registry key path
1465 *
1466 * \returns
1467 * A pointer to first char in the next path.
1468 * The next path (or NULL) in the list is returned in next_path.
1469 * Note: input string is modified in some cases. PASS IN A COPY!
1470 */
1471static char *loader_get_next_path(char *path) {
1472    uint32_t len;
1473    char *next;
1474
1475    if (path == NULL)
1476        return NULL;
1477    next = strchr(path, PATH_SEPERATOR);
1478    if (next == NULL) {
1479        len = (uint32_t)strlen(path);
1480        next = path + len;
1481    } else {
1482        *next = '\0';
1483        next++;
1484    }
1485
1486    return next;
1487}
1488
1489/**
1490 * Given a path which is absolute or relative, expand the path if relative or
1491 * leave the path unmodified if absolute. The base path to prepend to relative
1492 * paths is given in rel_base.
1493 *
1494 * \returns
1495 * A string in out_fullpath of the full absolute path
1496 */
1497static void loader_expand_path(const char *path, const char *rel_base,
1498                               size_t out_size, char *out_fullpath) {
1499    if (loader_platform_is_path_absolute(path)) {
1500        // do not prepend a base to an absolute path
1501        rel_base = "";
1502    }
1503
1504    loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
1505}
1506
1507/**
1508 * Given a filename (file)  and a list of paths (dir), try to find an existing
1509 * file in the paths.  If filename already is a path then no
1510 * searching in the given paths.
1511 *
1512 * \returns
1513 * A string in out_fullpath of either the full path or file.
1514 */
1515static void loader_get_fullpath(const char *file, const char *dirs,
1516                                size_t out_size, char *out_fullpath) {
1517    if (!loader_platform_is_path(file) && *dirs) {
1518        char *dirs_copy, *dir, *next_dir;
1519
1520        dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1521        strcpy(dirs_copy, dirs);
1522
1523        // find if file exists after prepending paths in given list
1524        for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir));
1525             dir = next_dir) {
1526            loader_platform_combine_path(out_fullpath, out_size, dir, file,
1527                                         NULL);
1528            if (loader_platform_file_exists(out_fullpath)) {
1529                return;
1530            }
1531        }
1532    }
1533
1534    snprintf(out_fullpath, out_size, "%s", file);
1535}
1536
1537/**
1538 * Read a JSON file into a buffer.
1539 *
1540 * \returns
1541 * A pointer to a cJSON object representing the JSON parse tree.
1542 * This returned buffer should be freed by caller.
1543 */
1544static cJSON *loader_get_json(const struct loader_instance *inst,
1545                              const char *filename) {
1546    FILE *file;
1547    char *json_buf;
1548    cJSON *json;
1549    size_t len;
1550    file = fopen(filename, "rb");
1551    if (!file) {
1552        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1553                   "Couldn't open JSON file %s", filename);
1554        return NULL;
1555    }
1556    fseek(file, 0, SEEK_END);
1557    len = ftell(file);
1558    fseek(file, 0, SEEK_SET);
1559    json_buf = (char *)loader_stack_alloc(len + 1);
1560    if (json_buf == NULL) {
1561        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1562                   "Out of memory can't get JSON file");
1563        fclose(file);
1564        return NULL;
1565    }
1566    if (fread(json_buf, sizeof(char), len, file) != len) {
1567        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1568                   "fread failed can't get JSON file");
1569        fclose(file);
1570        return NULL;
1571    }
1572    fclose(file);
1573    json_buf[len] = '\0';
1574
1575    // parse text from file
1576    json = cJSON_Parse(json_buf);
1577    if (json == NULL)
1578        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1579                   "Can't parse JSON file %s", filename);
1580    return json;
1581}
1582
1583/**
1584 * Do a deep copy of the loader_layer_properties structure.
1585 */
1586static void loader_copy_layer_properties(const struct loader_instance *inst,
1587                                         struct loader_layer_properties *dst,
1588                                         struct loader_layer_properties *src) {
1589    uint32_t cnt, i;
1590    memcpy(dst, src, sizeof(*src));
1591    dst->instance_extension_list.list =
1592        loader_heap_alloc(inst, sizeof(VkExtensionProperties) *
1593                                    src->instance_extension_list.count,
1594                          VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1595    dst->instance_extension_list.capacity =
1596        sizeof(VkExtensionProperties) * src->instance_extension_list.count;
1597    memcpy(dst->instance_extension_list.list, src->instance_extension_list.list,
1598           dst->instance_extension_list.capacity);
1599    dst->device_extension_list.list =
1600        loader_heap_alloc(inst, sizeof(struct loader_dev_ext_props) *
1601                                    src->device_extension_list.count,
1602                          VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1603
1604    dst->device_extension_list.capacity =
1605        sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
1606    memcpy(dst->device_extension_list.list, src->device_extension_list.list,
1607           dst->device_extension_list.capacity);
1608    if (src->device_extension_list.count > 0 &&
1609        src->device_extension_list.list->entrypoint_count > 0) {
1610        cnt = src->device_extension_list.list->entrypoint_count;
1611        dst->device_extension_list.list->entrypoints = loader_heap_alloc(
1612            inst, sizeof(char *) * cnt, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1613        for (i = 0; i < cnt; i++) {
1614            dst->device_extension_list.list->entrypoints[i] = loader_heap_alloc(
1615                inst,
1616                strlen(src->device_extension_list.list->entrypoints[i]) + 1,
1617                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1618            strcpy(dst->device_extension_list.list->entrypoints[i],
1619                   src->device_extension_list.list->entrypoints[i]);
1620        }
1621    }
1622}
1623
1624/**
1625 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1626 * file, add entry to the layer_list.
1627 * Fill out the layer_properties in this list entry from the input cJSON object.
1628 *
1629 * \returns
1630 * void
1631 * layer_list has a new entry and initialized accordingly.
1632 * If the json input object does not have all the required fields no entry
1633 * is added to the list.
1634 */
1635static void
1636loader_add_layer_properties(const struct loader_instance *inst,
1637                            struct loader_layer_list *layer_instance_list,
1638                            struct loader_layer_list *layer_device_list,
1639                            cJSON *json, bool is_implicit, char *filename) {
1640    /* Fields in layer manifest file that are required:
1641     * (required) “file_format_version”
1642     * following are required in the "layer" object:
1643     * (required) "name"
1644     * (required) "type"
1645     * (required) “library_path”
1646     * (required) “api_version”
1647     * (required) “implementation_version”
1648     * (required) “description”
1649     * (required for implicit layers) “disable_environment”
1650     *
1651     * First get all required items and if any missing abort
1652     */
1653
1654    cJSON *item, *layer_node, *ext_item;
1655    char *temp;
1656    char *name, *type, *library_path, *api_version;
1657    char *implementation_version, *description;
1658    cJSON *disable_environment;
1659    int i, j;
1660    VkExtensionProperties ext_prop;
1661    item = cJSON_GetObjectItem(json, "file_format_version");
1662    if (item == NULL) {
1663        return;
1664    }
1665    char *file_vers = cJSON_PrintUnformatted(item);
1666    loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
1667               "Found manifest file %s, version %s", filename, file_vers);
1668    if (strcmp(file_vers, "\"1.0.0\"") != 0)
1669        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1670                   "Unexpected manifest file version (expected 1.0.0), may "
1671                   "cause errors");
1672    loader_tls_heap_free(file_vers);
1673
1674    layer_node = cJSON_GetObjectItem(json, "layer");
1675    if (layer_node == NULL) {
1676        loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1677                   "Can't find \"layer\" object in manifest JSON file, "
1678                   "skipping this file");
1679        return;
1680    }
1681
1682    // loop through all "layer" objects in the file
1683    do {
1684#define GET_JSON_OBJECT(node, var)                                             \
1685    {                                                                          \
1686        var = cJSON_GetObjectItem(node, #var);                                 \
1687        if (var == NULL) {                                                     \
1688            layer_node = layer_node->next;                                     \
1689            loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,                  \
1690                       "Didn't find required layer object %s in manifest "     \
1691                       "JSON file, skipping this layer",                       \
1692                       #var);                                                  \
1693            continue;                                                          \
1694        }                                                                      \
1695    }
1696#define GET_JSON_ITEM(node, var)                                               \
1697    {                                                                          \
1698        item = cJSON_GetObjectItem(node, #var);                                \
1699        if (item == NULL) {                                                    \
1700            layer_node = layer_node->next;                                     \
1701            loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,                  \
1702                       "Didn't find required layer value %s in manifest JSON " \
1703                       "file, skipping this layer",                            \
1704                       #var);                                                  \
1705            continue;                                                          \
1706        }                                                                      \
1707        temp = cJSON_Print(item);                                              \
1708        temp[strlen(temp) - 1] = '\0';                                         \
1709        var = loader_stack_alloc(strlen(temp) + 1);                            \
1710        strcpy(var, &temp[1]);                                                 \
1711        loader_tls_heap_free(temp);                                            \
1712    }
1713        GET_JSON_ITEM(layer_node, name)
1714        GET_JSON_ITEM(layer_node, type)
1715        GET_JSON_ITEM(layer_node, library_path)
1716        GET_JSON_ITEM(layer_node, api_version)
1717        GET_JSON_ITEM(layer_node, implementation_version)
1718        GET_JSON_ITEM(layer_node, description)
1719        if (is_implicit) {
1720            GET_JSON_OBJECT(layer_node, disable_environment)
1721        }
1722#undef GET_JSON_ITEM
1723#undef GET_JSON_OBJECT
1724
1725        // add list entry
1726        struct loader_layer_properties *props = NULL;
1727        if (!strcmp(type, "DEVICE")) {
1728            if (layer_device_list == NULL) {
1729                layer_node = layer_node->next;
1730                continue;
1731            }
1732            props = loader_get_next_layer_property(inst, layer_device_list);
1733            props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT
1734                                        : VK_LAYER_TYPE_DEVICE_EXPLICIT;
1735        }
1736        if (!strcmp(type, "INSTANCE")) {
1737            if (layer_instance_list == NULL) {
1738                layer_node = layer_node->next;
1739                continue;
1740            }
1741            props = loader_get_next_layer_property(inst, layer_instance_list);
1742            props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT
1743                                        : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
1744        }
1745        if (!strcmp(type, "GLOBAL")) {
1746            if (layer_instance_list != NULL)
1747                props =
1748                    loader_get_next_layer_property(inst, layer_instance_list);
1749            else if (layer_device_list != NULL)
1750                props = loader_get_next_layer_property(inst, layer_device_list);
1751            else {
1752                layer_node = layer_node->next;
1753                continue;
1754            }
1755            props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT
1756                                        : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1757        }
1758
1759        if (props == NULL) {
1760            layer_node = layer_node->next;
1761            continue;
1762        }
1763
1764        strncpy(props->info.layerName, name, sizeof(props->info.layerName));
1765        props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
1766
1767        char *fullpath = props->lib_name;
1768        char *rel_base;
1769        if (loader_platform_is_path(library_path)) {
1770            // a relative or absolute path
1771            char *name_copy = loader_stack_alloc(strlen(filename) + 1);
1772            strcpy(name_copy, filename);
1773            rel_base = loader_platform_dirname(name_copy);
1774            loader_expand_path(library_path, rel_base, MAX_STRING_SIZE,
1775                               fullpath);
1776        } else {
1777            // a filename which is assumed in a system directory
1778            loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH,
1779                                MAX_STRING_SIZE, fullpath);
1780        }
1781        props->info.specVersion = loader_make_version(api_version);
1782        props->info.implementationVersion = atoi(implementation_version);
1783        strncpy((char *)props->info.description, description,
1784                sizeof(props->info.description));
1785        props->info.description[sizeof(props->info.description) - 1] = '\0';
1786        if (is_implicit) {
1787            strncpy(props->disable_env_var.name,
1788                    disable_environment->child->string,
1789                    sizeof(props->disable_env_var.name));
1790            props->disable_env_var
1791                .name[sizeof(props->disable_env_var.name) - 1] = '\0';
1792            strncpy(props->disable_env_var.value,
1793                    disable_environment->child->valuestring,
1794                    sizeof(props->disable_env_var.value));
1795            props->disable_env_var
1796                .value[sizeof(props->disable_env_var.value) - 1] = '\0';
1797        }
1798
1799/**
1800 * Now get all optional items and objects and put in list:
1801 * functions
1802 * instance_extensions
1803 * device_extensions
1804 * enable_environment (implicit layers only)
1805 */
1806#define GET_JSON_OBJECT(node, var)                                             \
1807    { var = cJSON_GetObjectItem(node, #var); }
1808#define GET_JSON_ITEM(node, var)                                               \
1809    {                                                                          \
1810        item = cJSON_GetObjectItem(node, #var);                                \
1811        if (item != NULL) {                                                    \
1812            temp = cJSON_Print(item);                                          \
1813            temp[strlen(temp) - 1] = '\0';                                     \
1814            var = loader_stack_alloc(strlen(temp) + 1);                        \
1815            strcpy(var, &temp[1]);                                             \
1816            loader_tls_heap_free(temp);                                        \
1817        }                                                                      \
1818    }
1819
1820        cJSON *instance_extensions, *device_extensions, *functions,
1821            *enable_environment;
1822        cJSON *entrypoints;
1823        char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version;
1824        char **entry_array;
1825        vkGetInstanceProcAddr = NULL;
1826        vkGetDeviceProcAddr = NULL;
1827        spec_version = NULL;
1828        entrypoints = NULL;
1829        entry_array = NULL;
1830        /**
1831         * functions
1832         *     vkGetInstanceProcAddr
1833         *     vkGetDeviceProcAddr
1834         */
1835        GET_JSON_OBJECT(layer_node, functions)
1836        if (functions != NULL) {
1837            GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1838            GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1839            if (vkGetInstanceProcAddr != NULL)
1840                strncpy(props->functions.str_gipa, vkGetInstanceProcAddr,
1841                        sizeof(props->functions.str_gipa));
1842            props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] =
1843                '\0';
1844            if (vkGetDeviceProcAddr != NULL)
1845                strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr,
1846                        sizeof(props->functions.str_gdpa));
1847            props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] =
1848                '\0';
1849        }
1850        /**
1851         * instance_extensions
1852         * array of
1853         *     name
1854         *     spec_version
1855         */
1856        GET_JSON_OBJECT(layer_node, instance_extensions)
1857        if (instance_extensions != NULL) {
1858            int count = cJSON_GetArraySize(instance_extensions);
1859            for (i = 0; i < count; i++) {
1860                ext_item = cJSON_GetArrayItem(instance_extensions, i);
1861                GET_JSON_ITEM(ext_item, name)
1862                GET_JSON_ITEM(ext_item, spec_version)
1863                if (name != NULL) {
1864                    strncpy(ext_prop.extensionName, name,
1865                            sizeof(ext_prop.extensionName));
1866                    ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
1867                        '\0';
1868                }
1869                ext_prop.specVersion = atoi(spec_version);
1870                loader_add_to_ext_list(inst, &props->instance_extension_list, 1,
1871                                       &ext_prop);
1872            }
1873        }
1874        /**
1875         * device_extensions
1876         * array of
1877         *     name
1878         *     spec_version
1879         *     entrypoints
1880         */
1881        GET_JSON_OBJECT(layer_node, device_extensions)
1882        if (device_extensions != NULL) {
1883            int count = cJSON_GetArraySize(device_extensions);
1884            for (i = 0; i < count; i++) {
1885                ext_item = cJSON_GetArrayItem(device_extensions, i);
1886                GET_JSON_ITEM(ext_item, name)
1887                GET_JSON_ITEM(ext_item, spec_version)
1888                if (name != NULL) {
1889                    strncpy(ext_prop.extensionName, name,
1890                            sizeof(ext_prop.extensionName));
1891                    ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
1892                        '\0';
1893                }
1894                ext_prop.specVersion = atoi(spec_version);
1895                // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
1896                GET_JSON_OBJECT(ext_item, entrypoints)
1897                int entry_count;
1898                if (entrypoints == NULL) {
1899                    loader_add_to_dev_ext_list(inst, &props->device_extension_list,
1900                                               &ext_prop, 0, NULL);
1901                    continue;
1902                }
1903                entry_count = cJSON_GetArraySize(entrypoints);
1904                if (entry_count)
1905                    entry_array = (char **)loader_stack_alloc(sizeof(char *) *
1906                                                              entry_count);
1907                for (j = 0; j < entry_count; j++) {
1908                    ext_item = cJSON_GetArrayItem(entrypoints, j);
1909                    if (ext_item != NULL) {
1910                        temp = cJSON_Print(ext_item);
1911                        temp[strlen(temp) - 1] = '\0';
1912                        entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
1913                        strcpy(entry_array[j], &temp[1]);
1914                        loader_tls_heap_free(temp);
1915                    }
1916                }
1917                loader_add_to_dev_ext_list(inst, &props->device_extension_list,
1918                                           &ext_prop, entry_count, entry_array);
1919            }
1920        }
1921        if (is_implicit) {
1922            GET_JSON_OBJECT(layer_node, enable_environment)
1923
1924            // enable_environment is optional
1925            if (enable_environment) {
1926                strncpy(props->enable_env_var.name,
1927                        enable_environment->child->string,
1928                        sizeof(props->enable_env_var.name));
1929                props->enable_env_var
1930                    .name[sizeof(props->enable_env_var.name) - 1] = '\0';
1931                strncpy(props->enable_env_var.value,
1932                        enable_environment->child->valuestring,
1933                        sizeof(props->enable_env_var.value));
1934                props->enable_env_var
1935                    .value[sizeof(props->enable_env_var.value) - 1] = '\0';
1936            }
1937        }
1938#undef GET_JSON_ITEM
1939#undef GET_JSON_OBJECT
1940        // for global layers need to add them to both device and instance list
1941        if (!strcmp(type, "GLOBAL")) {
1942            struct loader_layer_properties *dev_props;
1943            if (layer_instance_list == NULL || layer_device_list == NULL) {
1944                layer_node = layer_node->next;
1945                continue;
1946            }
1947            dev_props = loader_get_next_layer_property(inst, layer_device_list);
1948            // copy into device layer list
1949            loader_copy_layer_properties(inst, dev_props, props);
1950        }
1951        layer_node = layer_node->next;
1952    } while (layer_node != NULL);
1953    return;
1954}
1955
1956/**
1957 * Find the Vulkan library manifest files.
1958 *
1959 * This function scans the location or env_override directories/files
1960 * for a list of JSON manifest files.  If env_override is non-NULL
1961 * and has a valid value. Then the location is ignored.  Otherwise
1962 * location is used to look for manifest files. The location
1963 * is interpreted as  Registry path on Windows and a directory path(s)
1964 * on Linux.
1965 *
1966 * \returns
1967 * A string list of manifest files to be opened in out_files param.
1968 * List has a pointer to string for each manifest filename.
1969 * When done using the list in out_files, pointers should be freed.
1970 * Location or override  string lists can be either files or directories as
1971 *follows:
1972 *            | location | override
1973 * --------------------------------
1974 * Win ICD    | files    | files
1975 * Win Layer  | files    | dirs
1976 * Linux ICD  | dirs     | files
1977 * Linux Layer| dirs     | dirs
1978 */
1979static void loader_get_manifest_files(const struct loader_instance *inst,
1980                                      const char *env_override, bool is_layer,
1981                                      const char *location,
1982                                      struct loader_manifest_files *out_files) {
1983    char *override = NULL;
1984    char *loc;
1985    char *file, *next_file, *name;
1986    size_t alloced_count = 64;
1987    char full_path[2048];
1988    DIR *sysdir = NULL;
1989    bool list_is_dirs = false;
1990    struct dirent *dent;
1991
1992    out_files->count = 0;
1993    out_files->filename_list = NULL;
1994
1995    if (env_override != NULL && (override = loader_getenv(env_override))) {
1996#if !defined(_WIN32)
1997        if (geteuid() != getuid()) {
1998            /* Don't allow setuid apps to use the env var: */
1999            loader_free_getenv(override);
2000            override = NULL;
2001        }
2002#endif
2003    }
2004
2005    if (location == NULL) {
2006        loader_log(
2007            inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2008            "Can't get manifest files with NULL location, env_override=%s",
2009            env_override);
2010        return;
2011    }
2012
2013#if defined(_WIN32)
2014    list_is_dirs = (is_layer && override != NULL) ? true : false;
2015#else
2016    list_is_dirs = (override == NULL || is_layer) ? true : false;
2017#endif
2018    // Make a copy of the input we are using so it is not modified
2019    // Also handle getting the location(s) from registry on Windows
2020    if (override == NULL) {
2021        loc = loader_stack_alloc(strlen(location) + 1);
2022        if (loc == NULL) {
2023            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2024                       "Out of memory can't get manifest files");
2025            return;
2026        }
2027        strcpy(loc, location);
2028#if defined(_WIN32)
2029        loc = loader_get_registry_files(inst, loc);
2030        if (loc == NULL) {
2031            if (!is_layer) {
2032                loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2033                           "Registry lookup failed can't get ICD manifest "
2034                           "files, do you have a Vulkan driver installed");
2035            } else {
2036                // warning only for layers
2037                loader_log(
2038                    inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2039                    "Registry lookup failed can't get layer manifest files");
2040            }
2041            return;
2042        }
2043#endif
2044    } else {
2045        loc = loader_stack_alloc(strlen(override) + 1);
2046        if (loc == NULL) {
2047            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2048                       "Out of memory can't get manifest files");
2049            return;
2050        }
2051        strcpy(loc, override);
2052        loader_free_getenv(override);
2053    }
2054
2055    // Print out the paths being searched if debugging is enabled
2056    loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2057               "Searching the following paths for manifest files: %s\n", loc);
2058
2059    file = loc;
2060    while (*file) {
2061        next_file = loader_get_next_path(file);
2062        if (list_is_dirs) {
2063            sysdir = opendir(file);
2064            name = NULL;
2065            if (sysdir) {
2066                dent = readdir(sysdir);
2067                if (dent == NULL)
2068                    break;
2069                name = &(dent->d_name[0]);
2070                loader_get_fullpath(name, file, sizeof(full_path), full_path);
2071                name = full_path;
2072            }
2073        } else {
2074#if defined(_WIN32)
2075            name = file;
2076#else
2077            // only Linux has relative paths
2078            char *dir;
2079            // make a copy of location so it isn't modified
2080            dir = loader_stack_alloc(strlen(loc) + 1);
2081            if (dir == NULL) {
2082                loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2083                           "Out of memory can't get manifest files");
2084                return;
2085            }
2086            strcpy(dir, loc);
2087
2088            loader_get_fullpath(file, dir, sizeof(full_path), full_path);
2089
2090            name = full_path;
2091#endif
2092        }
2093        while (name) {
2094            /* Look for files ending with ".json" suffix */
2095            uint32_t nlen = (uint32_t)strlen(name);
2096            const char *suf = name + nlen - 5;
2097            if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
2098                if (out_files->count == 0) {
2099                    out_files->filename_list =
2100                        loader_heap_alloc(inst, alloced_count * sizeof(char *),
2101                                          VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2102                } else if (out_files->count == alloced_count) {
2103                    out_files->filename_list =
2104                        loader_heap_realloc(inst, out_files->filename_list,
2105                                            alloced_count * sizeof(char *),
2106                                            alloced_count * sizeof(char *) * 2,
2107                                            VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2108                    alloced_count *= 2;
2109                }
2110                if (out_files->filename_list == NULL) {
2111                    loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2112                               "Out of memory can't alloc manifest file list");
2113                    return;
2114                }
2115                out_files->filename_list[out_files->count] = loader_heap_alloc(
2116                    inst, strlen(name) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2117                if (out_files->filename_list[out_files->count] == NULL) {
2118                    loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2119                               "Out of memory can't get manifest files");
2120                    return;
2121                }
2122                strcpy(out_files->filename_list[out_files->count], name);
2123                out_files->count++;
2124            } else if (!list_is_dirs) {
2125                loader_log(
2126                    inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2127                    "Skipping manifest file %s, file name must end in .json",
2128                    name);
2129            }
2130            if (list_is_dirs) {
2131                dent = readdir(sysdir);
2132                if (dent == NULL)
2133                    break;
2134                name = &(dent->d_name[0]);
2135                loader_get_fullpath(name, file, sizeof(full_path), full_path);
2136                name = full_path;
2137            } else {
2138                break;
2139            }
2140        }
2141        if (sysdir)
2142            closedir(sysdir);
2143        file = next_file;
2144    }
2145    return;
2146}
2147
2148void loader_init_icd_lib_list() {}
2149
2150void loader_destroy_icd_lib_list() {}
2151/**
2152 * Try to find the Vulkan ICD driver(s).
2153 *
2154 * This function scans the default system loader path(s) or path
2155 * specified by the \c VK_ICD_FILENAMES environment variable in
2156 * order to find loadable VK ICDs manifest files. From these
2157 * manifest files it finds the ICD libraries.
2158 *
2159 * \returns
2160 * a list of icds that were discovered
2161 */
2162void loader_icd_scan(const struct loader_instance *inst,
2163                     struct loader_icd_libs *icds) {
2164    char *file_str;
2165    struct loader_manifest_files manifest_files;
2166
2167    loader_scanned_icd_init(inst, icds);
2168    // Get a list of manifest files for ICDs
2169    loader_get_manifest_files(inst, "VK_ICD_FILENAMES", false,
2170                              DEFAULT_VK_DRIVERS_INFO, &manifest_files);
2171    if (manifest_files.count == 0)
2172        return;
2173    loader_platform_thread_lock_mutex(&loader_json_lock);
2174    for (uint32_t i = 0; i < manifest_files.count; i++) {
2175        file_str = manifest_files.filename_list[i];
2176        if (file_str == NULL)
2177            continue;
2178
2179        cJSON *json;
2180        json = loader_get_json(inst, file_str);
2181        if (!json)
2182            continue;
2183        cJSON *item, *itemICD;
2184        item = cJSON_GetObjectItem(json, "file_format_version");
2185        if (item == NULL) {
2186            loader_platform_thread_unlock_mutex(&loader_json_lock);
2187            return;
2188        }
2189        char *file_vers = cJSON_Print(item);
2190        loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2191                   "Found manifest file %s, version %s", file_str, file_vers);
2192        if (strcmp(file_vers, "\"1.0.0\"") != 0)
2193            loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2194                       "Unexpected manifest file version (expected 1.0.0), may "
2195                       "cause errors");
2196        loader_tls_heap_free(file_vers);
2197        itemICD = cJSON_GetObjectItem(json, "ICD");
2198        if (itemICD != NULL) {
2199            item = cJSON_GetObjectItem(itemICD, "library_path");
2200            if (item != NULL) {
2201                char *temp = cJSON_Print(item);
2202                if (!temp || strlen(temp) == 0) {
2203                    loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2204                               "Can't find \"library_path\" in ICD JSON file "
2205                               "%s, skipping",
2206                               file_str);
2207                    loader_tls_heap_free(temp);
2208                    loader_heap_free(inst, file_str);
2209                    cJSON_Delete(json);
2210                    continue;
2211                }
2212                // strip out extra quotes
2213                temp[strlen(temp) - 1] = '\0';
2214                char *library_path = loader_stack_alloc(strlen(temp) + 1);
2215                strcpy(library_path, &temp[1]);
2216                loader_tls_heap_free(temp);
2217                if (!library_path || strlen(library_path) == 0) {
2218                    loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2219                               "Can't find \"library_path\" in ICD JSON file "
2220                               "%s, skipping",
2221                               file_str);
2222                    loader_heap_free(inst, file_str);
2223                    cJSON_Delete(json);
2224                    continue;
2225                }
2226                char fullpath[MAX_STRING_SIZE];
2227                // Print out the paths being searched if debugging is enabled
2228                loader_log(
2229                    inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2230                    "Searching for ICD drivers named %s default dir %s\n",
2231                    library_path, DEFAULT_VK_DRIVERS_PATH);
2232                if (loader_platform_is_path(library_path)) {
2233                    // a relative or absolute path
2234                    char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
2235                    char *rel_base;
2236                    strcpy(name_copy, file_str);
2237                    rel_base = loader_platform_dirname(name_copy);
2238                    loader_expand_path(library_path, rel_base, sizeof(fullpath),
2239                                       fullpath);
2240                } else {
2241                    // a filename which is assumed in a system directory
2242                    loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH,
2243                                        sizeof(fullpath), fullpath);
2244                }
2245
2246                uint32_t vers = 0;
2247                item = cJSON_GetObjectItem(itemICD, "api_version");
2248                if (item != NULL) {
2249                    temp = cJSON_Print(item);
2250                    vers = loader_make_version(temp);
2251                    loader_tls_heap_free(temp);
2252                }
2253                loader_scanned_icd_add(inst, icds, fullpath, vers);
2254            } else
2255                loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2256                           "Can't find \"library_path\" object in ICD JSON "
2257                           "file %s, skipping",
2258                           file_str);
2259        } else
2260            loader_log(
2261                inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2262                "Can't find \"ICD\" object in ICD JSON file %s, skipping",
2263                file_str);
2264
2265        loader_heap_free(inst, file_str);
2266        cJSON_Delete(json);
2267    }
2268    loader_heap_free(inst, manifest_files.filename_list);
2269    loader_platform_thread_unlock_mutex(&loader_json_lock);
2270}
2271
2272void loader_layer_scan(const struct loader_instance *inst,
2273                       struct loader_layer_list *instance_layers,
2274                       struct loader_layer_list *device_layers) {
2275    char *file_str;
2276    struct loader_manifest_files
2277        manifest_files[2]; // [0] = explicit, [1] = implicit
2278    cJSON *json;
2279    uint32_t i;
2280    uint32_t implicit;
2281
2282    // Get a list of manifest files for layers
2283    loader_get_manifest_files(inst, LAYERS_PATH_ENV, true,
2284                              DEFAULT_VK_ELAYERS_INFO, &manifest_files[0]);
2285    // Pass NULL for environment variable override - implicit layers are not
2286    // overridden by LAYERS_PATH_ENV
2287    loader_get_manifest_files(inst, NULL, true, DEFAULT_VK_ILAYERS_INFO,
2288                              &manifest_files[1]);
2289    if (manifest_files[0].count == 0 && manifest_files[1].count == 0)
2290        return;
2291
2292#if 0 // TODO
2293    /**
2294     * We need a list of the layer libraries, not just a list of
2295     * the layer properties (a layer library could expose more than
2296     * one layer property). This list of scanned layers would be
2297     * used to check for global and physicaldevice layer properties.
2298     */
2299    if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
2300        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2301                   "Alloc for layer list failed: %s line: %d", __FILE__, __LINE__);
2302        return;
2303    }
2304#endif
2305
2306    /* cleanup any previously scanned libraries */
2307    loader_delete_layer_properties(inst, instance_layers);
2308    loader_delete_layer_properties(inst, device_layers);
2309
2310    loader_platform_thread_lock_mutex(&loader_json_lock);
2311    for (implicit = 0; implicit < 2; implicit++) {
2312        for (i = 0; i < manifest_files[implicit].count; i++) {
2313            file_str = manifest_files[implicit].filename_list[i];
2314            if (file_str == NULL)
2315                continue;
2316
2317            // parse file into JSON struct
2318            json = loader_get_json(inst, file_str);
2319            if (!json) {
2320                continue;
2321            }
2322
2323            // TODO error if device layers expose instance_extensions
2324            // TODO error if instance layers expose device extensions
2325            loader_add_layer_properties(inst, instance_layers, device_layers,
2326                                        json, (implicit == 1), file_str);
2327
2328            loader_heap_free(inst, file_str);
2329            cJSON_Delete(json);
2330        }
2331    }
2332    if (manifest_files[0].count != 0)
2333        loader_heap_free(inst, manifest_files[0].filename_list);
2334
2335    if (manifest_files[1].count != 0)
2336        loader_heap_free(inst, manifest_files[1].filename_list);
2337    loader_platform_thread_unlock_mutex(&loader_json_lock);
2338}
2339
2340static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
2341loader_gpa_instance_internal(VkInstance inst, const char *pName) {
2342    if (!strcmp(pName, "vkGetInstanceProcAddr"))
2343        return (void *)loader_gpa_instance_internal;
2344    if (!strcmp(pName, "vkCreateInstance"))
2345        return (void *)loader_CreateInstance;
2346    if (!strcmp(pName, "vkCreateDevice"))
2347        return (void *)loader_create_device_terminator;
2348
2349    // inst is not wrapped
2350    if (inst == VK_NULL_HANDLE) {
2351        return NULL;
2352    }
2353    VkLayerInstanceDispatchTable *disp_table =
2354        *(VkLayerInstanceDispatchTable **)inst;
2355    void *addr;
2356
2357    if (disp_table == NULL)
2358        return NULL;
2359
2360    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2361    if (addr) {
2362        return addr;
2363    }
2364
2365    if (disp_table->GetInstanceProcAddr == NULL) {
2366        return NULL;
2367    }
2368    return disp_table->GetInstanceProcAddr(inst, pName);
2369}
2370
2371/**
2372 * Initialize device_ext dispatch table entry as follows:
2373 * If dev == NULL find all logical devices created within this instance and
2374 *  init the entry (given by idx) in the ext dispatch table.
2375 * If dev != NULL only initialize the entry in the given dev's dispatch table.
2376 * The initialization value is gotten by calling down the device chain with
2377 * GDPA.
2378 * If GDPA returns NULL then don't initialize the dispatch table entry.
2379 */
2380static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst,
2381                                               struct loader_device *dev,
2382                                               uint32_t idx,
2383                                               const char *funcName)
2384
2385{
2386    void *gdpa_value;
2387    if (dev != NULL) {
2388        gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
2389            dev->device, funcName);
2390        if (gdpa_value != NULL)
2391            dev->loader_dispatch.ext_dispatch.DevExt[idx] =
2392                (PFN_vkDevExt)gdpa_value;
2393    } else {
2394        for (uint32_t i = 0; i < inst->total_icd_count; i++) {
2395            struct loader_icd *icd = &inst->icds[i];
2396            struct loader_device *dev = icd->logical_device_list;
2397            while (dev) {
2398                gdpa_value =
2399                    dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
2400                        dev->device, funcName);
2401                if (gdpa_value != NULL)
2402                    dev->loader_dispatch.ext_dispatch.DevExt[idx] =
2403                        (PFN_vkDevExt)gdpa_value;
2404                dev = dev->next;
2405            }
2406        }
2407    }
2408}
2409
2410/**
2411 * Find all dev extension in the hash table  and initialize the dispatch table
2412 * for dev  for each of those extension entrypoints found in hash table.
2413
2414 */
2415static void loader_init_dispatch_dev_ext(struct loader_instance *inst,
2416                                         struct loader_device *dev) {
2417    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
2418        if (inst->disp_hash[i].func_name != NULL)
2419            loader_init_dispatch_dev_ext_entry(inst, dev, i,
2420                                               inst->disp_hash[i].func_name);
2421    }
2422}
2423
2424static bool loader_check_icds_for_address(struct loader_instance *inst,
2425                                          const char *funcName) {
2426    struct loader_icd *icd;
2427    icd = inst->icds;
2428    while (icd) {
2429        if (icd->this_icd_lib->GetInstanceProcAddr(icd->instance, funcName))
2430            // this icd supports funcName
2431            return true;
2432        icd = icd->next;
2433    }
2434
2435    return false;
2436}
2437
2438static void loader_free_dev_ext_table(struct loader_instance *inst) {
2439    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
2440        loader_heap_free(inst, inst->disp_hash[i].func_name);
2441        loader_heap_free(inst, inst->disp_hash[i].list.index);
2442    }
2443    memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
2444}
2445
2446static bool loader_add_dev_ext_table(struct loader_instance *inst,
2447                                     uint32_t *ptr_idx, const char *funcName) {
2448    uint32_t i;
2449    uint32_t idx = *ptr_idx;
2450    struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
2451
2452    if (!inst->disp_hash[idx].func_name) {
2453        // no entry here at this idx, so use it
2454        assert(list->capacity == 0);
2455        inst->disp_hash[idx].func_name = (char *)loader_heap_alloc(
2456            inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2457        if (inst->disp_hash[idx].func_name == NULL) {
2458            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2459                       "loader_add_dev_ext_table() can't allocate memory for "
2460                       "func_name");
2461            return false;
2462        }
2463        strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
2464        return true;
2465    }
2466
2467    // check for enough capacity
2468    if (list->capacity == 0) {
2469        list->index = loader_heap_alloc(inst, 8 * sizeof(*(list->index)),
2470                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2471        if (list->index == NULL) {
2472            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2473                       "loader_add_dev_ext_table() can't allocate list memory");
2474            return false;
2475        }
2476        list->capacity = 8 * sizeof(*(list->index));
2477    } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
2478        list->index = loader_heap_realloc(inst, list->index, list->capacity,
2479                                          list->capacity * 2,
2480                                          VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2481        if (list->index == NULL) {
2482            loader_log(
2483                inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2484                "loader_add_dev_ext_table() can't reallocate list memory");
2485            return false;
2486        }
2487        list->capacity *= 2;
2488    }
2489
2490    // find an unused index in the hash table and use it
2491    i = (idx + 1) % MAX_NUM_DEV_EXTS;
2492    do {
2493        if (!inst->disp_hash[i].func_name) {
2494            assert(inst->disp_hash[i].list.capacity == 0);
2495            inst->disp_hash[i].func_name =
2496                (char *)loader_heap_alloc(inst, strlen(funcName) + 1,
2497                                          VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2498            if (inst->disp_hash[i].func_name == NULL) {
2499                loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2500                           "loader_add_dev_ext_table() can't rallocate "
2501                           "func_name memory");
2502                return false;
2503            }
2504            strncpy(inst->disp_hash[i].func_name, funcName,
2505                    strlen(funcName) + 1);
2506            list->index[list->count] = i;
2507            list->count++;
2508            *ptr_idx = i;
2509            return true;
2510        }
2511        i = (i + 1) % MAX_NUM_DEV_EXTS;
2512    } while (i != idx);
2513
2514    loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2515               "loader_add_dev_ext_table() couldn't insert into hash table; is "
2516               "it full?");
2517    return false;
2518}
2519
2520static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
2521                                         uint32_t *idx, const char *funcName) {
2522    uint32_t alt_idx;
2523    if (inst->disp_hash[*idx].func_name &&
2524        !strcmp(inst->disp_hash[*idx].func_name, funcName))
2525        return true;
2526
2527    // funcName wasn't at the primary spot in the hash table
2528    // search the list of secondary locations (shallow search, not deep search)
2529    for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
2530        alt_idx = inst->disp_hash[*idx].list.index[i];
2531        if (!strcmp(inst->disp_hash[*idx].func_name, funcName)) {
2532            *idx = alt_idx;
2533            return true;
2534        }
2535    }
2536
2537    return false;
2538}
2539
2540/**
2541 * This function returns generic trampoline code address for unknown entry
2542 * points.
2543 * Presumably, these unknown entry points (as given by funcName) are device
2544 * extension entrypoints.  A hash table is used to keep a list of unknown entry
2545 * points and their mapping to the device extension dispatch table
2546 * (struct loader_dev_ext_dispatch_table).
2547 * \returns
2548 * For a given entry point string (funcName), if an existing mapping is found
2549 * the
2550 * trampoline address for that mapping is returned. Otherwise, this unknown
2551 * entry point
2552 * has not been seen yet. Next check if a layer or ICD supports it.  If so then
2553 * a
2554 * new entry in the hash table is initialized and that trampoline address for
2555 * the new entry is returned. Null is returned if the hash table is full or
2556 * if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
2557 */
2558void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
2559    uint32_t idx;
2560    uint32_t seed = 0;
2561
2562    idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
2563
2564    if (loader_name_in_dev_ext_table(inst, &idx, funcName))
2565        // found funcName already in hash
2566        return loader_get_dev_ext_trampoline(idx);
2567
2568    // Check if funcName is supported in either ICDs or a layer library
2569    if (!loader_check_icds_for_address(inst, funcName)) {
2570        // TODO Add check in layer libraries for support of address
2571        // if support found in layers continue on
2572        return NULL;
2573    }
2574
2575    if (loader_add_dev_ext_table(inst, &idx, funcName)) {
2576        // successfully added new table entry
2577        // init any dev dispatch table entrys as needed
2578        loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
2579        return loader_get_dev_ext_trampoline(idx);
2580    }
2581
2582    return NULL;
2583}
2584
2585struct loader_instance *loader_get_instance(const VkInstance instance) {
2586    /* look up the loader_instance in our list by comparing dispatch tables, as
2587     * there is no guarantee the instance is still a loader_instance* after any
2588     * layers which wrap the instance object.
2589     */
2590    const VkLayerInstanceDispatchTable *disp;
2591    struct loader_instance *ptr_instance = NULL;
2592    disp = loader_get_instance_dispatch(instance);
2593    for (struct loader_instance *inst = loader.instances; inst;
2594         inst = inst->next) {
2595        if (inst->disp == disp) {
2596            ptr_instance = inst;
2597            break;
2598        }
2599    }
2600    return ptr_instance;
2601}
2602
2603static loader_platform_dl_handle
2604loader_add_layer_lib(const struct loader_instance *inst, const char *chain_type,
2605                     struct loader_layer_properties *layer_prop) {
2606    struct loader_lib_info *new_layer_lib_list, *my_lib;
2607    size_t new_alloc_size;
2608    /*
2609     * TODO: We can now track this information in the
2610     * scanned_layer_libraries list.
2611     */
2612    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
2613        if (strcmp(loader.loaded_layer_lib_list[i].lib_name,
2614                   layer_prop->lib_name) == 0) {
2615            /* Have already loaded this library, just increment ref count */
2616            loader.loaded_layer_lib_list[i].ref_count++;
2617            loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2618                       "%s Chain: Increment layer reference count for layer "
2619                       "library %s",
2620                       chain_type, layer_prop->lib_name);
2621            return loader.loaded_layer_lib_list[i].lib_handle;
2622        }
2623    }
2624
2625    /* Haven't seen this library so load it */
2626    new_alloc_size = 0;
2627    if (loader.loaded_layer_lib_capacity == 0)
2628        new_alloc_size = 8 * sizeof(struct loader_lib_info);
2629    else if (loader.loaded_layer_lib_capacity <=
2630             loader.loaded_layer_lib_count * sizeof(struct loader_lib_info))
2631        new_alloc_size = loader.loaded_layer_lib_capacity * 2;
2632
2633    if (new_alloc_size) {
2634        new_layer_lib_list = loader_heap_realloc(
2635            inst, loader.loaded_layer_lib_list,
2636            loader.loaded_layer_lib_capacity, new_alloc_size,
2637            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2638        if (!new_layer_lib_list) {
2639            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2640                       "loader: realloc failed in loader_add_layer_lib");
2641            return NULL;
2642        }
2643        loader.loaded_layer_lib_capacity = new_alloc_size;
2644        loader.loaded_layer_lib_list = new_layer_lib_list;
2645    } else
2646        new_layer_lib_list = loader.loaded_layer_lib_list;
2647    my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
2648
2649    strncpy(my_lib->lib_name, layer_prop->lib_name, sizeof(my_lib->lib_name));
2650    my_lib->lib_name[sizeof(my_lib->lib_name) - 1] = '\0';
2651    my_lib->ref_count = 0;
2652    my_lib->lib_handle = NULL;
2653
2654    if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) ==
2655        NULL) {
2656        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2657                   loader_platform_open_library_error(my_lib->lib_name));
2658        return NULL;
2659    } else {
2660        loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2661                   "Chain: %s: Loading layer library %s", chain_type,
2662                   layer_prop->lib_name);
2663    }
2664    loader.loaded_layer_lib_count++;
2665    my_lib->ref_count++;
2666
2667    return my_lib->lib_handle;
2668}
2669
2670static void
2671loader_remove_layer_lib(struct loader_instance *inst,
2672                        struct loader_layer_properties *layer_prop) {
2673    uint32_t idx = loader.loaded_layer_lib_count;
2674    struct loader_lib_info *new_layer_lib_list, *my_lib = NULL;
2675
2676    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
2677        if (strcmp(loader.loaded_layer_lib_list[i].lib_name,
2678                   layer_prop->lib_name) == 0) {
2679            /* found matching library */
2680            idx = i;
2681            my_lib = &loader.loaded_layer_lib_list[i];
2682            break;
2683        }
2684    }
2685
2686    if (idx == loader.loaded_layer_lib_count) {
2687        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2688                   "Unable to unref library %s", layer_prop->lib_name);
2689        return;
2690    }
2691
2692    if (my_lib) {
2693        my_lib->ref_count--;
2694        if (my_lib->ref_count > 0) {
2695            loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2696                       "Decrement reference count for layer library %s",
2697                       layer_prop->lib_name);
2698            return;
2699        }
2700    }
2701    loader_platform_close_library(my_lib->lib_handle);
2702    loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2703               "Unloading layer library %s", layer_prop->lib_name);
2704
2705    /* Need to remove unused library from list */
2706    new_layer_lib_list =
2707        loader_heap_alloc(inst, loader.loaded_layer_lib_capacity,
2708                          VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2709    if (!new_layer_lib_list) {
2710        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2711                   "loader: heap alloc failed loader_remove_layer_library");
2712        return;
2713    }
2714
2715    if (idx > 0) {
2716        /* Copy records before idx */
2717        memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
2718               sizeof(struct loader_lib_info) * idx);
2719    }
2720    if (idx < (loader.loaded_layer_lib_count - 1)) {
2721        /* Copy records after idx */
2722        memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx + 1],
2723               sizeof(struct loader_lib_info) *
2724                   (loader.loaded_layer_lib_count - idx - 1));
2725    }
2726
2727    loader_heap_free(inst, loader.loaded_layer_lib_list);
2728    loader.loaded_layer_lib_count--;
2729    loader.loaded_layer_lib_list = new_layer_lib_list;
2730}
2731
2732/**
2733 * Go through the search_list and find any layers which match type. If layer
2734 * type match is found in then add it to ext_list.
2735 */
2736static void
2737loader_add_layer_implicit(const struct loader_instance *inst,
2738                          const enum layer_type type,
2739                          struct loader_layer_list *list,
2740                          const struct loader_layer_list *search_list) {
2741    bool enable;
2742    char *env_value;
2743    uint32_t i;
2744    for (i = 0; i < search_list->count; i++) {
2745        const struct loader_layer_properties *prop = &search_list->list[i];
2746        if (prop->type & type) {
2747            /* Found an implicit layer, see if it should be enabled */
2748            enable = false;
2749
2750            // if no enable_environment variable is specified, this implicit
2751            // layer
2752            // should always be enabled. Otherwise check if the variable is set
2753            if (prop->enable_env_var.name[0] == 0) {
2754                enable = true;
2755            } else {
2756                env_value = loader_getenv(prop->enable_env_var.name);
2757                if (env_value && !strcmp(prop->enable_env_var.value, env_value))
2758                    enable = true;
2759                loader_free_getenv(env_value);
2760            }
2761
2762            // disable_environment has priority, i.e. if both enable and disable
2763            // environment variables are set, the layer is disabled. Implicit
2764            // layers
2765            // are required to have a disable_environment variables
2766            env_value = loader_getenv(prop->disable_env_var.name);
2767            if (env_value)
2768                enable = false;
2769            loader_free_getenv(env_value);
2770
2771            if (enable)
2772                loader_add_to_layer_list(inst, list, 1, prop);
2773        }
2774    }
2775}
2776
2777/**
2778 * Get the layer name(s) from the env_name environment variable. If layer
2779 * is found in search_list then add it to layer_list.  But only add it to
2780 * layer_list if type matches.
2781 */
2782static void loader_add_layer_env(const struct loader_instance *inst,
2783                                 const enum layer_type type,
2784                                 const char *env_name,
2785                                 struct loader_layer_list *layer_list,
2786                                 const struct loader_layer_list *search_list) {
2787    char *layerEnv;
2788    char *next, *name;
2789
2790    layerEnv = loader_getenv(env_name);
2791    if (layerEnv == NULL) {
2792        return;
2793    }
2794    name = loader_stack_alloc(strlen(layerEnv) + 1);
2795    if (name == NULL) {
2796        return;
2797    }
2798    strcpy(name, layerEnv);
2799
2800    loader_free_getenv(layerEnv);
2801
2802    while (name && *name) {
2803        next = loader_get_next_path(name);
2804        loader_find_layer_name_add_list(inst, name, type, search_list,
2805                                        layer_list);
2806        name = next;
2807    }
2808
2809    return;
2810}
2811
2812void loader_deactivate_instance_layers(struct loader_instance *instance) {
2813    /* Create instance chain of enabled layers */
2814    for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
2815        struct loader_layer_properties *layer_prop =
2816            &instance->activated_layer_list.list[i];
2817
2818        loader_remove_layer_lib(instance, layer_prop);
2819    }
2820    loader_destroy_layer_list(instance, &instance->activated_layer_list);
2821}
2822
2823VkResult
2824loader_enable_instance_layers(struct loader_instance *inst,
2825                              const VkInstanceCreateInfo *pCreateInfo,
2826                              const struct loader_layer_list *instance_layers) {
2827    VkResult err;
2828
2829    assert(inst && "Cannot have null instance");
2830
2831    if (!loader_init_layer_list(inst, &inst->activated_layer_list)) {
2832        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2833                   "Failed to alloc Instance activated layer list");
2834        return VK_ERROR_OUT_OF_HOST_MEMORY;
2835    }
2836
2837    /* Add any implicit layers first */
2838    loader_add_layer_implicit(inst, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2839                              &inst->activated_layer_list, instance_layers);
2840
2841    /* Add any layers specified via environment variable next */
2842    loader_add_layer_env(inst, VK_LAYER_TYPE_INSTANCE_EXPLICIT,
2843                         "VK_INSTANCE_LAYERS", &inst->activated_layer_list,
2844                         instance_layers);
2845
2846    /* Add layers specified by the application */
2847    err = loader_add_layer_names_to_list(
2848        inst, &inst->activated_layer_list, pCreateInfo->enabledLayerCount,
2849        pCreateInfo->ppEnabledLayerNames, instance_layers);
2850
2851    return err;
2852}
2853
2854/*
2855 * Given the list of layers to activate in the loader_instance
2856 * structure. This function will add a VkLayerInstanceCreateInfo
2857 * structure to the VkInstanceCreateInfo.pNext pointer.
2858 * Each activated layer will have it's own VkLayerInstanceLink
2859 * structure that tells the layer what Get*ProcAddr to call to
2860 * get function pointers to the next layer down.
2861 * Once the chain info has been created this function will
2862 * execute the CreateInstance call chain. Each layer will
2863 * then have an opportunity in it's CreateInstance function
2864 * to setup it's dispatch table when the lower layer returns
2865 * successfully.
2866 * Each layer can wrap or not-wrap the returned VkInstance object
2867 * as it sees fit.
2868 * The instance chain is terminated by a loader function
2869 * that will call CreateInstance on all available ICD's and
2870 * cache those VkInstance objects for future use.
2871 */
2872VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo,
2873                                      const VkAllocationCallbacks *pAllocator,
2874                                      struct loader_instance *inst,
2875                                      VkInstance *created_instance) {
2876    uint32_t activated_layers = 0;
2877    VkLayerInstanceCreateInfo chain_info;
2878    VkLayerInstanceLink *layer_instance_link_info = NULL;
2879    VkInstanceCreateInfo loader_create_info;
2880    VkResult res;
2881
2882    PFN_vkGetInstanceProcAddr nextGIPA = loader_gpa_instance_internal;
2883    PFN_vkGetInstanceProcAddr fpGIPA = loader_gpa_instance_internal;
2884
2885    memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
2886
2887    if (inst->activated_layer_list.count > 0) {
2888
2889        chain_info.u.pLayerInfo = NULL;
2890        chain_info.pNext = pCreateInfo->pNext;
2891        chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
2892        chain_info.function = VK_LAYER_LINK_INFO;
2893        loader_create_info.pNext = &chain_info;
2894
2895        layer_instance_link_info = loader_stack_alloc(
2896            sizeof(VkLayerInstanceLink) * inst->activated_layer_list.count);
2897        if (!layer_instance_link_info) {
2898            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2899                       "Failed to alloc Instance objects for layer");
2900            return VK_ERROR_OUT_OF_HOST_MEMORY;
2901        }
2902
2903        /* Create instance chain of enabled layers */
2904        for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
2905            struct loader_layer_properties *layer_prop =
2906                &inst->activated_layer_list.list[i];
2907            loader_platform_dl_handle lib_handle;
2908
2909            lib_handle = loader_add_layer_lib(inst, "instance", layer_prop);
2910            if (!lib_handle)
2911                continue;
2912            if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
2913                NULL) {
2914                if (layer_prop->functions.str_gipa == NULL ||
2915                    strlen(layer_prop->functions.str_gipa) == 0) {
2916                    fpGIPA = (PFN_vkGetInstanceProcAddr)
2917                        loader_platform_get_proc_address(
2918                            lib_handle, "vkGetInstanceProcAddr");
2919                    layer_prop->functions.get_instance_proc_addr = fpGIPA;
2920                } else
2921                    fpGIPA = (PFN_vkGetInstanceProcAddr)
2922                        loader_platform_get_proc_address(
2923                            lib_handle, layer_prop->functions.str_gipa);
2924                if (!fpGIPA) {
2925                    loader_log(
2926                        inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2927                        "Failed to find vkGetInstanceProcAddr in layer %s",
2928                        layer_prop->lib_name);
2929                    continue;
2930                }
2931            }
2932
2933            layer_instance_link_info[activated_layers].pNext =
2934                chain_info.u.pLayerInfo;
2935            layer_instance_link_info[activated_layers]
2936                .pfnNextGetInstanceProcAddr = nextGIPA;
2937            chain_info.u.pLayerInfo =
2938                &layer_instance_link_info[activated_layers];
2939            nextGIPA = fpGIPA;
2940
2941            loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2942                       "Insert instance layer %s (%s)",
2943                       layer_prop->info.layerName, layer_prop->lib_name);
2944
2945            activated_layers++;
2946        }
2947    }
2948
2949    PFN_vkCreateInstance fpCreateInstance =
2950        (PFN_vkCreateInstance)nextGIPA(*created_instance, "vkCreateInstance");
2951    if (fpCreateInstance) {
2952        VkLayerInstanceCreateInfo instance_create_info;
2953
2954        instance_create_info.sType =
2955            VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
2956        instance_create_info.function = VK_LAYER_INSTANCE_INFO;
2957
2958        instance_create_info.u.instanceInfo.instance_info = inst;
2959        instance_create_info.u.instanceInfo.pfnNextGetInstanceProcAddr =
2960            nextGIPA;
2961
2962        instance_create_info.pNext = loader_create_info.pNext;
2963        loader_create_info.pNext = &instance_create_info;
2964
2965        res = fpCreateInstance(&loader_create_info, pAllocator,
2966                               created_instance);
2967    } else {
2968        // Couldn't find CreateInstance function!
2969        res = VK_ERROR_INITIALIZATION_FAILED;
2970    }
2971
2972    if (res != VK_SUCCESS) {
2973        // TODO: Need to clean up here
2974    } else {
2975        loader_init_instance_core_dispatch_table(inst->disp, nextGIPA,
2976                                                 *created_instance);
2977    }
2978
2979    return res;
2980}
2981
2982void loader_activate_instance_layer_extensions(struct loader_instance *inst,
2983                                               VkInstance created_inst) {
2984
2985    loader_init_instance_extension_dispatch_table(
2986        inst->disp, inst->disp->GetInstanceProcAddr, created_inst);
2987}
2988
2989static VkResult
2990loader_enable_device_layers(const struct loader_instance *inst,
2991                            struct loader_icd *icd,
2992                            struct loader_layer_list *activated_layer_list,
2993                            const VkDeviceCreateInfo *pCreateInfo,
2994                            const struct loader_layer_list *device_layers)
2995
2996{
2997    VkResult err;
2998
2999    assert(activated_layer_list && "Cannot have null output layer list");
3000
3001    if (activated_layer_list->list == NULL ||
3002        activated_layer_list->capacity == 0) {
3003        loader_init_layer_list(inst, activated_layer_list);
3004    }
3005
3006    if (activated_layer_list->list == NULL) {
3007        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3008                   "Failed to alloc device activated layer list");
3009        return VK_ERROR_OUT_OF_HOST_MEMORY;
3010    }
3011
3012    /* Add any implicit layers first */
3013    loader_add_layer_implicit(inst, VK_LAYER_TYPE_DEVICE_IMPLICIT,
3014                              activated_layer_list, device_layers);
3015
3016    /* Add any layers specified via environment variable next */
3017    loader_add_layer_env(inst, VK_LAYER_TYPE_DEVICE_EXPLICIT,
3018                         "VK_DEVICE_LAYERS", activated_layer_list,
3019                         device_layers);
3020
3021    /* Add layers specified by the application */
3022    err = loader_add_layer_names_to_list(
3023        inst, activated_layer_list, pCreateInfo->enabledLayerCount,
3024        pCreateInfo->ppEnabledLayerNames, device_layers);
3025
3026    return err;
3027}
3028
3029VKAPI_ATTR VkResult VKAPI_CALL
3030loader_create_device_terminator(VkPhysicalDevice physicalDevice,
3031                                const VkDeviceCreateInfo *pCreateInfo,
3032                                const VkAllocationCallbacks *pAllocator,
3033                                VkDevice *pDevice) {
3034    struct loader_physical_device *phys_dev;
3035    phys_dev = loader_get_physical_device(physicalDevice);
3036
3037    VkLayerDeviceCreateInfo *chain_info =
3038        (VkLayerDeviceCreateInfo *)pCreateInfo->pNext;
3039    while (chain_info &&
3040           !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
3041             chain_info->function == VK_LAYER_DEVICE_INFO)) {
3042        chain_info = (VkLayerDeviceCreateInfo *)chain_info->pNext;
3043    }
3044    assert(chain_info != NULL);
3045
3046    struct loader_device *dev =
3047        (struct loader_device *)chain_info->u.deviceInfo.device_info;
3048    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
3049        chain_info->u.deviceInfo.pfnNextGetInstanceProcAddr;
3050    PFN_vkCreateDevice fpCreateDevice =
3051        (PFN_vkCreateDevice)fpGetInstanceProcAddr(phys_dev->this_icd->instance,
3052                                                  "vkCreateDevice");
3053    if (fpCreateDevice == NULL) {
3054        return VK_ERROR_INITIALIZATION_FAILED;
3055    }
3056
3057    VkDeviceCreateInfo localCreateInfo;
3058    memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
3059    localCreateInfo.pNext = loader_strip_create_extensions(pCreateInfo->pNext);
3060
3061    /*
3062     * NOTE: Need to filter the extensions to only those
3063     * supported by the ICD.
3064     * No ICD will advertise support for layers. An ICD
3065     * library could support a layer, but it would be
3066     * independent of the actual ICD, just in the same library.
3067     */
3068    char **filtered_extension_names = NULL;
3069    filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
3070    if (!filtered_extension_names) {
3071        return VK_ERROR_OUT_OF_HOST_MEMORY;
3072    }
3073
3074    localCreateInfo.enabledLayerCount = 0;
3075    localCreateInfo.ppEnabledLayerNames = NULL;
3076
3077    localCreateInfo.enabledExtensionCount = 0;
3078    localCreateInfo.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
3079
3080    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3081        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
3082        VkExtensionProperties *prop = get_extension_property(extension_name,
3083                                      &phys_dev->device_extension_cache);
3084        if (prop) {
3085            filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *) extension_name;
3086            localCreateInfo.enabledExtensionCount++;
3087        }
3088    }
3089
3090    VkDevice localDevice;
3091    // TODO: Why does fpCreateDevice behave differently than
3092    // this_icd->CreateDevice?
3093    //    VkResult res = fpCreateDevice(phys_dev->phys_dev, &localCreateInfo,
3094    //    pAllocator, &localDevice);
3095    VkResult res = phys_dev->this_icd->CreateDevice(
3096        phys_dev->phys_dev, &localCreateInfo, pAllocator, &localDevice);
3097
3098    if (res != VK_SUCCESS) {
3099        return res;
3100    }
3101
3102    *pDevice = localDevice;
3103
3104    /* Init dispatch pointer in new device object */
3105    loader_init_dispatch(*pDevice, &dev->loader_dispatch);
3106
3107    return res;
3108}
3109
3110VkResult loader_create_device_chain(VkPhysicalDevice physicalDevice,
3111                                    const VkDeviceCreateInfo *pCreateInfo,
3112                                    const VkAllocationCallbacks *pAllocator,
3113                                    struct loader_instance *inst,
3114                                    struct loader_icd *icd,
3115                                    struct loader_device *dev) {
3116    uint32_t activated_layers = 0;
3117    VkLayerDeviceLink *layer_device_link_info;
3118    VkLayerDeviceCreateInfo chain_info;
3119    VkLayerDeviceCreateInfo device_info;
3120    VkDeviceCreateInfo loader_create_info;
3121    VkResult res;
3122
3123    PFN_vkGetDeviceProcAddr fpGDPA, nextGDPA = icd->GetDeviceProcAddr;
3124    PFN_vkGetInstanceProcAddr fpGIPA, nextGIPA = loader_gpa_instance_internal;
3125
3126    memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
3127
3128    chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
3129    chain_info.function = VK_LAYER_LINK_INFO;
3130    chain_info.u.pLayerInfo = NULL;
3131    chain_info.pNext = pCreateInfo->pNext;
3132
3133    layer_device_link_info = loader_stack_alloc(
3134        sizeof(VkLayerDeviceLink) * dev->activated_layer_list.count);
3135    if (!layer_device_link_info) {
3136        loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3137                   "Failed to alloc Device objects for layer");
3138        return VK_ERROR_OUT_OF_HOST_MEMORY;
3139    }
3140
3141    /*
3142     * This structure is used by loader_create_device_terminator
3143     * so that it can intialize the device dispatch table pointer
3144     * in the device object returned by the ICD. Without this
3145     * structure the code wouldn't know where the loader's device_info
3146     * structure is located.
3147     */
3148    device_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
3149    device_info.function = VK_LAYER_DEVICE_INFO;
3150    device_info.pNext = &chain_info;
3151    device_info.u.deviceInfo.device_info = dev;
3152    device_info.u.deviceInfo.pfnNextGetInstanceProcAddr =
3153        icd->this_icd_lib->GetInstanceProcAddr;
3154
3155    loader_create_info.pNext = &device_info;
3156
3157    if (dev->activated_layer_list.count > 0) {
3158        /* Create instance chain of enabled layers */
3159        for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
3160            struct loader_layer_properties *layer_prop =
3161                &dev->activated_layer_list.list[i];
3162            loader_platform_dl_handle lib_handle;
3163
3164            lib_handle = loader_add_layer_lib(inst, "device", layer_prop);
3165            if (!lib_handle)
3166                continue;
3167            if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
3168                NULL) {
3169                if (layer_prop->functions.str_gipa == NULL ||
3170                    strlen(layer_prop->functions.str_gipa) == 0) {
3171                    fpGIPA = (PFN_vkGetInstanceProcAddr)
3172                        loader_platform_get_proc_address(
3173                            lib_handle, "vkGetInstanceProcAddr");
3174                    layer_prop->functions.get_instance_proc_addr = fpGIPA;
3175                } else
3176                    fpGIPA = (PFN_vkGetInstanceProcAddr)
3177                        loader_platform_get_proc_address(
3178                            lib_handle, layer_prop->functions.str_gipa);
3179                if (!fpGIPA) {
3180                    loader_log(
3181                        inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3182                        "Failed to find vkGetInstanceProcAddr in layer %s",
3183                        layer_prop->lib_name);
3184                    continue;
3185                }
3186            }
3187            if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
3188                if (layer_prop->functions.str_gdpa == NULL ||
3189                    strlen(layer_prop->functions.str_gdpa) == 0) {
3190                    fpGDPA = (PFN_vkGetDeviceProcAddr)
3191                        loader_platform_get_proc_address(lib_handle,
3192                                                         "vkGetDeviceProcAddr");
3193                    layer_prop->functions.get_device_proc_addr = fpGDPA;
3194                } else
3195                    fpGDPA = (PFN_vkGetDeviceProcAddr)
3196                        loader_platform_get_proc_address(
3197                            lib_handle, layer_prop->functions.str_gdpa);
3198                if (!fpGDPA) {
3199                    loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3200                               "Failed to find vkGetDeviceProcAddr in layer %s",
3201                               layer_prop->lib_name);
3202                    continue;
3203                }
3204            }
3205
3206            layer_device_link_info[activated_layers].pNext =
3207                chain_info.u.pLayerInfo;
3208            layer_device_link_info[activated_layers]
3209                .pfnNextGetInstanceProcAddr = nextGIPA;
3210            layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
3211                nextGDPA;
3212            chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
3213            nextGIPA = fpGIPA;
3214            nextGDPA = fpGDPA;
3215
3216            loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3217                       "Insert device layer %s (%s)",
3218                       layer_prop->info.layerName, layer_prop->lib_name);
3219
3220            activated_layers++;
3221        }
3222    }
3223
3224    PFN_vkCreateDevice fpCreateDevice =
3225        (PFN_vkCreateDevice)nextGIPA((VkInstance)inst, "vkCreateDevice");
3226    if (fpCreateDevice) {
3227        res = fpCreateDevice(physicalDevice, &loader_create_info, pAllocator,
3228                             &dev->device);
3229    } else {
3230        // Couldn't find CreateDevice function!
3231        return VK_ERROR_INITIALIZATION_FAILED;
3232    }
3233
3234    /* Initialize device dispatch table */
3235    loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA,
3236                                      dev->device);
3237
3238    return res;
3239}
3240
3241VkResult loader_validate_layers(const struct loader_instance *inst,
3242                                const uint32_t layer_count,
3243                                const char *const *ppEnabledLayerNames,
3244                                const struct loader_layer_list *list) {
3245    struct loader_layer_properties *prop;
3246
3247    for (uint32_t i = 0; i < layer_count; i++) {
3248        VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
3249        if (result != VK_STRING_ERROR_NONE) {
3250            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3251                "Loader: Device ppEnabledLayerNames contains string that is too long or is badly formed");
3252            return VK_ERROR_LAYER_NOT_PRESENT;
3253        }
3254
3255        prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
3256        if (!prop) {
3257            return VK_ERROR_LAYER_NOT_PRESENT;
3258        }
3259    }
3260    return VK_SUCCESS;
3261}
3262
3263VkResult loader_validate_instance_extensions(
3264    const struct loader_instance *inst,
3265    const struct loader_extension_list *icd_exts,
3266    const struct loader_layer_list *instance_layer,
3267    const VkInstanceCreateInfo *pCreateInfo) {
3268
3269    VkExtensionProperties *extension_prop;
3270    struct loader_layer_properties *layer_prop;
3271
3272    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3273        VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
3274        if (result != VK_STRING_ERROR_NONE) {
3275            loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3276                "Loader: Instance ppEnabledExtensionNames contains string that is too long or is badly formed");
3277            return VK_ERROR_EXTENSION_NOT_PRESENT;
3278        }
3279
3280        extension_prop = get_extension_property(
3281            pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
3282
3283        if (extension_prop) {
3284            continue;
3285        }
3286
3287        extension_prop = NULL;
3288
3289        /* Not in global list, search layer extension lists */
3290        for (uint32_t j = 0; j < pCreateInfo->enabledLayerCount; j++) {
3291            layer_prop = loader_get_layer_property(
3292                pCreateInfo->ppEnabledLayerNames[i], instance_layer);
3293            if (!layer_prop) {
3294                /* Should NOT get here, loader_validate_layers
3295                 * should have already filtered this case out.
3296                 */
3297                continue;
3298            }
3299
3300            extension_prop =
3301                get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
3302                                       &layer_prop->instance_extension_list);
3303            if (extension_prop) {
3304                /* Found the extension in one of the layers enabled by the app.
3305                 */
3306                break;
3307            }
3308        }
3309
3310        if (!extension_prop) {
3311            /* Didn't find extension name in any of the global layers, error out
3312             */
3313            return VK_ERROR_EXTENSION_NOT_PRESENT;
3314        }
3315    }
3316    return VK_SUCCESS;
3317}
3318
3319VkResult loader_validate_device_extensions(
3320    struct loader_physical_device *phys_dev,
3321    const struct loader_layer_list *activated_device_layers,
3322    const VkDeviceCreateInfo *pCreateInfo) {
3323    VkExtensionProperties *extension_prop;
3324    struct loader_layer_properties *layer_prop;
3325
3326    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3327
3328        VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
3329        if (result != VK_STRING_ERROR_NONE) {
3330            loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3331                "Loader: Device ppEnabledExtensionNames contains string that is too long or is badly formed");
3332            return VK_ERROR_EXTENSION_NOT_PRESENT;
3333        }
3334
3335        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
3336        extension_prop = get_extension_property(
3337            extension_name, &phys_dev->device_extension_cache);
3338
3339        if (extension_prop) {
3340            continue;
3341        }
3342
3343        /* Not in global list, search activated layer extension lists */
3344        for (uint32_t j = 0; j < activated_device_layers->count; j++) {
3345            layer_prop = &activated_device_layers->list[j];
3346
3347            extension_prop = get_dev_extension_property(
3348                extension_name, &layer_prop->device_extension_list);
3349            if (extension_prop) {
3350                /* Found the extension in one of the layers enabled by the app.
3351                 */
3352                break;
3353            }
3354        }
3355
3356        if (!extension_prop) {
3357            /* Didn't find extension name in any of the device layers, error out
3358             */
3359            return VK_ERROR_EXTENSION_NOT_PRESENT;
3360        }
3361    }
3362    return VK_SUCCESS;
3363}
3364
3365VKAPI_ATTR VkResult VKAPI_CALL
3366loader_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
3367                      const VkAllocationCallbacks *pAllocator,
3368                      VkInstance *pInstance) {
3369    struct loader_icd *icd;
3370    VkExtensionProperties *prop;
3371    char **filtered_extension_names = NULL;
3372    VkInstanceCreateInfo icd_create_info;
3373    VkResult res = VK_SUCCESS;
3374    bool success = false;
3375
3376    VkLayerInstanceCreateInfo *chain_info =
3377        (VkLayerInstanceCreateInfo *)pCreateInfo->pNext;
3378    while (
3379        chain_info &&
3380        !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
3381          chain_info->function == VK_LAYER_INSTANCE_INFO)) {
3382        chain_info = (VkLayerInstanceCreateInfo *)chain_info->pNext;
3383    }
3384    assert(chain_info != NULL);
3385
3386    struct loader_instance *ptr_instance =
3387        (struct loader_instance *)chain_info->u.instanceInfo.instance_info;
3388    memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
3389
3390    icd_create_info.enabledLayerCount = 0;
3391    icd_create_info.ppEnabledLayerNames = NULL;
3392
3393    // strip off the VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO entries
3394    icd_create_info.pNext = loader_strip_create_extensions(pCreateInfo->pNext);
3395
3396    /*
3397     * NOTE: Need to filter the extensions to only those
3398     * supported by the ICD.
3399     * No ICD will advertise support for layers. An ICD
3400     * library could support a layer, but it would be
3401     * independent of the actual ICD, just in the same library.
3402     */
3403    filtered_extension_names =
3404        loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
3405    if (!filtered_extension_names) {
3406        return VK_ERROR_OUT_OF_HOST_MEMORY;
3407    }
3408    icd_create_info.ppEnabledExtensionNames =
3409        (const char *const *)filtered_extension_names;
3410
3411    for (uint32_t i = 0; i < ptr_instance->icd_libs.count; i++) {
3412        icd = loader_icd_add(ptr_instance, &ptr_instance->icd_libs.list[i]);
3413        if (icd) {
3414            icd_create_info.enabledExtensionCount = 0;
3415            struct loader_extension_list icd_exts;
3416
3417            loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3418                       "Build ICD instance extension list");
3419            // traverse scanned icd list adding non-duplicate extensions to the
3420            // list
3421            loader_init_generic_list(ptr_instance,
3422                                     (struct loader_generic_list *)&icd_exts,
3423                                     sizeof(VkExtensionProperties));
3424            loader_add_instance_extensions(
3425                ptr_instance,
3426                icd->this_icd_lib->EnumerateInstanceExtensionProperties,
3427                icd->this_icd_lib->lib_name, &icd_exts);
3428
3429            for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
3430                prop = get_extension_property(
3431                    pCreateInfo->ppEnabledExtensionNames[i], &icd_exts);
3432                if (prop) {
3433                    filtered_extension_names[icd_create_info
3434                                                 .enabledExtensionCount] =
3435                        (char *)pCreateInfo->ppEnabledExtensionNames[i];
3436                    icd_create_info.enabledExtensionCount++;
3437                }
3438            }
3439
3440            loader_destroy_generic_list(
3441                ptr_instance, (struct loader_generic_list *)&icd_exts);
3442
3443            res = ptr_instance->icd_libs.list[i].CreateInstance(
3444                &icd_create_info, pAllocator, &(icd->instance));
3445            if (res == VK_SUCCESS)
3446                success = loader_icd_init_entrys(
3447                    icd, icd->instance,
3448                    ptr_instance->icd_libs.list[i].GetInstanceProcAddr);
3449
3450            if (res != VK_SUCCESS || !success) {
3451                ptr_instance->icds = ptr_instance->icds->next;
3452                loader_icd_destroy(ptr_instance, icd);
3453                loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3454                           "ICD ignored: failed to CreateInstance and find "
3455                           "entrypoints with ICD");
3456            }
3457        }
3458    }
3459
3460    /*
3461     * If no ICDs were added to instance list and res is unchanged
3462     * from it's initial value, the loader was unable to find
3463     * a suitable ICD.
3464     */
3465    if (ptr_instance->icds == NULL) {
3466        if (res == VK_SUCCESS) {
3467            return VK_ERROR_INCOMPATIBLE_DRIVER;
3468        } else {
3469            return res;
3470        }
3471    }
3472
3473    return VK_SUCCESS;
3474}
3475
3476VKAPI_ATTR void VKAPI_CALL
3477loader_DestroyInstance(VkInstance instance,
3478                       const VkAllocationCallbacks *pAllocator) {
3479    struct loader_instance *ptr_instance = loader_instance(instance);
3480    struct loader_icd *icds = ptr_instance->icds;
3481    struct loader_icd *next_icd;
3482
3483    // Remove this instance from the list of instances:
3484    struct loader_instance *prev = NULL;
3485    struct loader_instance *next = loader.instances;
3486    while (next != NULL) {
3487        if (next == ptr_instance) {
3488            // Remove this instance from the list:
3489            if (prev)
3490                prev->next = next->next;
3491            else
3492                loader.instances = next->next;
3493            break;
3494        }
3495        prev = next;
3496        next = next->next;
3497    }
3498
3499    while (icds) {
3500        if (icds->instance) {
3501            icds->DestroyInstance(icds->instance, pAllocator);
3502        }
3503        next_icd = icds->next;
3504        icds->instance = VK_NULL_HANDLE;
3505        loader_icd_destroy(ptr_instance, icds);
3506
3507        icds = next_icd;
3508    }
3509    loader_delete_layer_properties(ptr_instance,
3510                                   &ptr_instance->device_layer_list);
3511    loader_delete_layer_properties(ptr_instance,
3512                                   &ptr_instance->instance_layer_list);
3513    loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_libs);
3514    loader_destroy_generic_list(
3515        ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
3516    for (uint32_t i = 0; i < ptr_instance->total_gpu_count; i++)
3517        loader_destroy_generic_list(
3518            ptr_instance,
3519            (struct loader_generic_list *)&ptr_instance->phys_devs[i]
3520                .device_extension_cache);
3521    loader_heap_free(ptr_instance, ptr_instance->phys_devs);
3522    loader_free_dev_ext_table(ptr_instance);
3523}
3524
3525VkResult
3526loader_init_physical_device_info(struct loader_instance *ptr_instance) {
3527    struct loader_icd *icd;
3528    uint32_t i, j, idx, count = 0;
3529    VkResult res;
3530    struct loader_phys_dev_per_icd *phys_devs;
3531
3532    ptr_instance->total_gpu_count = 0;
3533    phys_devs = (struct loader_phys_dev_per_icd *)loader_stack_alloc(
3534        sizeof(struct loader_phys_dev_per_icd) * ptr_instance->total_icd_count);
3535    if (!phys_devs)
3536        return VK_ERROR_OUT_OF_HOST_MEMORY;
3537
3538    icd = ptr_instance->icds;
3539    for (i = 0; i < ptr_instance->total_icd_count; i++) {
3540        assert(icd);
3541        res = icd->EnumeratePhysicalDevices(icd->instance, &phys_devs[i].count,
3542                                            NULL);
3543        if (res != VK_SUCCESS)
3544            return res;
3545        count += phys_devs[i].count;
3546        icd = icd->next;
3547    }
3548
3549    ptr_instance->phys_devs =
3550        (struct loader_physical_device *)loader_heap_alloc(
3551            ptr_instance, count * sizeof(struct loader_physical_device),
3552            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3553    if (!ptr_instance->phys_devs)
3554        return VK_ERROR_OUT_OF_HOST_MEMORY;
3555
3556    icd = ptr_instance->icds;
3557
3558    struct loader_physical_device *inst_phys_devs = ptr_instance->phys_devs;
3559    idx = 0;
3560    for (i = 0; i < ptr_instance->total_icd_count; i++) {
3561        assert(icd);
3562
3563        phys_devs[i].phys_devs = (VkPhysicalDevice *)loader_stack_alloc(
3564            phys_devs[i].count * sizeof(VkPhysicalDevice));
3565        if (!phys_devs[i].phys_devs) {
3566            loader_heap_free(ptr_instance, ptr_instance->phys_devs);
3567            ptr_instance->phys_devs = NULL;
3568            return VK_ERROR_OUT_OF_HOST_MEMORY;
3569        }
3570        res = icd->EnumeratePhysicalDevices(
3571            icd->instance, &(phys_devs[i].count), phys_devs[i].phys_devs);
3572        if ((res == VK_SUCCESS)) {
3573            ptr_instance->total_gpu_count += phys_devs[i].count;
3574            for (j = 0; j < phys_devs[i].count; j++) {
3575
3576                // initialize the loader's physicalDevice object
3577                loader_set_dispatch((void *)&inst_phys_devs[idx],
3578                                    ptr_instance->disp);
3579                inst_phys_devs[idx].this_instance = ptr_instance;
3580                inst_phys_devs[idx].this_icd = icd;
3581                inst_phys_devs[idx].phys_dev = phys_devs[i].phys_devs[j];
3582                memset(&inst_phys_devs[idx].device_extension_cache, 0,
3583                       sizeof(struct loader_extension_list));
3584
3585                idx++;
3586            }
3587        } else {
3588            loader_heap_free(ptr_instance, ptr_instance->phys_devs);
3589            ptr_instance->phys_devs = NULL;
3590            return res;
3591        }
3592
3593        icd = icd->next;
3594    }
3595
3596    return VK_SUCCESS;
3597}
3598
3599VKAPI_ATTR VkResult VKAPI_CALL
3600loader_EnumeratePhysicalDevices(VkInstance instance,
3601                                uint32_t *pPhysicalDeviceCount,
3602                                VkPhysicalDevice *pPhysicalDevices) {
3603    uint32_t i;
3604    uint32_t copy_count = 0;
3605    struct loader_instance *ptr_instance = (struct loader_instance *)instance;
3606    VkResult res = VK_SUCCESS;
3607
3608    if (ptr_instance->total_gpu_count == 0) {
3609        res = loader_init_physical_device_info(ptr_instance);
3610    }
3611
3612    *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
3613    if (!pPhysicalDevices) {
3614        return res;
3615    }
3616
3617    copy_count = (ptr_instance->total_gpu_count < *pPhysicalDeviceCount)
3618                     ? ptr_instance->total_gpu_count
3619                     : *pPhysicalDeviceCount;
3620    for (i = 0; i < copy_count; i++) {
3621        pPhysicalDevices[i] = (VkPhysicalDevice)&ptr_instance->phys_devs[i];
3622    }
3623    *pPhysicalDeviceCount = copy_count;
3624
3625    if (copy_count < ptr_instance->total_gpu_count) {
3626        return VK_INCOMPLETE;
3627    }
3628
3629    return res;
3630}
3631
3632VKAPI_ATTR void VKAPI_CALL
3633loader_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
3634                                   VkPhysicalDeviceProperties *pProperties) {
3635    struct loader_physical_device *phys_dev =
3636        (struct loader_physical_device *)physicalDevice;
3637    struct loader_icd *icd = phys_dev->this_icd;
3638
3639    if (icd->GetPhysicalDeviceProperties)
3640        icd->GetPhysicalDeviceProperties(phys_dev->phys_dev, pProperties);
3641}
3642
3643VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceQueueFamilyProperties(
3644    VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
3645    VkQueueFamilyProperties *pProperties) {
3646    struct loader_physical_device *phys_dev =
3647        (struct loader_physical_device *)physicalDevice;
3648    struct loader_icd *icd = phys_dev->this_icd;
3649
3650    if (icd->GetPhysicalDeviceQueueFamilyProperties)
3651        icd->GetPhysicalDeviceQueueFamilyProperties(
3652            phys_dev->phys_dev, pQueueFamilyPropertyCount, pProperties);
3653}
3654
3655VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceMemoryProperties(
3656    VkPhysicalDevice physicalDevice,
3657    VkPhysicalDeviceMemoryProperties *pProperties) {
3658    struct loader_physical_device *phys_dev =
3659        (struct loader_physical_device *)physicalDevice;
3660    struct loader_icd *icd = phys_dev->this_icd;
3661
3662    if (icd->GetPhysicalDeviceMemoryProperties)
3663        icd->GetPhysicalDeviceMemoryProperties(phys_dev->phys_dev, pProperties);
3664}
3665
3666VKAPI_ATTR void VKAPI_CALL
3667loader_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
3668                                 VkPhysicalDeviceFeatures *pFeatures) {
3669    struct loader_physical_device *phys_dev =
3670        (struct loader_physical_device *)physicalDevice;
3671    struct loader_icd *icd = phys_dev->this_icd;
3672
3673    if (icd->GetPhysicalDeviceFeatures)
3674        icd->GetPhysicalDeviceFeatures(phys_dev->phys_dev, pFeatures);
3675}
3676
3677VKAPI_ATTR void VKAPI_CALL
3678loader_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice,
3679                                         VkFormat format,
3680                                         VkFormatProperties *pFormatInfo) {
3681    struct loader_physical_device *phys_dev =
3682        (struct loader_physical_device *)physicalDevice;
3683    struct loader_icd *icd = phys_dev->this_icd;
3684
3685    if (icd->GetPhysicalDeviceFormatProperties)
3686        icd->GetPhysicalDeviceFormatProperties(phys_dev->phys_dev, format,
3687                                               pFormatInfo);
3688}
3689
3690VKAPI_ATTR VkResult VKAPI_CALL loader_GetPhysicalDeviceImageFormatProperties(
3691    VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
3692    VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
3693    VkImageFormatProperties *pImageFormatProperties) {
3694    struct loader_physical_device *phys_dev =
3695        (struct loader_physical_device *)physicalDevice;
3696    struct loader_icd *icd = phys_dev->this_icd;
3697
3698    if (!icd->GetPhysicalDeviceImageFormatProperties)
3699        return VK_ERROR_INITIALIZATION_FAILED;
3700
3701    return icd->GetPhysicalDeviceImageFormatProperties(
3702        phys_dev->phys_dev, format, type, tiling, usage, flags,
3703        pImageFormatProperties);
3704}
3705
3706VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceSparseImageFormatProperties(
3707    VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
3708    VkSampleCountFlagBits samples, VkImageUsageFlags usage,
3709    VkImageTiling tiling, uint32_t *pNumProperties,
3710    VkSparseImageFormatProperties *pProperties) {
3711    struct loader_physical_device *phys_dev =
3712        (struct loader_physical_device *)physicalDevice;
3713    struct loader_icd *icd = phys_dev->this_icd;
3714
3715    if (icd->GetPhysicalDeviceSparseImageFormatProperties)
3716        icd->GetPhysicalDeviceSparseImageFormatProperties(
3717            phys_dev->phys_dev, format, type, samples, usage, tiling,
3718            pNumProperties, pProperties);
3719}
3720
3721VKAPI_ATTR VkResult VKAPI_CALL
3722loader_CreateDevice(VkPhysicalDevice physicalDevice,
3723                    const VkDeviceCreateInfo *pCreateInfo,
3724                    const VkAllocationCallbacks *pAllocator,
3725                    VkDevice *pDevice) {
3726    struct loader_physical_device *phys_dev;
3727    struct loader_icd *icd;
3728    struct loader_device *dev;
3729    struct loader_instance *inst;
3730    struct loader_layer_list activated_layer_list = {0};
3731    VkResult res;
3732
3733    assert(pCreateInfo->queueCreateInfoCount >= 1);
3734
3735    // TODO this only works for one physical device per instance
3736    // once CreateDevice layer bootstrapping is done via DeviceCreateInfo
3737    // hopefully don't need this anymore in trampoline code
3738    phys_dev = loader_get_physical_device(physicalDevice);
3739    icd = phys_dev->this_icd;
3740    if (!icd)
3741        return VK_ERROR_INITIALIZATION_FAILED;
3742
3743    inst = phys_dev->this_instance;
3744
3745    if (!icd->CreateDevice) {
3746        return VK_ERROR_INITIALIZATION_FAILED;
3747    }
3748
3749    /* validate any app enabled layers are available */
3750    if (pCreateInfo->enabledLayerCount > 0) {
3751        res = loader_validate_layers(inst,
3752                                     pCreateInfo->enabledLayerCount,
3753                                     pCreateInfo->ppEnabledLayerNames,
3754                                     &inst->device_layer_list);
3755        if (res != VK_SUCCESS) {
3756            return res;
3757        }
3758    }
3759
3760    /* Get the physical device extensions if they haven't been retrieved yet */
3761    if (phys_dev->device_extension_cache.capacity == 0) {
3762        if (!loader_init_generic_list(
3763                inst,
3764                (struct loader_generic_list *)&phys_dev->device_extension_cache,
3765                sizeof(VkExtensionProperties))) {
3766            return VK_ERROR_OUT_OF_HOST_MEMORY;
3767        }
3768
3769        res = loader_add_device_extensions(
3770            inst, icd, phys_dev->phys_dev,
3771            phys_dev->this_icd->this_icd_lib->lib_name,
3772            &phys_dev->device_extension_cache);
3773        if (res != VK_SUCCESS) {
3774            return res;
3775        }
3776    }
3777
3778    /* fetch a list of all layers activated, explicit and implicit */
3779    res = loader_enable_device_layers(inst, icd, &activated_layer_list,
3780                                      pCreateInfo, &inst->device_layer_list);
3781    if (res != VK_SUCCESS) {
3782        return res;
3783    }
3784
3785    /* make sure requested extensions to be enabled are supported */
3786    res = loader_validate_device_extensions(phys_dev, &activated_layer_list,
3787                                            pCreateInfo);
3788    if (res != VK_SUCCESS) {
3789        loader_destroy_generic_list(
3790            inst, (struct loader_generic_list *)&activated_layer_list);
3791        return res;
3792    }
3793
3794    dev = loader_add_logical_device(inst, &icd->logical_device_list);
3795    if (dev == NULL) {
3796        loader_destroy_generic_list(
3797            inst, (struct loader_generic_list *)&activated_layer_list);
3798        return VK_ERROR_OUT_OF_HOST_MEMORY;
3799    }
3800
3801    /* move the locally filled layer list into the device, and pass ownership of
3802     * the memory */
3803    dev->activated_layer_list.capacity = activated_layer_list.capacity;
3804    dev->activated_layer_list.count = activated_layer_list.count;
3805    dev->activated_layer_list.list = activated_layer_list.list;
3806    memset(&activated_layer_list, 0, sizeof(activated_layer_list));
3807
3808    /* activate any layers on device chain which terminates with device*/
3809    res = loader_enable_device_layers(inst, icd, &dev->activated_layer_list,
3810                                      pCreateInfo, &inst->device_layer_list);
3811    if (res != VK_SUCCESS) {
3812        loader_remove_logical_device(inst, icd, dev);
3813        return res;
3814    }
3815
3816    res = loader_create_device_chain(physicalDevice, pCreateInfo, pAllocator,
3817                                     inst, icd, dev);
3818    if (res != VK_SUCCESS) {
3819        loader_remove_logical_device(inst, icd, dev);
3820        return res;
3821    }
3822
3823    *pDevice = dev->device;
3824
3825    /* initialize any device extension dispatch entry's from the instance list*/
3826    loader_init_dispatch_dev_ext(inst, dev);
3827
3828    /* initialize WSI device extensions as part of core dispatch since loader
3829     * has
3830     * dedicated trampoline code for these*/
3831    loader_init_device_extension_dispatch_table(
3832        &dev->loader_dispatch,
3833        dev->loader_dispatch.core_dispatch.GetDeviceProcAddr, *pDevice);
3834
3835    return res;
3836}
3837
3838/**
3839 * Get an instance level or global level entry point address.
3840 * @param instance
3841 * @param pName
3842 * @return
3843 *    If instance == NULL returns a global level functions only
3844 *    If instance is valid returns a trampoline entry point for all dispatchable
3845 * Vulkan
3846 *    functions both core and extensions.
3847 */
3848LOADER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3849vkGetInstanceProcAddr(VkInstance instance, const char *pName) {
3850
3851    void *addr;
3852
3853    addr = globalGetProcAddr(pName);
3854    if (instance == VK_NULL_HANDLE) {
3855        // get entrypoint addresses that are global (no dispatchable object)
3856
3857        return addr;
3858    } else {
3859        // if a global entrypoint return NULL
3860        if (addr)
3861            return NULL;
3862    }
3863
3864    struct loader_instance *ptr_instance = loader_get_instance(instance);
3865    if (ptr_instance == NULL)
3866        return NULL;
3867    // Return trampoline code for non-global entrypoints including any
3868    // extensions.
3869    // Device extensions are returned if a layer or ICD supports the extension.
3870    // Instance extensions are returned if the extension is enabled and the
3871    // loader
3872    // or someone else supports the extension
3873    return trampolineGetProcAddr(ptr_instance, pName);
3874}
3875
3876/**
3877 * Get a device level or global level entry point address.
3878 * @param device
3879 * @param pName
3880 * @return
3881 *    If device is valid, returns a device relative entry point for device level
3882 *    entry points both core and extensions.
3883 *    Device relative means call down the device chain.
3884 */
3885LOADER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3886vkGetDeviceProcAddr(VkDevice device, const char *pName) {
3887    void *addr;
3888
3889    /* for entrypoints that loader must handle (ie non-dispatchable or create
3890       object)
3891       make sure the loader entrypoint is returned */
3892    addr = loader_non_passthrough_gdpa(pName);
3893    if (addr) {
3894        return addr;
3895    }
3896
3897    /* Although CreateDevice is on device chain it's dispatchable object isn't
3898     * a VkDevice or child of VkDevice so return NULL.
3899     */
3900    if (!strcmp(pName, "CreateDevice"))
3901        return NULL;
3902
3903    /* return the dispatch table entrypoint for the fastest case */
3904    const VkLayerDispatchTable *disp_table = *(VkLayerDispatchTable **)device;
3905    if (disp_table == NULL)
3906        return NULL;
3907
3908    addr = loader_lookup_device_dispatch_table(disp_table, pName);
3909    if (addr)
3910        return addr;
3911
3912    if (disp_table->GetDeviceProcAddr == NULL)
3913        return NULL;
3914    return disp_table->GetDeviceProcAddr(device, pName);
3915}
3916
3917LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
3918vkEnumerateInstanceExtensionProperties(const char *pLayerName,
3919                                       uint32_t *pPropertyCount,
3920                                       VkExtensionProperties *pProperties) {
3921    struct loader_extension_list *global_ext_list = NULL;
3922    struct loader_layer_list instance_layers;
3923    struct loader_extension_list icd_extensions;
3924    struct loader_icd_libs icd_libs;
3925    uint32_t copy_size;
3926
3927    tls_instance = NULL;
3928    memset(&icd_extensions, 0, sizeof(icd_extensions));
3929    memset(&instance_layers, 0, sizeof(instance_layers));
3930    loader_platform_thread_once(&once_init, loader_initialize);
3931
3932    /* get layer libraries if needed */
3933    if (pLayerName && strlen(pLayerName) != 0) {
3934        if (vk_string_validate(MaxLoaderStringLength, pLayerName) == VK_STRING_ERROR_NONE) {
3935            loader_layer_scan(NULL, &instance_layers, NULL);
3936            for (uint32_t i = 0; i < instance_layers.count; i++) {
3937                struct loader_layer_properties *props = &instance_layers.list[i];
3938                if (strcmp(props->info.layerName, pLayerName) == 0) {
3939                   global_ext_list = &props->instance_extension_list;
3940                }
3941            }
3942        } else {
3943            assert(VK_FALSE && "vkEnumerateInstanceExtensionProperties:  pLayerName is too long or is badly formed");
3944            return VK_ERROR_EXTENSION_NOT_PRESENT;
3945        }
3946    } else {
3947        /* Scan/discover all ICD libraries */
3948        memset(&icd_libs, 0, sizeof(struct loader_icd_libs));
3949        loader_icd_scan(NULL, &icd_libs);
3950        /* get extensions from all ICD's, merge so no duplicates */
3951        loader_get_icd_loader_instance_extensions(NULL, &icd_libs,
3952                                                  &icd_extensions);
3953        loader_scanned_icd_clear(NULL, &icd_libs);
3954        global_ext_list = &icd_extensions;
3955    }
3956
3957    if (global_ext_list == NULL) {
3958        loader_destroy_layer_list(NULL, &instance_layers);
3959        return VK_ERROR_LAYER_NOT_PRESENT;
3960    }
3961
3962    if (pProperties == NULL) {
3963        *pPropertyCount = global_ext_list->count;
3964        loader_destroy_layer_list(NULL, &instance_layers);
3965        loader_destroy_generic_list(
3966            NULL, (struct loader_generic_list *)&icd_extensions);
3967        return VK_SUCCESS;
3968    }
3969
3970    copy_size = *pPropertyCount < global_ext_list->count
3971                    ? *pPropertyCount
3972                    : global_ext_list->count;
3973    for (uint32_t i = 0; i < copy_size; i++) {
3974        memcpy(&pProperties[i], &global_ext_list->list[i],
3975               sizeof(VkExtensionProperties));
3976    }
3977    *pPropertyCount = copy_size;
3978    loader_destroy_generic_list(NULL,
3979                                (struct loader_generic_list *)&icd_extensions);
3980
3981    if (copy_size < global_ext_list->count) {
3982        loader_destroy_layer_list(NULL, &instance_layers);
3983        return VK_INCOMPLETE;
3984    }
3985
3986    loader_destroy_layer_list(NULL, &instance_layers);
3987    return VK_SUCCESS;
3988}
3989
3990LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
3991vkEnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
3992                                   VkLayerProperties *pProperties) {
3993
3994    struct loader_layer_list instance_layer_list;
3995    tls_instance = NULL;
3996
3997    loader_platform_thread_once(&once_init, loader_initialize);
3998
3999    uint32_t copy_size;
4000
4001    /* get layer libraries */
4002    memset(&instance_layer_list, 0, sizeof(instance_layer_list));
4003    loader_layer_scan(NULL, &instance_layer_list, NULL);
4004
4005    if (pProperties == NULL) {
4006        *pPropertyCount = instance_layer_list.count;
4007        loader_destroy_layer_list(NULL, &instance_layer_list);
4008        return VK_SUCCESS;
4009    }
4010
4011    copy_size = (*pPropertyCount < instance_layer_list.count)
4012                    ? *pPropertyCount
4013                    : instance_layer_list.count;
4014    for (uint32_t i = 0; i < copy_size; i++) {
4015        memcpy(&pProperties[i], &instance_layer_list.list[i].info,
4016               sizeof(VkLayerProperties));
4017    }
4018
4019    *pPropertyCount = copy_size;
4020    loader_destroy_layer_list(NULL, &instance_layer_list);
4021
4022    if (copy_size < instance_layer_list.count) {
4023        return VK_INCOMPLETE;
4024    }
4025
4026    return VK_SUCCESS;
4027}
4028
4029VKAPI_ATTR VkResult VKAPI_CALL
4030loader_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
4031                                          const char *pLayerName,
4032                                          uint32_t *pPropertyCount,
4033                                          VkExtensionProperties *pProperties) {
4034    struct loader_physical_device *phys_dev;
4035    uint32_t copy_size;
4036
4037    uint32_t count;
4038    struct loader_device_extension_list *dev_ext_list = NULL;
4039    struct loader_layer_list implicit_layer_list;
4040
4041    // TODO fix this aliases physical devices
4042    phys_dev = loader_get_physical_device(physicalDevice);
4043
4044    /* get layer libraries if needed */
4045    if (pLayerName && strlen(pLayerName) != 0) {
4046        if (vk_string_validate(MaxLoaderStringLength, pLayerName) == VK_STRING_ERROR_NONE) {
4047            for (uint32_t i = 0;
4048                i < phys_dev->this_instance->device_layer_list.count; i++) {
4049                struct loader_layer_properties *props =
4050                    &phys_dev->this_instance->device_layer_list.list[i];
4051                if (strcmp(props->info.layerName, pLayerName) == 0) {
4052                   dev_ext_list = &props->device_extension_list;
4053                }
4054            }
4055            count = (dev_ext_list == NULL) ? 0: dev_ext_list->count;
4056            if (pProperties == NULL) {
4057                *pPropertyCount = count;
4058                return VK_SUCCESS;
4059            }
4060
4061            copy_size = *pPropertyCount < count ? *pPropertyCount : count;
4062            for (uint32_t i = 0; i < copy_size; i++) {
4063                memcpy(&pProperties[i], &dev_ext_list->list[i].props,
4064                       sizeof(VkExtensionProperties));
4065            }
4066            *pPropertyCount = copy_size;
4067
4068            if (copy_size < count) {
4069                return VK_INCOMPLETE;
4070            }
4071        } else {
4072            loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4073                "vkEnumerateDeviceExtensionProperties:  pLayerName is too long or is badly formed");
4074            return VK_ERROR_EXTENSION_NOT_PRESENT;
4075        }
4076        return VK_SUCCESS;
4077    } else {
4078        /* this case is during the call down the instance chain with pLayerName
4079         * == NULL*/
4080        struct loader_icd *icd = phys_dev->this_icd;
4081        uint32_t icd_ext_count = *pPropertyCount;
4082        VkResult res;
4083
4084        /* get device extensions */
4085        res = icd->EnumerateDeviceExtensionProperties(
4086            phys_dev->phys_dev, NULL, &icd_ext_count, pProperties);
4087        if (res != VK_SUCCESS)
4088            return res;
4089
4090        loader_init_layer_list(phys_dev->this_instance, &implicit_layer_list);
4091
4092        loader_add_layer_implicit(
4093            phys_dev->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
4094            &implicit_layer_list,
4095            &phys_dev->this_instance->instance_layer_list);
4096        /* we need to determine which implicit layers are active,
4097         * and then add their extensions. This can't be cached as
4098         * it depends on results of environment variables (which can change).
4099         */
4100        if (pProperties != NULL) {
4101            /* initialize dev_extension list within the physicalDevice object */
4102            res = loader_init_device_extensions(
4103                phys_dev->this_instance, phys_dev, icd_ext_count, pProperties,
4104                &phys_dev->device_extension_cache);
4105            if (res != VK_SUCCESS)
4106                return res;
4107
4108            /* we need to determine which implicit layers are active,
4109             * and then add their extensions. This can't be cached as
4110             * it depends on results of environment variables (which can
4111             * change).
4112             */
4113            struct loader_extension_list all_exts = {0};
4114            loader_add_to_ext_list(phys_dev->this_instance, &all_exts,
4115                                   phys_dev->device_extension_cache.count,
4116                                   phys_dev->device_extension_cache.list);
4117
4118            loader_init_layer_list(phys_dev->this_instance,
4119                                   &implicit_layer_list);
4120
4121            loader_add_layer_implicit(
4122                phys_dev->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
4123                &implicit_layer_list,
4124                &phys_dev->this_instance->instance_layer_list);
4125
4126            for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
4127                for (
4128                    uint32_t j = 0;
4129                    j < implicit_layer_list.list[i].device_extension_list.count;
4130                    j++) {
4131                    loader_add_to_ext_list(phys_dev->this_instance, &all_exts,
4132                                           1,
4133                                           &implicit_layer_list.list[i]
4134                                                .device_extension_list.list[j]
4135                                                .props);
4136                }
4137            }
4138            uint32_t capacity = *pPropertyCount;
4139            VkExtensionProperties *props = pProperties;
4140
4141            for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
4142                props[i] = all_exts.list[i];
4143            }
4144            /* wasn't enough space for the extensions, we did partial copy now
4145             * return VK_INCOMPLETE */
4146            if (capacity < all_exts.count) {
4147                res = VK_INCOMPLETE;
4148            } else {
4149                *pPropertyCount = all_exts.count;
4150            }
4151            loader_destroy_generic_list(
4152                phys_dev->this_instance,
4153                (struct loader_generic_list *)&all_exts);
4154        } else {
4155            /* just return the count; need to add in the count of implicit layer
4156             * extensions
4157             * don't worry about duplicates being added in the count */
4158            *pPropertyCount = icd_ext_count;
4159
4160            for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
4161                *pPropertyCount +=
4162                    implicit_layer_list.list[i].device_extension_list.count;
4163            }
4164            res = VK_SUCCESS;
4165        }
4166
4167        loader_destroy_generic_list(
4168            phys_dev->this_instance,
4169            (struct loader_generic_list *)&implicit_layer_list);
4170        return res;
4171    }
4172}
4173
4174VKAPI_ATTR VkResult VKAPI_CALL
4175loader_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
4176                                      uint32_t *pPropertyCount,
4177                                      VkLayerProperties *pProperties) {
4178    uint32_t copy_size;
4179    struct loader_physical_device *phys_dev;
4180    // TODO fix this, aliases physical devices
4181    phys_dev = loader_get_physical_device(physicalDevice);
4182    uint32_t count = phys_dev->this_instance->device_layer_list.count;
4183
4184    if (pProperties == NULL) {
4185        *pPropertyCount = count;
4186        return VK_SUCCESS;
4187    }
4188
4189    copy_size = (*pPropertyCount < count) ? *pPropertyCount : count;
4190    for (uint32_t i = 0; i < copy_size; i++) {
4191        memcpy(&pProperties[i],
4192               &(phys_dev->this_instance->device_layer_list.list[i].info),
4193               sizeof(VkLayerProperties));
4194    }
4195    *pPropertyCount = copy_size;
4196
4197    if (copy_size < count) {
4198        return VK_INCOMPLETE;
4199    }
4200
4201    return VK_SUCCESS;
4202}
4203
4204VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8)
4205{
4206    VkStringErrorFlags result = VK_STRING_ERROR_NONE;
4207    int                num_char_bytes;
4208    int                i,j;
4209
4210    for (i = 0; i < max_length; i++)
4211    {
4212        if (utf8[i] == 0) {
4213            break;
4214        } else if ((utf8[i] > 0x20) && (utf8[i] < 0x7f)) {
4215            num_char_bytes = 0;
4216        } else if ((utf8[i] & UTF8_ONE_BYTE_MASK)   == UTF8_ONE_BYTE_CODE) {
4217            num_char_bytes = 1;
4218        } else if ((utf8[i] & UTF8_TWO_BYTE_MASK)   == UTF8_TWO_BYTE_CODE)   {
4219            num_char_bytes = 2;
4220        } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
4221            num_char_bytes = 3;
4222        } else {
4223            result = VK_STRING_ERROR_BAD_DATA;
4224        }
4225
4226        // Validate the following num_char_bytes of data
4227        for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
4228            if (++i == max_length) {
4229                result |= VK_STRING_ERROR_LENGTH;
4230                break;
4231            }
4232            if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
4233                result |= VK_STRING_ERROR_BAD_DATA;
4234            }
4235        }
4236    }
4237    return result;
4238}
4239
4240