loader.c revision b3e934dd44eaf3fb9c74c1789e8d7ac71918a8b6
1b1928704201034c785a26296a49f69355eb56a05Nick Lewycky/*
2b1928704201034c785a26296a49f69355eb56a05Nick Lewycky *
3b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Copyright (C) 2015 Valve Corporation
4b1928704201034c785a26296a49f69355eb56a05Nick Lewycky *
5b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Permission is hereby granted, free of charge, to any person obtaining a
6b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * copy of this software and associated documentation files (the "Software"),
7b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * to deal in the Software without restriction, including without limitation
8b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * and/or sell copies of the Software, and to permit persons to whom the
10b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Software is furnished to do so, subject to the following conditions:
11b1928704201034c785a26296a49f69355eb56a05Nick Lewycky *
12b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * The above copyright notice and this permission notice shall be included
13b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * in all copies or substantial portions of the Software.
14b1928704201034c785a26296a49f69355eb56a05Nick Lewycky *
15b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * DEALINGS IN THE SOFTWARE.
22b1928704201034c785a26296a49f69355eb56a05Nick Lewycky *
2306cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth * Author: Chia-I Wu <olvaffe@gmail.com>
24b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
25b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Author: Ian Elliott <ian@LunarG.com>
26b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Author: Jon Ashburn <jon@lunarg.com>
27d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth *
280b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth */
290b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth
300b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#define _GNU_SOURCE
31d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include <stdio.h>
32a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include <stdlib.h>
3306cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth#include <stdarg.h>
3406cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth#include <stdbool.h>
3539c41c3c93e0d223792acb093adce21a714b01c6Bill Wendling#include <string.h>
3606cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth
37a11c3e25015a62c817e60ec4f955a7f3f3bb6c67Rafael Espindola#include <sys/types.h>
3806cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth#if defined(_WIN32)
3906cb8ed00696eb14d1b831921452e50ec0568ea2Chandler Carruth#include "dirent_on_windows.h"
40c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky#else // _WIN32
41b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include <dirent.h>
42b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif // _WIN32
43b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include "vk_loader_platform.h"
44b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#include "loader.h"
45a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "gpa_helper.h"
46a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "table_ops.h"
47a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "debug_report.h"
48a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "wsi.h"
49a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "vulkan/vk_icd.h"
50a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "cJSON.h"
51a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#include "murmurhash.h"
52a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
53a204ef3168c8804808c716115ba915c89d8849b9Nick Lewyckystatic loader_platform_dl_handle loader_add_layer_lib(
54a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        const struct loader_instance *inst,
55a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        const char *chain_type,
56a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        struct loader_layer_properties *layer_prop);
57a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
58a204ef3168c8804808c716115ba915c89d8849b9Nick Lewyckystatic void loader_remove_layer_lib(
59a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        struct loader_instance *inst,
60a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        struct loader_layer_properties *layer_prop);
61a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
62a204ef3168c8804808c716115ba915c89d8849b9Nick Lewyckystruct loader_struct loader = {0};
63a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky// TLS for instance for alloc/free callbacks
64a204ef3168c8804808c716115ba915c89d8849b9Nick LewyckyTHREAD_LOCAL_DECL struct loader_instance *tls_instance;
65b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
66b1928704201034c785a26296a49f69355eb56a05Nick Lewyckystatic bool loader_init_generic_list(
67b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        const struct loader_instance *inst,
68b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        struct loader_generic_list *list_info,
69a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        size_t element_size);
70a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
71a204ef3168c8804808c716115ba915c89d8849b9Nick Lewyckystatic int loader_platform_combine_path(char *dest, int len, ...);
72a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
73a204ef3168c8804808c716115ba915c89d8849b9Nick Lewyckystruct loader_phys_dev_per_icd {
74a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    uint32_t count;
75a61e52c9b7cf874b46cef687c1c4627a35952542Nick Lewycky    VkPhysicalDevice *phys_devs;
76a61e52c9b7cf874b46cef687c1c4627a35952542Nick Lewycky};
77a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
78a204ef3168c8804808c716115ba915c89d8849b9Nick Lewyckyenum loader_debug {
79a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    LOADER_INFO_BIT       = 0x01,
80a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    LOADER_WARN_BIT       = 0x02,
81a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    LOADER_PERF_BIT       = 0x04,
82a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    LOADER_ERROR_BIT      = 0x08,
83a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    LOADER_DEBUG_BIT      = 0x10,
84a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky};
85b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
86b1928704201034c785a26296a49f69355eb56a05Nick Lewyckyuint32_t g_loader_debug = 0;
87b1928704201034c785a26296a49f69355eb56a05Nick Lewyckyuint32_t g_loader_log_msgs = 0;
88b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
89b1928704201034c785a26296a49f69355eb56a05Nick Lewycky//thread safety lock for accessing global data structures such as "loader"
90a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky// all entrypoints on the instance chain need to be locked except GPA
91b1928704201034c785a26296a49f69355eb56a05Nick Lewycky// additionally CreateDevice and DestroyDevice needs to be locked
92269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewyckyloader_platform_thread_mutex loader_lock;
93269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewyckyloader_platform_thread_mutex loader_json_lock;
9464a0a33307723957bf2f15e3181a290853c6f833Nick Lewycky
9564a0a33307723957bf2f15e3181a290853c6f833Nick Lewycky// This table contains the loader's instance dispatch table, which contains
96b1928704201034c785a26296a49f69355eb56a05Nick Lewycky// default functions if no instance layers are activated.  This contains
970c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky// pointers to "terminator functions".
980c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewyckyconst VkLayerInstanceDispatchTable instance_disp = {
99f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    .GetInstanceProcAddr = vkGetInstanceProcAddr,
1000c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky    .CreateInstance = loader_CreateInstance,
101b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .DestroyInstance = loader_DestroyInstance,
102b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
10377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
104b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .GetPhysicalDeviceFormatProperties = loader_GetPhysicalDeviceFormatProperties,
105b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .GetPhysicalDeviceImageFormatProperties = loader_GetPhysicalDeviceImageFormatProperties,
10618764716861243c58a711a92190624dc2f6aafc9Bill Wendling    .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
107d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    .GetPhysicalDeviceQueueFamilyProperties = loader_GetPhysicalDeviceQueueFamilyProperties,
108b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
109b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .EnumerateDeviceExtensionProperties = loader_EnumerateDeviceExtensionProperties,
1101790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .EnumerateDeviceLayerProperties = loader_EnumerateDeviceLayerProperties,
1111790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
1121790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .DestroySurfaceKHR = loader_DestroySurfaceKHR,
1131790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .GetPhysicalDeviceSurfaceSupportKHR = loader_GetPhysicalDeviceSurfaceSupportKHR,
1141790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .GetPhysicalDeviceSurfaceCapabilitiesKHR = loader_GetPhysicalDeviceSurfaceCapabilitiesKHR,
1151790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .GetPhysicalDeviceSurfaceFormatsKHR = loader_GetPhysicalDeviceSurfaceFormatsKHR,
1161790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .GetPhysicalDeviceSurfacePresentModesKHR = loader_GetPhysicalDeviceSurfacePresentModesKHR,
1171790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
11864a0a33307723957bf2f15e3181a290853c6f833Nick Lewycky    .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
11964a0a33307723957bf2f15e3181a290853c6f833Nick Lewycky#ifdef VK_USE_PLATFORM_MIR_KHR
1201790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    .CreateMirSurfaceKHR = loader_CreateMirSurfaceKHR,
121b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .GetPhysicalDeviceMirPresentationSupportKHR = loader_GetPhysicalDeviceMirPresentationSupportKHR,
122b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
123d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling#ifdef VK_USE_PLATFORM_WAYLAND_KHR
124d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    .CreateWaylandSurfaceKHR = loader_CreateWaylandSurfaceKHR,
125d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    .GetPhysicalDeviceWaylandPresentationSupportKHR = loader_GetPhysicalDeviceWaylandPresentationSupportKHR,
12677b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling#endif
127b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#ifdef VK_USE_PLATFORM_WIN32_KHR
128f2a2806baf3763d551a9f361124b608b2eed66faBill Wendling    .CreateWin32SurfaceKHR = loader_CreateWin32SurfaceKHR,
129269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky    .GetPhysicalDeviceWin32PresentationSupportKHR = loader_GetPhysicalDeviceWin32PresentationSupportKHR,
130a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#endif
131a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky#ifdef VK_USE_PLATFORM_XCB_KHR
132a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    .CreateXcbSurfaceKHR = loader_CreateXcbSurfaceKHR,
133a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    .GetPhysicalDeviceXcbPresentationSupportKHR = loader_GetPhysicalDeviceXcbPresentationSupportKHR,
134a61e52c9b7cf874b46cef687c1c4627a35952542Nick Lewycky#endif
1351790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky#ifdef VK_USE_PLATFORM_XLIB_KHR
136b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .CreateXlibSurfaceKHR = loader_CreateXlibSurfaceKHR,
137b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .GetPhysicalDeviceXlibPresentationSupportKHR = loader_GetPhysicalDeviceXlibPresentationSupportKHR,
138b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
139b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#ifdef VK_USE_PLATFORM_ANDROID_KHR
140b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    .CreateAndroidSurfaceKHR = loader_CreateAndroidSurfaceKHR,
141b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif
142b1928704201034c785a26296a49f69355eb56a05Nick Lewycky};
143b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
144a204ef3168c8804808c716115ba915c89d8849b9Nick LewyckyLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
145a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
146a61e52c9b7cf874b46cef687c1c4627a35952542Nick Lewyckyvoid* loader_heap_alloc(
147b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    const struct loader_instance     *instance,
1485d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky    size_t                            size,
1495d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky    VkSystemAllocationScope           alloc_scope)
1505d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky{
1515d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky    if (instance && instance->alloc_callbacks.pfnAllocation) {
1525d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky        /* TODO: What should default alignment be? 1, 4, 8, other? */
1535d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky        return instance->alloc_callbacks.pfnAllocation(instance->alloc_callbacks.pUserData, size, 4, alloc_scope);
154b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    }
155b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    return malloc(size);
156b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
157d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper
158d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Toppervoid loader_heap_free(
159d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper    const struct loader_instance   *instance,
160d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper    void                           *pMemory)
161b1928704201034c785a26296a49f69355eb56a05Nick Lewycky{
162b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (pMemory == NULL) return;
163b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (instance && instance->alloc_callbacks.pfnFree) {
1641790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMemory);
1651790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        return;
166b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    }
167b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    free(pMemory);
1681790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky}
1691790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
170b1928704201034c785a26296a49f69355eb56a05Nick Lewyckyvoid* loader_heap_realloc(
171b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    const struct loader_instance *instance,
172b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    void                       *pMemory,
173b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    size_t                      orig_size,
174619850cb3161733e9284ff3bf9a68d1a3b76f0b4Craig Topper    size_t                      size,
175b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    VkSystemAllocationScope          alloc_scope)
17617df2c3240837b4382898ead8c3ead407a338520Nick Lewycky{
17717df2c3240837b4382898ead8c3ead407a338520Nick Lewycky    if (pMemory == NULL  || orig_size == 0)
178d363ff334d796c7f3df834d928a10d88ed758454Nick Lewycky        return loader_heap_alloc(instance, size, alloc_scope);
179b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (size == 0) {
180b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        loader_heap_free(instance, pMemory);
1811790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        return NULL;
1821790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    }
1831790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    if (instance && instance->alloc_callbacks.pfnAllocation) {
1841790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        if (size <= orig_size) {
185b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            memset(((uint8_t *)pMemory) + size,  0, orig_size - size);
186b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            return pMemory;
1877a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky        }
1887a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky        void *new_ptr = instance->alloc_callbacks.pfnAllocation(instance->alloc_callbacks.pUserData, size, 4, alloc_scope);
1897a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky        if (!new_ptr)
190b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            return NULL;
191b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        memcpy(new_ptr, pMemory, orig_size);
192b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMemory);
193b1928704201034c785a26296a49f69355eb56a05Nick Lewycky	return new_ptr;
194d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper    }
195d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper    return realloc(pMemory, size);
196d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper}
197d6d6a97c3c41395dfed46572b69fb6a5d67a5a8bCraig Topper
198b1928704201034c785a26296a49f69355eb56a05Nick Lewyckyvoid *loader_tls_heap_alloc(size_t size)
199b1928704201034c785a26296a49f69355eb56a05Nick Lewycky{
200b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    return loader_heap_alloc(tls_instance, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
201b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
202b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
20316c19a155c65fd41865562fe4e678ef32728510bDevang Patelvoid loader_tls_heap_free(void *pMemory)
20416c19a155c65fd41865562fe4e678ef32728510bDevang Patel{
205b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    loader_heap_free(tls_instance, pMemory);
206b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
2071790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
2081790c9cbb6714e81eab1412909a2320acaecc43bNick Lewyckystatic void loader_log(VkFlags msg_type, int32_t msg_code,
209b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    const char *format, ...)
210b1928704201034c785a26296a49f69355eb56a05Nick Lewycky{
211619850cb3161733e9284ff3bf9a68d1a3b76f0b4Craig Topper    char msg[512];
212bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    va_list ap;
21316c19a155c65fd41865562fe4e678ef32728510bDevang Patel    int ret;
214b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
215b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (!(msg_type & g_loader_log_msgs)) {
21616c19a155c65fd41865562fe4e678ef32728510bDevang Patel        return;
21716c19a155c65fd41865562fe4e678ef32728510bDevang Patel    }
21816c19a155c65fd41865562fe4e678ef32728510bDevang Patel
21916c19a155c65fd41865562fe4e678ef32728510bDevang Patel    va_start(ap, format);
22016c19a155c65fd41865562fe4e678ef32728510bDevang Patel    ret = vsnprintf(msg, sizeof(msg), format, ap);
22116c19a155c65fd41865562fe4e678ef32728510bDevang Patel    if ((ret >= (int) sizeof(msg)) || ret < 0) {
222b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        msg[sizeof(msg)-1] = '\0';
22316c19a155c65fd41865562fe4e678ef32728510bDevang Patel    }
22416c19a155c65fd41865562fe4e678ef32728510bDevang Patel    va_end(ap);
225b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
226b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#if defined(WIN32)
227b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    OutputDebugString(msg);
228680018ff8965610b3f1c976b0be1dfd45116b218Devang Patel    OutputDebugString("\n");
22916c19a155c65fd41865562fe4e678ef32728510bDevang Patel#endif
2301790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    fputs(msg, stderr);
231b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    fputc('\n', stderr);
232b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
233c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky
234c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky#if defined(WIN32)
235c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewyckystatic char *loader_get_next_path(char *path);
236c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky/**
237c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky* Find the list of registry files (names within a key) in key "location".
238c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky*
239c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
240c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky* for a list or name/values which are added to a returned list (function return value).
241c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky* The DWORD values within the key must be 0 or they are skipped.
242b1928704201034c785a26296a49f69355eb56a05Nick Lewycky* Function return is a string with a ';'  separated list of filenames.
243b1928704201034c785a26296a49f69355eb56a05Nick Lewycky* Function return is NULL if no valid name/value pairs  are found in the key,
244b1928704201034c785a26296a49f69355eb56a05Nick Lewycky* or the key is not found.
245b1928704201034c785a26296a49f69355eb56a05Nick Lewycky*
246b1928704201034c785a26296a49f69355eb56a05Nick Lewycky* \returns
24768155d31cd0175be89e26ee68387cb411fca537bDevang Patel* A string list of filenames as pointer.
2481790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky* When done using the returned string list, pointer should be freed.
2491790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky*/
25016c19a155c65fd41865562fe4e678ef32728510bDevang Patelstatic char *loader_get_registry_files(const struct loader_instance *inst, char *location)
251b1928704201034c785a26296a49f69355eb56a05Nick Lewycky{
2521790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    LONG rtn_value;
253b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    HKEY hive, key;
254b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    DWORD access_flags;
2551790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    char name[2048];
2561790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    char *out = NULL;
257b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    char *loc = location;
258b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    char *next;
2591790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    DWORD idx = 0;
2601790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    DWORD name_size = sizeof(name);
261c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky    DWORD value;
2621790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    DWORD total_size = 4096;
2631790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    DWORD value_size = sizeof(value);
26416c19a155c65fd41865562fe4e678ef32728510bDevang Patel
265c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky    while(*loc)
266b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    {
267b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        next = loader_get_next_path(loc);
2681790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        hive = DEFAULT_VK_REGISTRY_HIVE;
2691790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        access_flags = KEY_QUERY_VALUE;
2701790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
271c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky        if (rtn_value != ERROR_SUCCESS) {
272c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky            // We didn't find the key.  Try the 32-bit hive (where we've seen the
273c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky            // key end up on some people's systems):
2746227d5c690504c7ada5780c00a635b282c46e275Craig Topper            access_flags |= KEY_WOW64_32KEY;
275c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky            rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
276c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky            if (rtn_value != ERROR_SUCCESS) {
277c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky                // We still couldn't find the key, so give up:
2781790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                loc = next;
2791790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                continue;
280b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            }
281b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        }
282b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
2831790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
284b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            if (value_size == sizeof(value) && value == 0) {
285b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                if (out == NULL) {
286b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                    out = loader_heap_alloc(inst, total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
287b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                    out[0] = '\0';
288b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                }
2891790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                else if (strlen(out) + name_size + 1 > total_size) {
2901790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    out = loader_heap_realloc(inst, out, total_size, total_size * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
291b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                    total_size *= 2;
292b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                }
293b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                if (out == NULL) {
2941790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
2951790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    return NULL;
2961790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                }
297b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                if (strlen(out) == 0)
298b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                     snprintf(out, name_size + 1, "%s", name);
299b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                else
300b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                     snprintf(out + strlen(out), name_size + 2, "%c%s", PATH_SEPERATOR, name);
301b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            }
302b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            name_size = 2048;
303b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        }
304d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky        loc = next;
305a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky    }
306b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
307b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    return out;
308b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
309bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky
310b1928704201034c785a26296a49f69355eb56a05Nick Lewycky#endif // WIN32
311b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
3121790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky/**
313b1928704201034c785a26296a49f69355eb56a05Nick Lewycky * Combine path elements, separating each element with the platform-specific
3141790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * directory separator, and save the combined string to a destination buffer,
3151790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * not exceeding the given length. Path elements are given as variadic args,
3161790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * with a NULL element terminating the list.
3175d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky *
3181790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * \returns the total length of the combined string, not including an ASCII
319a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky * NUL termination character. This length may exceed the available storage:
320bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky * in this case, the written string will be truncated to avoid a buffer
3211790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * overrun, and the return value will greater than or equal to the storage
3221790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * size. A NULL argument may be provided as the destination buffer in order
323bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky * to determine the required string length without actually writing a string.
324a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky */
325bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky
3265d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewyckystatic int loader_platform_combine_path(char *dest, int len, ...)
3271790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky{
3281790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    int required_len = 0;
329b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    va_list ap;
330b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    const char *component;
331b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
3321790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    va_start(ap, len);
3331790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
334b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    while((component = va_arg(ap, const char *))) {
335b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        if (required_len > 0) {
3361790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            // This path element is not the first non-empty element; prepend
3371790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            // a directory separator if space allows
338b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            if (dest && required_len + 1 < len) {
339b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                snprintf(dest + required_len, len - required_len, "%c",
3401790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                         DIRECTORY_SYMBOL);
3411790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            }
342a4c4c0e1298f4dd9791eff2bae857e7be6d0ab56Nick Lewycky            required_len++;
343a4c4c0e1298f4dd9791eff2bae857e7be6d0ab56Nick Lewycky        }
3441790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
345b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        if (dest && required_len < len) {
3461790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            strncpy(dest + required_len, component, len - required_len);
3471790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        }
3481790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        required_len += strlen(component);
3491790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    }
350b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
351bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    va_end(ap);
352b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
353b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    // strncpy(3) won't add a NUL terminating byte in the event of truncation.
354c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky    if (dest && required_len >= len) {
355c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky        dest[len - 1] = '\0';
356c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky    }
357c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky
3581790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    return required_len;
3591790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky}
3601790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
3611790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
3621790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky/**
3631790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky * Given string of three part form "maj.min.pat" convert to a vulkan version
364bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky * number.
365bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky */
3661790c9cbb6714e81eab1412909a2320acaecc43bNick Lewyckystatic uint32_t loader_make_version(const char *vers_str)
3671790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky{
368b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    uint32_t vers = 0, major=0, minor=0, patch=0;
369b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    char *minor_str= NULL;
370b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    char *patch_str = NULL;
371b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    char *cstr;
372c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky    char *str;
373c4e6b540f05932eea37ca10b6c1fded522777954Nick Lewycky
374b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (!vers_str)
375b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        return vers;
376b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    cstr = loader_stack_alloc(strlen(vers_str) + 1);
377b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    strcpy(cstr, vers_str);
3781790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    while ((str = strchr(cstr, '.')) != NULL) {
3791790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        if (minor_str == NULL) {
380b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            minor_str = str + 1;
381b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            *str = '\0';
382b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            major = atoi(cstr);
383f2a2806baf3763d551a9f361124b608b2eed66faBill Wendling        }
384269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky        else if (patch_str == NULL) {
385269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky            patch_str = str + 1;
386269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky            *str = '\0';
387269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky            minor = atoi(minor_str);
388fcf74ed5a2bc10570dec2084a2db1f6580b1210dNick Lewycky        }
389269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky        else {
390fcf74ed5a2bc10570dec2084a2db1f6580b1210dNick Lewycky            return vers;
391fcf74ed5a2bc10570dec2084a2db1f6580b1210dNick Lewycky        }
3926e5190c193f6267893daf6943af88e95039e739cBill Wendling        cstr = str + 1;
3936e5190c193f6267893daf6943af88e95039e739cBill Wendling    }
3946e5190c193f6267893daf6943af88e95039e739cBill Wendling    patch = atoi(patch_str);
395fcf74ed5a2bc10570dec2084a2db1f6580b1210dNick Lewycky
396269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky    return VK_MAKE_VERSION(major, minor, patch);
397269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky
398fcf74ed5a2bc10570dec2084a2db1f6580b1210dNick Lewycky}
3996e5190c193f6267893daf6943af88e95039e739cBill Wendling
400fcf74ed5a2bc10570dec2084a2db1f6580b1210dNick Lewyckybool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
40139c41c3c93e0d223792acb093adce21a714b01c6Bill Wendling{
40239c41c3c93e0d223792acb093adce21a714b01c6Bill Wendling    return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
40339c41c3c93e0d223792acb093adce21a714b01c6Bill Wendling}
40439c41c3c93e0d223792acb093adce21a714b01c6Bill Wendling
40539c41c3c93e0d223792acb093adce21a714b01c6Bill Wendling/**
406269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky * Search the given ext_array for an extension
407269687fa350c1aa044bc063c64362a04ecabaa33Nick Lewycky * matching the given vk_ext_prop
4080c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky */
4091790c9cbb6714e81eab1412909a2320acaecc43bNick Lewyckybool has_vk_extension_property_array(
4100c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky        const VkExtensionProperties *vk_ext_prop,
4110c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky        const uint32_t count,
412a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        const VkExtensionProperties *ext_array)
413a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky{
414a61e52c9b7cf874b46cef687c1c4627a35952542Nick Lewycky    for (uint32_t i = 0; i < count; i++) {
4150c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky        if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
4160c4de8a4eb5fd6437b571611794ef84427fc4755Nick Lewycky            return true;
41764a0a33307723957bf2f15e3181a290853c6f833Nick Lewycky    }
418f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    return false;
419bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky}
420bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky
421bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky/**
422bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky * Search the given ext_list for an extension
423bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky * matching the given vk_ext_prop
424bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky */
425bba40db07234cef7867b45c67f50632e684cbb15Nick Lewyckybool has_vk_extension_property(
426bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        const VkExtensionProperties *vk_ext_prop,
427bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        const struct loader_extension_list *ext_list)
428f2a2806baf3763d551a9f361124b608b2eed66faBill Wendling{
429c1b49b56d4132efa2e06deb8f23508d0de4c8800Rafael Espindola    for (uint32_t i = 0; i < ext_list->count; i++) {
430d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky        if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop))
431a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky            return true;
432d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky    }
433bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    return false;
434bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky}
435bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky
436bba40db07234cef7867b45c67f50632e684cbb15Nick Lewyckystatic inline bool loader_is_layer_type_device(const enum layer_type type) {
437cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren    if ((type & VK_LAYER_TYPE_DEVICE_EXPLICIT) ||
438cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren                (type & VK_LAYER_TYPE_DEVICE_IMPLICIT))
439cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren        return true;
440cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren    return false;
441bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky}
442bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky
443bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky/*
444a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky * Search the given layer list for a layer matching the given layer name
445bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky */
446bba40db07234cef7867b45c67f50632e684cbb15Nick Lewyckystatic struct loader_layer_properties *loader_get_layer_property(
447bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        const char *name,
448bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        const struct loader_layer_list *layer_list)
449bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky{
450bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    for (uint32_t i = 0; i < layer_list->count; i++) {
451bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        const VkLayerProperties *item = &layer_list->list[i].info;
452f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        if (strcmp(name, item->layerName) == 0)
453bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky            return &layer_list->list[i];
454bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    }
455bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    return NULL;
456bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky}
457bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky
458bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky/**
459bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky * Get the next unused layer property in the list. Init the property to zero.
460bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky */
461bba40db07234cef7867b45c67f50632e684cbb15Nick Lewyckystatic struct loader_layer_properties *loader_get_next_layer_property(
462bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky                                           const struct loader_instance *inst,
463bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky                                           struct loader_layer_list *layer_list)
464bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky{
465bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky    if (layer_list->capacity == 0) {
466bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        layer_list->list = loader_heap_alloc(inst,
467bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky                                  sizeof(struct loader_layer_properties) * 64,
468b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                  VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
469b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        if (layer_list->list == NULL) {
470bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't add any layer properties to list");
471b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            return NULL;
472bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        }
473bba40db07234cef7867b45c67f50632e684cbb15Nick Lewycky        memset(layer_list->list, 0, sizeof(struct loader_layer_properties) * 64);
474b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
475b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    }
476b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
477f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    // ensure enough room to add an entry
478f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    if ((layer_list->count + 1) * sizeof (struct loader_layer_properties)
479f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel            > layer_list->capacity) {
480f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        layer_list->list = loader_heap_realloc(inst, layer_list->list,
481f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                                            layer_list->capacity,
48277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling                                            layer_list->capacity * 2,
483f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
484f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        if (layer_list->list == NULL) {
485f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel            loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
486f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                            "realloc failed for layer list");
487f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        }
488f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        layer_list->capacity *= 2;
489cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren    }
490cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren
491cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren    layer_list->count++;
492cbafae6d33031a72ba8219c28cb0e852511f79a3Manman Ren    return &(layer_list->list[layer_list->count - 1]);
493f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel}
494f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
495f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel/**
496f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel * Remove all layer properties entrys from the list
497f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel */
498f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patelvoid loader_delete_layer_properties(
499f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                        const struct loader_instance *inst,
500f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                        struct loader_layer_list *layer_list)
501f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel{
502f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    uint32_t i, j;
503f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    struct loader_device_extension_list *dev_ext_list;
504f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    if (!layer_list)
505f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        return;
5061790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
507f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    for (i = 0; i < layer_list->count; i++) {
5081790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        loader_destroy_generic_list(inst, (struct loader_generic_list *)
509b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                   &layer_list->list[i].instance_extension_list);
5101790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        dev_ext_list = &layer_list->list[i].device_extension_list;
511ce718ff9f42c7da092eaa01dd0242e8d5ba84713Hans Wennborg        if (dev_ext_list->capacity > 0 && dev_ext_list->list->entrypoint_count > 0) {
512f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel            for (j= 0; j < dev_ext_list->list->entrypoint_count; j++) {
513f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                loader_heap_free(inst, dev_ext_list->list->entrypoints[j]);
514f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel            }
515f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel            loader_heap_free(inst, dev_ext_list->list->entrypoints);
516f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        }
517f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        loader_destroy_generic_list(inst, (struct loader_generic_list *)
518f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel                                   dev_ext_list);
519f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    }
520f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    layer_list->count = 0;
521f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
522f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    if (layer_list->capacity > 0) {
523f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        layer_list->capacity = 0;
524f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        loader_heap_free(inst, layer_list->list);
525f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    }
526f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
527f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel}
528bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky
529f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patelstatic void loader_add_global_extensions(
530f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        const struct loader_instance *inst,
531bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky        const PFN_vkEnumerateInstanceExtensionProperties fp_get_props,
532bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky        const char *lib_name,
533bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky        struct loader_extension_list *ext_list)
534f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel{
535bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky    uint32_t i, count;
536f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    VkExtensionProperties *ext_props;
537f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    VkResult res;
538f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
539bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky    if (!fp_get_props) {
540f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        /* No EnumerateInstanceExtensionProperties defined */
541f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        return;
542f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    }
543f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
544f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    res = fp_get_props(NULL, &count, NULL);
545f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    if (res != VK_SUCCESS) {
546f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
547b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        return;
548b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    }
549f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
550f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    if (count == 0) {
551f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        /* No ExtensionProperties to report */
5521790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        return;
5531790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    }
554f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
555f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
556f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
557f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    res = fp_get_props(NULL, &count, ext_props);
558bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky    if (res != VK_SUCCESS) {
559f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
560f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        return;
561f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    }
56277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
56377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    for (i = 0; i < count; i++) {
564f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        char spec_version[64];
565f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
5661790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
5671790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                 VK_MAJOR(ext_props[i].specVersion),
568c7a884040e4ec7795515978a94803894ad08c4caBill Wendling                 VK_MINOR(ext_props[i].specVersion),
569c7a884040e4ec7795515978a94803894ad08c4caBill Wendling                 VK_PATCH(ext_props[i].specVersion));
57077b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
57177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling                   "Global Extension: %s (%s) version %s",
57277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling                   ext_props[i].extensionName, lib_name, spec_version);
573f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
574b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    }
575b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
5764a8fefaf8303f30514bc2a40d840a1709dae65cfBill Wendling    return;
577d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling}
578d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling
579d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling/*
580d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling * Initialize ext_list with the physical device extensions.
58118764716861243c58a711a92190624dc2f6aafc9Bill Wendling * The extension properties are passed as inputs in count and ext_props.
58218764716861243c58a711a92190624dc2f6aafc9Bill Wendling */
583d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendlingstatic VkResult loader_init_physical_device_extensions(
584d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        const struct loader_instance *inst,
585d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        struct loader_physical_device *phys_dev,
586d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        uint32_t count,
587d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        VkExtensionProperties *ext_props,
588d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        struct loader_extension_list *ext_list)
589d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling{
590d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    VkResult res;
591d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    uint32_t i;
592d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling
593d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    if (!loader_init_generic_list(inst, (struct loader_generic_list *) ext_list,
594d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling                                  sizeof(VkExtensionProperties))) {
595d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        return VK_ERROR_OUT_OF_HOST_MEMORY;
5968640c6a5227b75666e02424e2181289692138348Bill Wendling    }
5978640c6a5227b75666e02424e2181289692138348Bill Wendling
5988640c6a5227b75666e02424e2181289692138348Bill Wendling    for (i = 0; i < count; i++) {
5998640c6a5227b75666e02424e2181289692138348Bill Wendling        char spec_version[64];
6008640c6a5227b75666e02424e2181289692138348Bill Wendling
6018640c6a5227b75666e02424e2181289692138348Bill Wendling        snprintf(spec_version, sizeof (spec_version), "%d.%d.%d",
6028640c6a5227b75666e02424e2181289692138348Bill Wendling                VK_MAJOR(ext_props[i].specVersion),
6038640c6a5227b75666e02424e2181289692138348Bill Wendling                VK_MINOR(ext_props[i].specVersion),
6048640c6a5227b75666e02424e2181289692138348Bill Wendling                VK_PATCH(ext_props[i].specVersion));
6058640c6a5227b75666e02424e2181289692138348Bill Wendling        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
606d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling                "PhysicalDevice Extension: %s (%s) version %s",
607d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling                ext_props[i].extensionName, phys_dev->this_icd->this_icd_lib->lib_name, spec_version);
608d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
609b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        if (res != VK_SUCCESS)
61077b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling            return res;
61177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    }
61277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
61377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    return VK_SUCCESS;
614f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel}
615b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
616b1928704201034c785a26296a49f69355eb56a05Nick Lewyckystatic VkResult loader_add_physical_device_extensions(
6171790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        const struct loader_instance *inst,
6181790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        VkPhysicalDevice physical_device,
6191790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        const char *lib_name,
6201790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        struct loader_extension_list *ext_list)
6211790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky{
6221790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    uint32_t i, count;
6231790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    VkResult res;
6241790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    VkExtensionProperties *ext_props;
6251790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
6261790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    res = loader_EnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
6271790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    if (res == VK_SUCCESS && count > 0) {
6281790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        ext_props = loader_stack_alloc(count * sizeof (VkExtensionProperties));
6299e6ee16b1814268897965b81e82a74ef39173ee1Benjamin Kramer        if (!ext_props)
630db125cfaf57cc83e7dd7453de2d509bc8efd0e5eChris Lattner            return VK_ERROR_OUT_OF_HOST_MEMORY;
6319e6ee16b1814268897965b81e82a74ef39173ee1Benjamin Kramer        res = loader_EnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
6321790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        if (res != VK_SUCCESS)
6339e6ee16b1814268897965b81e82a74ef39173ee1Benjamin Kramer            return res;
6341790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        for (i = 0; i < count; i++) {
6359e6ee16b1814268897965b81e82a74ef39173ee1Benjamin Kramer            char spec_version[64];
6361790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
6371790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            snprintf(spec_version, sizeof (spec_version), "%d.%d.%d",
6381790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    VK_MAJOR(ext_props[i].specVersion),
6391790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    VK_MINOR(ext_props[i].specVersion),
6401790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    VK_PATCH(ext_props[i].specVersion));
6411790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
6427a2ba2fbe4b0ccaacc2cedbc1bfd2a3764170efeNick Lewycky                    "PhysicalDevice Extension: %s (%s) version %s",
6431790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                    ext_props[i].extensionName, lib_name, spec_version);
6441790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
645bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky            if (res != VK_SUCCESS)
646bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky                return res;
6471790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        }
6481790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    } else {
6491790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from library %s", lib_name);
6501790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        return res;
6511790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    }
6521790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
6531790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    return VK_SUCCESS;
6541790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky}
6559e6ee16b1814268897965b81e82a74ef39173ee1Benjamin Kramer
6561790c9cbb6714e81eab1412909a2320acaecc43bNick Lewyckystatic bool loader_init_generic_list(const struct loader_instance *inst,
6571790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                                     struct loader_generic_list *list_info,
6581790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                                     size_t element_size)
659267010864e139781ef5949939e081c41f954de0aJay Foad{
6601790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    list_info->capacity = 32 * element_size;
6611790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    list_info->list = loader_heap_alloc(inst, list_info->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6621790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    if (list_info->list == NULL) {
6631790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        return false;
6641790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    }
665b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    memset(list_info->list, 0, list_info->capacity);
666d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky    list_info->count = 0;
667d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky    return true;
668d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky}
669d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky
670d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewyckyvoid loader_destroy_generic_list(const struct loader_instance *inst,
6711790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                                 struct loader_generic_list *list)
6721790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky{
6731790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    loader_heap_free(inst, list->list);
67477b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    list->count = 0;
67577b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    list->capacity = 0;
676c7a884040e4ec7795515978a94803894ad08c4caBill Wendling}
67777b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
678b8bce928f4ffdf50eff69334f3e25b27848536b6Micah Villmow/*
679b8bce928f4ffdf50eff69334f3e25b27848536b6Micah Villmow * Append non-duplicate extension properties defined in props
68077b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling * to the given ext_list.
68177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling * Return
68277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling *  Vk_SUCCESS on success
683b1928704201034c785a26296a49f69355eb56a05Nick Lewycky */
684b1928704201034c785a26296a49f69355eb56a05Nick LewyckyVkResult loader_add_to_ext_list(
685b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        const struct loader_instance *inst,
68617d2f776011cba33f7f5afb03c8066d35dbf8afcNick Lewycky        struct loader_extension_list *ext_list,
6875409a188328d9de3755febc23558d4fc1797d04eNick Lewycky        uint32_t prop_list_count,
6885409a188328d9de3755febc23558d4fc1797d04eNick Lewycky        const VkExtensionProperties *props)
68917d2f776011cba33f7f5afb03c8066d35dbf8afcNick Lewycky{
6905409a188328d9de3755febc23558d4fc1797d04eNick Lewycky    uint32_t i;
691c7a884040e4ec7795515978a94803894ad08c4caBill Wendling    const VkExtensionProperties *cur_ext;
6921790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
693b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (ext_list->list == NULL || ext_list->capacity == 0) {
694b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        loader_init_generic_list(inst, (struct loader_generic_list *) ext_list,
695b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                 sizeof(VkExtensionProperties));
6965fdd6c8793462549e3593890ec61573da06e3346Jay Foad    }
697b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
698b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (ext_list->list == NULL)
699b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        return VK_ERROR_OUT_OF_HOST_MEMORY;
700d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky
7011790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    for (i = 0; i < prop_list_count; i++) {
702b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        cur_ext = &props[i];
703b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
70418764716861243c58a711a92190624dc2f6aafc9Bill Wendling        // look for duplicates
70518764716861243c58a711a92190624dc2f6aafc9Bill Wendling        if (has_vk_extension_property(cur_ext, ext_list)) {
70618764716861243c58a711a92190624dc2f6aafc9Bill Wendling            continue;
70718764716861243c58a711a92190624dc2f6aafc9Bill Wendling        }
70818764716861243c58a711a92190624dc2f6aafc9Bill Wendling
709d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        // add to list at end
710d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        // check for enough capacity
711d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        if (ext_list->count * sizeof(VkExtensionProperties)
712d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling                        >= ext_list->capacity) {
713d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling
714b1928704201034c785a26296a49f69355eb56a05Nick Lewycky            ext_list->list = loader_heap_realloc(inst,
715db125cfaf57cc83e7dd7453de2d509bc8efd0e5eChris Lattner                                                 ext_list->list,
7161790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                                                 ext_list->capacity,
717b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                                 ext_list->capacity * 2,
718b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
7191790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
7201790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            if (ext_list->list == NULL)
7211790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky                return VK_ERROR_OUT_OF_HOST_MEMORY;
7221790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
7231790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            // double capacity
7241790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky            ext_list->capacity *= 2;
7251790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        }
7261790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky
7271790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties));
7281790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky        ext_list->count++;
7291790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    }
7301790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky    return VK_SUCCESS;
731b1928704201034c785a26296a49f69355eb56a05Nick Lewycky}
732d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling
73321b742ffce7bec3d71e09c7c6d901a756d55feb3Bill Wendling/*
734253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling * Append one extension property defined in props with entrypoints
735253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling * defined in entrys to the given ext_list.
736253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling * Return
737253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling *  Vk_SUCCESS on success
738253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling */
739b1928704201034c785a26296a49f69355eb56a05Nick LewyckyVkResult loader_add_to_dev_ext_list(
740034b94b17006f51722886b0f2283fb6fb19aca1fBill Wendling        const struct loader_instance *inst,
741a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky        struct loader_device_extension_list *ext_list,
742034b94b17006f51722886b0f2283fb6fb19aca1fBill Wendling        const VkExtensionProperties *props,
743253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling        uint32_t entry_count,
744253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling        char **entrys)
7451790c9cbb6714e81eab1412909a2320acaecc43bNick Lewycky{
746b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    uint32_t idx;
747b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (ext_list->list == NULL || ext_list->capacity == 0) {
748b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        loader_init_generic_list(inst, (struct loader_generic_list *) ext_list,
749b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                 sizeof(struct loader_dev_ext_props));
750b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    }
751b1928704201034c785a26296a49f69355eb56a05Nick Lewycky
752f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    if (ext_list->list == NULL)
753f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        return VK_ERROR_OUT_OF_HOST_MEMORY;
754f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel
755032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling    idx =ext_list->count;
756f2a2806baf3763d551a9f361124b608b2eed66faBill Wendling    // add to list at end
757d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky    // check for enough capacity
758d9686a98b8145010516c44a3a5b9b96bf934b9acNick Lewycky    if (idx * sizeof (struct loader_dev_ext_props)
759a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky            >= ext_list->capacity) {
7608fa6dc431deb7a9aadc23ec0a7bdcb2d02330972Nick Lewycky
7618fa6dc431deb7a9aadc23ec0a7bdcb2d02330972Nick Lewycky        ext_list->list = loader_heap_realloc(inst,
7625d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky                ext_list->list,
7635d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky                ext_list->capacity,
7645d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky                ext_list->capacity * 2,
7655d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
7665d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky
7675d22d02fac5ef25414c0fdd843b0fabba4998d6eNick Lewycky        if (ext_list->list == NULL)
76817d2f776011cba33f7f5afb03c8066d35dbf8afcNick Lewycky            return VK_ERROR_OUT_OF_HOST_MEMORY;
7698fa6dc431deb7a9aadc23ec0a7bdcb2d02330972Nick Lewycky
770f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel        // double capacity
771b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        ext_list->capacity *= 2;
772f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    }
773bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky
774f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    memcpy(&ext_list->list[idx].props, props, sizeof(struct loader_dev_ext_props));
775f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    ext_list->list[idx].entrypoint_count = entry_count;
776f6d3a4c7c4d14ad7a4e07e9f80f94f73651960d8Devang Patel    ext_list->list[idx].entrypoints = loader_heap_alloc(inst,
777b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                        sizeof(char *) * entry_count,
778b1928704201034c785a26296a49f69355eb56a05Nick Lewycky                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
779b1928704201034c785a26296a49f69355eb56a05Nick Lewycky    if (ext_list->list[idx].entrypoints == NULL)
7804a8fefaf8303f30514bc2a40d840a1709dae65cfBill Wendling        return VK_ERROR_OUT_OF_HOST_MEMORY;
781d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    for (uint32_t i = 0; i < entry_count; i++) {
782b1928704201034c785a26296a49f69355eb56a05Nick Lewycky        ext_list->list[idx].entrypoints[i] = loader_heap_alloc(inst,
78377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling                                            strlen(entrys[i]) + 1,
78477b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling                                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
78577b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        if (ext_list->list[idx].entrypoints[i] == NULL)
78677b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling            return VK_ERROR_OUT_OF_HOST_MEMORY;
78777b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
78877b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    }
789034b94b17006f51722886b0f2283fb6fb19aca1fBill Wendling    ext_list->count++;
790a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky
791034b94b17006f51722886b0f2283fb6fb19aca1fBill Wendling    return VK_SUCCESS;
79277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling}
79377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
79477b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling/**
79577b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling * Search the given search_list for any layers in the props list.
79677b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling * Add these to the output layer_list.  Don't add duplicates to the output layer_list.
79777b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling */
79877b19134104c3e96424dc010f2b69c3faf580e68Bill Wendlingstatic VkResult loader_add_layer_names_to_list(
79977b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        const struct loader_instance *inst,
80077b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        struct loader_layer_list *output_list,
80177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        uint32_t name_count,
80277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        const char * const *names,
80377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        const struct loader_layer_list *search_list)
80477b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling{
80577b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    struct loader_layer_properties *layer_prop;
806bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky    VkResult err = VK_SUCCESS;
80777b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
80877b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    for (uint32_t i = 0; i < name_count; i++) {
80977b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        const char *search_target = names[i];
81077b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        layer_prop = loader_get_layer_property(search_target, search_list);
81177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        if (!layer_prop) {
81277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
813bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky            err = VK_ERROR_LAYER_NOT_PRESENT;
81477b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling            continue;
81577b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        }
81677b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
81777b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        loader_add_to_layer_list(inst, output_list, 1, layer_prop);
81858591b1647e0f1f213e5acd7bfa87c226ced0033Nick Lewycky    }
81958591b1647e0f1f213e5acd7bfa87c226ced0033Nick Lewycky
82058591b1647e0f1f213e5acd7bfa87c226ced0033Nick Lewycky    return err;
82177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling}
82277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
82377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling
82477b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling/*
82577b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling * Manage lists of VkLayerProperties
826bd2d1245e7db11b58b52c5b36fe76925683aaea5Nick Lewycky */
82777b19134104c3e96424dc010f2b69c3faf580e68Bill Wendlingstatic bool loader_init_layer_list(const struct loader_instance *inst,
82877b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling                                   struct loader_layer_list *list)
82977b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling{
83077b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    list->capacity = 32 * sizeof(struct loader_layer_properties);
83177b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    list->list = loader_heap_alloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
83277b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling    if (list->list == NULL) {
83377b19134104c3e96424dc010f2b69c3faf580e68Bill Wendling        return false;
834253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    }
835d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    memset(list->list, 0, list->capacity);
836253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    list->count = 0;
837253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    return true;
838d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling}
839253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling
840253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendlingvoid loader_destroy_layer_list(const struct loader_instance *inst,
841d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling                               struct loader_layer_list *layer_list)
842253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling{
843253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    loader_heap_free(inst, layer_list->list);
844253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    layer_list->count = 0;
845034b94b17006f51722886b0f2283fb6fb19aca1fBill Wendling    layer_list->capacity = 0;
846a204ef3168c8804808c716115ba915c89d8849b9Nick Lewycky}
847034b94b17006f51722886b0f2283fb6fb19aca1fBill Wendling
848253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling/*
849253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling * Manage list of layer libraries (loader_lib_info)
850253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling */
851253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendlingstatic bool loader_init_layer_library_list(const struct loader_instance *inst,
852253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling                                           struct loader_layer_library_list *list)
853253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling{
854253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    list->capacity = 32 * sizeof(struct loader_lib_info);
855253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    list->list = loader_heap_alloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
856253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    if (list->list == NULL) {
857253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling        return false;
858032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling    }
859032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling    memset(list->list, 0, list->capacity);
860032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling    list->count = 0;
861032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling    return true;
862032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling}
863032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling
864ec3fc2eac0e9203dd1094b9ce458e8c1b42b832fBill Wendlingvoid loader_destroy_layer_library_list(const struct loader_instance *inst,
865032dbee2a9d401ee05beb648465f21168e279bdaBill Wendling                                       struct loader_layer_library_list *list)
866253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling{
867253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    for (uint32_t i = 0; i < list->count; i++) {
868253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling        loader_heap_free(inst, list->list[i].lib_name);
869253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    }
870253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    loader_heap_free(inst, list->list);
871d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling    list->count = 0;
872253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling    list->capacity = 0;
873253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling}
874d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling
875d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendlingvoid loader_add_to_layer_library_list(
876d195eb6b83c2f3c70c9d1a59e26e8d6d2a3d38d3Bill Wendling        const struct loader_instance *inst,
877253353c9cf1ff16d9c30a89c2fb96160ac5a9d65Bill Wendling        struct loader_layer_library_list *list,
878        uint32_t item_count,
879        const struct loader_lib_info *new_items)
880{
881    uint32_t i;
882    struct loader_lib_info *item;
883
884    if (list->list == NULL || list->capacity == 0) {
885        loader_init_layer_library_list(inst, list);
886    }
887
888    if (list->list == NULL)
889        return;
890
891    for (i = 0; i < item_count; i++) {
892        item = (struct loader_lib_info *) &new_items[i];
893
894        // look for duplicates
895        for (uint32_t j = 0; j < list->count; j++) {
896            if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
897                continue;
898            }
899        }
900
901        // add to list at end
902        // check for enough capacity
903        if (list->count * sizeof(struct loader_lib_info)
904                        >= list->capacity) {
905
906            list->list = loader_heap_realloc(inst,
907                                             list->list,
908                                             list->capacity,
909                                             list->capacity * 2,
910                                             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
911            // double capacity
912            list->capacity *= 2;
913        }
914
915        memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
916        list->count++;
917    }
918}
919
920
921/*
922 * Search the given layer list for a list
923 * matching the given VkLayerProperties
924 */
925bool has_vk_layer_property(
926        const VkLayerProperties *vk_layer_prop,
927        const struct loader_layer_list *list)
928{
929    for (uint32_t i = 0; i < list->count; i++) {
930        if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
931            return true;
932    }
933    return false;
934}
935
936/*
937 * Search the given layer list for a layer
938 * matching the given name
939 */
940bool has_layer_name(
941        const char *name,
942        const struct loader_layer_list *list)
943{
944    for (uint32_t i = 0; i < list->count; i++) {
945        if (strcmp(name, list->list[i].info.layerName) == 0)
946            return true;
947    }
948    return false;
949}
950
951/*
952 * Append non-duplicate layer properties defined in prop_list
953 * to the given layer_info list
954 */
955void loader_add_to_layer_list(
956        const struct loader_instance *inst,
957        struct loader_layer_list *list,
958        uint32_t prop_list_count,
959        const struct loader_layer_properties *props)
960{
961    uint32_t i;
962    struct loader_layer_properties *layer;
963
964    if (list->list == NULL || list->capacity == 0) {
965        loader_init_layer_list(inst, list);
966    }
967
968    if (list->list == NULL)
969        return;
970
971    for (i = 0; i < prop_list_count; i++) {
972        layer = (struct loader_layer_properties *) &props[i];
973
974        // look for duplicates
975        if (has_vk_layer_property(&layer->info, list)) {
976            continue;
977        }
978
979        // add to list at end
980        // check for enough capacity
981        if (list->count * sizeof(struct loader_layer_properties)
982                        >= list->capacity) {
983
984            list->list = loader_heap_realloc(inst,
985                                             list->list,
986                                             list->capacity,
987                                             list->capacity * 2,
988                                             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
989            // double capacity
990            list->capacity *= 2;
991        }
992
993        memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
994        list->count++;
995    }
996}
997
998/**
999 * Search the search_list for any layer with a name
1000 * that matches the given name and a type that matches the given type
1001 * Add all matching layers to the found_list
1002 * Do not add if found loader_layer_properties is already
1003 * on the found_list.
1004 */
1005static void loader_find_layer_name_add_list(
1006        const struct loader_instance *inst,
1007        const char *name,
1008        const enum layer_type type,
1009        const struct loader_layer_list *search_list,
1010        struct loader_layer_list *found_list)
1011{
1012    bool found = false;
1013    for (uint32_t i = 0; i < search_list->count; i++) {
1014        struct loader_layer_properties *layer_prop = &search_list->list[i];
1015        if (0 == strcmp(layer_prop->info.layerName, name) &&
1016                (layer_prop->type & type)) {
1017            /* Found a layer with the same name, add to found_list */
1018            loader_add_to_layer_list(inst, found_list, 1, layer_prop);
1019            found = true;
1020        }
1021    }
1022    if (!found) {
1023        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Warning, couldn't find layer name %s to activate", name);
1024    }
1025}
1026
1027static VkExtensionProperties *get_extension_property(
1028        const char *name,
1029        const struct loader_extension_list *list)
1030{
1031    for (uint32_t i = 0; i < list->count; i++) {
1032        if (strcmp(name, list->list[i].extensionName) == 0)
1033            return &list->list[i];
1034    }
1035    return NULL;
1036}
1037
1038static VkExtensionProperties *get_dev_extension_property(
1039        const char *name,
1040        const struct loader_device_extension_list *list)
1041{
1042    for (uint32_t i = 0; i < list->count; i++) {
1043        if (strcmp(name, list->list[i].props.extensionName) == 0)
1044            return &list->list[i].props;
1045    }
1046    return NULL;
1047}
1048
1049/*
1050 * For global 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 GetProcAddr requests
1060 * loader_coalesce_extensions(void) - add extension records to the list of global
1061 * extension available to the app.
1062 * instance_disp - add function pointer for terminator function to this array.
1063 * The extension itself should be in a separate file that will be
1064 * linked directly with the loader.
1065 */
1066
1067void loader_get_icd_loader_instance_extensions(
1068                                        const struct loader_instance *inst,
1069                                        struct loader_icd_libs *icd_libs,
1070                                        struct loader_extension_list *inst_exts)
1071{
1072    struct loader_extension_list icd_exts;
1073    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Build ICD instance extension list");
1074    // traverse scanned icd list adding non-duplicate extensions to the list
1075    for (uint32_t i = 0; i < icd_libs->count; i++) {
1076        loader_init_generic_list(inst, (struct loader_generic_list *) &icd_exts,
1077                                 sizeof(VkExtensionProperties));
1078        loader_add_global_extensions(inst, icd_libs->list[i].EnumerateInstanceExtensionProperties,
1079                                     icd_libs->list[i].lib_name,
1080                                     &icd_exts);
1081        loader_add_to_ext_list(inst, inst_exts,
1082                               icd_exts.count,
1083                               icd_exts.list);
1084        loader_destroy_generic_list(inst, (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 *loader_get_physical_device(const VkPhysicalDevice physdev)
1093{
1094    uint32_t i;
1095    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1096        for (i = 0; i < inst->total_gpu_count; i++) {
1097            //TODO this aliases physDevices within instances, need for this
1098            // function to go away
1099            if (inst->phys_devs[i].disp == loader_get_instance_dispatch(physdev)) {
1100                return &inst->phys_devs[i];
1101            }
1102        }
1103    }
1104    return NULL;
1105}
1106
1107struct loader_icd *loader_get_icd_and_device(const VkDevice device,
1108                                             struct loader_device **found_dev)
1109{
1110    *found_dev = NULL;
1111    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1112        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1113            for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
1114                /* Value comparison of device prevents object wrapping by layers */
1115                if (loader_get_dispatch(dev->device) == loader_get_dispatch(device)) {
1116                    *found_dev = dev;
1117                    return icd;
1118                }
1119        }
1120    }
1121    return NULL;
1122}
1123
1124static void loader_destroy_logical_device(const struct loader_instance *inst,
1125                                          struct loader_device *dev)
1126{
1127    loader_heap_free(inst, dev->app_extension_props);
1128    if (dev->activated_layer_list.count)
1129        loader_destroy_layer_list(inst, &dev->activated_layer_list);
1130    loader_heap_free(inst, dev);
1131}
1132
1133static struct loader_device *loader_add_logical_device(
1134                                        const struct loader_instance *inst,
1135                                        const VkDevice dev,
1136                                        struct loader_device **device_list)
1137{
1138    struct loader_device *new_dev;
1139
1140    new_dev = loader_heap_alloc(inst, sizeof(struct loader_device), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1141    if (!new_dev) {
1142        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to alloc struct laoder-device");
1143        return NULL;
1144    }
1145
1146    memset(new_dev, 0, sizeof(struct loader_device));
1147
1148    new_dev->next = *device_list;
1149    new_dev->device = dev;
1150    *device_list = new_dev;
1151    return new_dev;
1152}
1153
1154void loader_remove_logical_device(
1155                            const struct loader_instance *inst,
1156                            struct loader_icd *icd,
1157                            struct loader_device *found_dev)
1158{
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
1178
1179static void loader_icd_destroy(
1180        struct loader_instance *ptr_inst,
1181        struct loader_icd *icd)
1182{
1183    ptr_inst->total_icd_count--;
1184    for (struct loader_device *dev = icd->logical_device_list; dev; ) {
1185        struct loader_device *next_dev = dev->next;
1186        loader_destroy_logical_device(ptr_inst, dev);
1187        dev = next_dev;
1188    }
1189
1190    loader_heap_free(ptr_inst, icd);
1191}
1192
1193static struct loader_icd * loader_icd_create(const struct loader_instance *inst)
1194{
1195    struct loader_icd *icd;
1196
1197    icd = loader_heap_alloc(inst, sizeof(*icd), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1198    if (!icd)
1199        return NULL;
1200
1201    memset(icd, 0, sizeof(*icd));
1202
1203    return icd;
1204}
1205
1206static struct loader_icd *loader_icd_add(
1207        struct loader_instance *ptr_inst,
1208        const struct loader_scanned_icds *icd_lib)
1209{
1210    struct loader_icd *icd;
1211
1212    icd = loader_icd_create(ptr_inst);
1213    if (!icd)
1214        return NULL;
1215
1216    icd->this_icd_lib = icd_lib;
1217    icd->this_instance = ptr_inst;
1218
1219    /* prepend to the list */
1220    icd->next = ptr_inst->icds;
1221    ptr_inst->icds = icd;
1222    ptr_inst->total_icd_count++;
1223
1224    return icd;
1225}
1226
1227void loader_scanned_icd_clear(
1228                            const struct loader_instance *inst,
1229                            struct loader_icd_libs *icd_libs)
1230{
1231    if (icd_libs->capacity == 0)
1232        return;
1233    for (uint32_t i = 0; i < icd_libs->count; i++) {
1234        loader_platform_close_library(icd_libs->list[i].handle);
1235        loader_heap_free(inst, icd_libs->list[i].lib_name);
1236    }
1237    loader_heap_free(inst, icd_libs->list);
1238    icd_libs->capacity = 0;
1239    icd_libs->count = 0;
1240    icd_libs->list = NULL;
1241}
1242
1243static void loader_scanned_icd_init(const struct loader_instance *inst,
1244                                    struct loader_icd_libs *icd_libs)
1245{
1246    loader_scanned_icd_clear(inst, icd_libs);
1247    icd_libs->capacity = 8 * sizeof(struct loader_scanned_icds);
1248    icd_libs->list = loader_heap_alloc(inst, icd_libs->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1249
1250}
1251
1252static void loader_scanned_icd_add(
1253                            const struct loader_instance *inst,
1254                            struct loader_icd_libs *icd_libs,
1255                            const char *filename,
1256                            uint32_t api_version)
1257{
1258    loader_platform_dl_handle handle;
1259    PFN_vkCreateInstance fp_create_inst;
1260    PFN_vkEnumerateInstanceExtensionProperties fp_get_global_ext_props;
1261    PFN_vkGetInstanceProcAddr fp_get_proc_addr;
1262    struct loader_scanned_icds *new_node;
1263
1264    /* TODO implement ref counting of libraries, for now this function leaves
1265       libraries open and the scanned_icd_clear closes them */
1266    // Used to call: dlopen(filename, RTLD_LAZY);
1267    handle = loader_platform_open_library(filename);
1268    if (!handle) {
1269        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
1270        return;
1271    }
1272
1273#define LOOKUP_LD(func_ptr, func) do {                            \
1274    func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
1275    if (!func_ptr) {                                           \
1276        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
1277        return;                                                \
1278    }                                                          \
1279} while (0)
1280
1281    LOOKUP_LD(fp_get_proc_addr, GetInstanceProcAddr);
1282    LOOKUP_LD(fp_create_inst, CreateInstance);
1283    LOOKUP_LD(fp_get_global_ext_props, EnumerateInstanceExtensionProperties);
1284
1285#undef LOOKUP_LD
1286
1287    // check for enough capacity
1288    if ((icd_libs->count * sizeof(struct loader_scanned_icds)) >= icd_libs->capacity) {
1289
1290            icd_libs->list = loader_heap_realloc(inst,
1291                                                 icd_libs->list,
1292                                                 icd_libs->capacity,
1293                                                 icd_libs->capacity * 2,
1294                                                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1295            // double capacity
1296            icd_libs->capacity *= 2;
1297    }
1298    new_node = &(icd_libs->list[icd_libs->count]);
1299
1300    new_node->handle = handle;
1301    new_node->api_version = api_version;
1302    new_node->GetInstanceProcAddr = fp_get_proc_addr;
1303    new_node->CreateInstance = fp_create_inst;
1304    new_node->EnumerateInstanceExtensionProperties = fp_get_global_ext_props;
1305
1306    new_node->lib_name = (char *) loader_heap_alloc(inst,
1307                                            strlen(filename) + 1,
1308                                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1309    if (!new_node->lib_name) {
1310        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
1311        return;
1312    }
1313    strcpy(new_node->lib_name, filename);
1314    icd_libs->count++;
1315}
1316
1317static bool loader_icd_init_entrys(struct loader_icd *icd,
1318                                   VkInstance inst,
1319                                   const PFN_vkGetInstanceProcAddr fp_gipa)
1320{
1321    /* initialize entrypoint function pointers */
1322
1323    #define LOOKUP_GIPA(func, required) do {                       \
1324    icd->func = (PFN_vk ##func) fp_gipa(inst, "vk" #func);         \
1325    if (!icd->func && required) {                                  \
1326        loader_log(VK_DBG_REPORT_WARN_BIT, 0,                      \
1327              loader_platform_get_proc_address_error("vk" #func)); \
1328        return false;                                              \
1329    }                                                              \
1330    } while (0)
1331
1332    LOOKUP_GIPA(GetDeviceProcAddr, true);
1333    LOOKUP_GIPA(DestroyInstance, true);
1334    LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1335    LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1336    LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
1337    LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
1338    LOOKUP_GIPA(CreateDevice, true);
1339    LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1340    LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
1341    LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
1342    LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
1343    LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
1344    LOOKUP_GIPA(DbgCreateMsgCallback, false);
1345    LOOKUP_GIPA(DbgDestroyMsgCallback, false);
1346    LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
1347    LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
1348    LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
1349    LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
1350#ifdef VK_USE_PLATFORM_WIN32_KHR
1351    LOOKUP_GIPA(GetPhysicalDeviceWin32PresentationSupportKHR, false);
1352#endif
1353#ifdef VK_USE_PLATFORM_XCB_KHR
1354    LOOKUP_GIPA(GetPhysicalDeviceXcbPresentationSupportKHR, false);
1355#endif
1356
1357#undef LOOKUP_GIPA
1358
1359    return true;
1360}
1361
1362static void loader_debug_init(void)
1363{
1364    const char *env;
1365
1366    if (g_loader_debug > 0)
1367        return;
1368
1369    g_loader_debug = 0;
1370
1371    /* parse comma-separated debug options */
1372    env = getenv("VK_LOADER_DEBUG");
1373    while (env) {
1374        const char *p = strchr(env, ',');
1375        size_t len;
1376
1377        if (p)
1378            len = p - env;
1379        else
1380            len = strlen(env);
1381
1382        if (len > 0) {
1383            if (strncmp(env, "all", len) == 0) {
1384                g_loader_debug = ~0u;
1385                g_loader_log_msgs = ~0u;
1386            } else if (strncmp(env, "warn", len) == 0) {
1387                g_loader_debug |= LOADER_WARN_BIT;
1388                g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1389            } else if (strncmp(env, "info", len) == 0) {
1390                g_loader_debug |= LOADER_INFO_BIT;
1391                g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1392            } else if (strncmp(env, "perf", len) == 0) {
1393                g_loader_debug |= LOADER_PERF_BIT;
1394                g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1395            } else if (strncmp(env, "error", len) == 0) {
1396                g_loader_debug |= LOADER_ERROR_BIT;
1397                g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1398            } else if (strncmp(env, "debug", len) == 0) {
1399                g_loader_debug |= LOADER_DEBUG_BIT;
1400                g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1401            }
1402        }
1403
1404        if (!p)
1405            break;
1406
1407        env = p + 1;
1408    }
1409}
1410
1411void loader_initialize(void)
1412{
1413    // initialize mutexs
1414    loader_platform_thread_create_mutex(&loader_lock);
1415    loader_platform_thread_create_mutex(&loader_json_lock);
1416
1417    // initialize logging
1418    loader_debug_init();
1419
1420    // initial cJSON to use alloc callbacks
1421    cJSON_Hooks alloc_fns = {
1422        .malloc_fn = loader_tls_heap_alloc,
1423        .free_fn = loader_tls_heap_free,
1424    };
1425    cJSON_InitHooks(&alloc_fns);
1426}
1427
1428struct loader_manifest_files {
1429    uint32_t count;
1430    char **filename_list;
1431};
1432
1433/**
1434 * Get next file or dirname given a string list or registry key path
1435 *
1436 * \returns
1437 * A pointer to first char in the next path.
1438 * The next path (or NULL) in the list is returned in next_path.
1439 * Note: input string is modified in some cases. PASS IN A COPY!
1440 */
1441static char *loader_get_next_path(char *path)
1442{
1443    uint32_t len;
1444    char *next;
1445
1446    if (path == NULL)
1447        return NULL;
1448    next = strchr(path, PATH_SEPERATOR);
1449    if (next == NULL) {
1450        len = (uint32_t) strlen(path);
1451        next = path + len;
1452    }
1453    else {
1454        *next = '\0';
1455        next++;
1456    }
1457
1458    return next;
1459}
1460
1461/**
1462 * Given a path which is absolute or relative, expand the path if relative or
1463 * leave the path unmodified if absolute. The base path to prepend to relative
1464 * paths is given in rel_base.
1465 *
1466 * \returns
1467 * A string in out_fullpath of the full absolute path
1468 */
1469static void loader_expand_path(const char *path,
1470                               const char *rel_base,
1471                               size_t out_size,
1472                               char *out_fullpath)
1473{
1474    if (loader_platform_is_path_absolute(path)) {
1475        // do not prepend a base to an absolute path
1476        rel_base = "";
1477    }
1478
1479    loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
1480}
1481
1482/**
1483 * Given a filename (file)  and a list of paths (dir), try to find an existing
1484 * file in the paths.  If filename already is a path then no
1485 * searching in the given paths.
1486 *
1487 * \returns
1488 * A string in out_fullpath of either the full path or file.
1489 */
1490static void loader_get_fullpath(const char *file,
1491                                const char *dirs,
1492                                size_t out_size,
1493                                char *out_fullpath)
1494{
1495    if (!loader_platform_is_path(file) && *dirs) {
1496        char *dirs_copy, *dir, *next_dir;
1497
1498        dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1499        strcpy(dirs_copy, dirs);
1500
1501        //find if file exists after prepending paths in given list
1502        for (dir = dirs_copy;
1503             *dir && (next_dir = loader_get_next_path(dir));
1504             dir = next_dir) {
1505            loader_platform_combine_path(out_fullpath, out_size, dir, file, NULL);
1506            if (loader_platform_file_exists(out_fullpath)) {
1507                return;
1508            }
1509        }
1510    }
1511
1512    snprintf(out_fullpath, out_size, "%s", file);
1513}
1514
1515/**
1516 * Read a JSON file into a buffer.
1517 *
1518 * \returns
1519 * A pointer to a cJSON object representing the JSON parse tree.
1520 * This returned buffer should be freed by caller.
1521 */
1522static cJSON *loader_get_json(const char *filename)
1523{
1524    FILE *file;
1525    char *json_buf;
1526    cJSON *json;
1527    uint64_t len;
1528    file = fopen(filename,"rb");
1529    if (!file) {
1530        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Couldn't open JSON file %s", filename);
1531        return NULL;
1532    }
1533    fseek(file, 0, SEEK_END);
1534    len = ftell(file);
1535    fseek(file, 0, SEEK_SET);
1536    json_buf = (char*) loader_stack_alloc(len+1);
1537    if (json_buf == NULL) {
1538        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1539        fclose(file);
1540        return NULL;
1541    }
1542    if (fread(json_buf, sizeof(char), len, file) != len) {
1543        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1544        fclose(file);
1545        return NULL;
1546    }
1547    fclose(file);
1548    json_buf[len] = '\0';
1549
1550    //parse text from file
1551    json = cJSON_Parse(json_buf);
1552    if (json == NULL)
1553        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1554    return json;
1555}
1556
1557/**
1558 * Do a deep copy of the loader_layer_properties structure.
1559 */
1560static void loader_copy_layer_properties(
1561                            const struct loader_instance *inst,
1562                            struct loader_layer_properties *dst,
1563                            struct loader_layer_properties *src)
1564{
1565    uint32_t cnt, i;
1566    memcpy(dst, src, sizeof (*src));
1567    dst->instance_extension_list.list = loader_heap_alloc(
1568                                        inst,
1569                                        sizeof(VkExtensionProperties) *
1570                                        src->instance_extension_list.count,
1571                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1572    dst->instance_extension_list.capacity = sizeof(VkExtensionProperties) *
1573                                        src->instance_extension_list.count;
1574    memcpy(dst->instance_extension_list.list, src->instance_extension_list.list,
1575                                        dst->instance_extension_list.capacity);
1576    dst->device_extension_list.list = loader_heap_alloc(
1577                                        inst,
1578                                        sizeof(struct loader_dev_ext_props) *
1579                                        src->device_extension_list.count,
1580                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1581
1582    dst->device_extension_list.capacity = sizeof(struct loader_dev_ext_props) *
1583                                        src->device_extension_list.count;
1584    memcpy(dst->device_extension_list.list, src->device_extension_list.list,
1585                                        dst->device_extension_list.capacity);
1586    if (src->device_extension_list.count > 0 &&
1587                   src->device_extension_list.list->entrypoint_count > 0) {
1588        cnt = src->device_extension_list.list->entrypoint_count;
1589        dst->device_extension_list.list->entrypoints = loader_heap_alloc(
1590                                        inst,
1591                                        sizeof(char *) * cnt,
1592                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1593        for (i = 0; i < cnt; i++) {
1594            dst->device_extension_list.list->entrypoints[i] =  loader_heap_alloc(
1595                                    inst,
1596                                    strlen(src->device_extension_list.list->entrypoints[i]) + 1,
1597                                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1598            strcpy(dst->device_extension_list.list->entrypoints[i],
1599                   src->device_extension_list.list->entrypoints[i]);
1600        }
1601    }
1602}
1603
1604/**
1605 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1606 * file, add entry to the layer_list.
1607 * Fill out the layer_properties in this list entry from the input cJSON object.
1608 *
1609 * \returns
1610 * void
1611 * layer_list has a new entry and initialized accordingly.
1612 * If the json input object does not have all the required fields no entry
1613 * is added to the list.
1614 */
1615static void loader_add_layer_properties(const struct loader_instance *inst,
1616                                        struct loader_layer_list *layer_instance_list,
1617                                        struct loader_layer_list *layer_device_list,
1618                                        cJSON *json,
1619                                        bool is_implicit,
1620                                        char *filename)
1621{
1622    /* Fields in layer manifest file that are required:
1623     * (required) “file_format_version”
1624     * following are required in the "layer" object:
1625     * (required) "name"
1626     * (required) "type"
1627     * (required) “library_path”
1628     * (required) “api_version”
1629     * (required) “implementation_version”
1630     * (required) “description”
1631     * (required for implicit layers) “disable_environment”
1632     *
1633     * First get all required items and if any missing abort
1634     */
1635
1636    cJSON *item, *layer_node, *ext_item;
1637    char *temp;
1638    char *name, *type, *library_path, *api_version;
1639    char *implementation_version, *description;
1640    cJSON *disable_environment;
1641    int i, j;
1642    VkExtensionProperties ext_prop;
1643    item = cJSON_GetObjectItem(json, "file_format_version");
1644    if (item == NULL) {
1645        return;
1646    }
1647    char *file_vers = cJSON_PrintUnformatted(item);
1648    loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1649               filename, file_vers);
1650    if (strcmp(file_vers, "\"1.0.0\"") != 0)
1651        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1652    loader_tls_heap_free(file_vers);
1653
1654    layer_node = cJSON_GetObjectItem(json, "layer");
1655    if (layer_node == NULL) {
1656        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
1657        return;
1658    }
1659
1660    // loop through all "layer" objects in the file
1661    do {
1662#define GET_JSON_OBJECT(node, var) {                  \
1663        var = cJSON_GetObjectItem(node, #var);        \
1664        if (var == NULL) {                            \
1665            layer_node = layer_node->next;            \
1666            continue;                                 \
1667        }                                             \
1668        }
1669#define GET_JSON_ITEM(node, var) {                    \
1670        item = cJSON_GetObjectItem(node, #var);       \
1671        if (item == NULL) {                           \
1672            layer_node = layer_node->next;            \
1673            continue;                                 \
1674        }                                             \
1675        temp = cJSON_Print(item);                     \
1676        temp[strlen(temp) - 1] = '\0';                \
1677        var = loader_stack_alloc(strlen(temp) + 1);   \
1678        strcpy(var, &temp[1]);                        \
1679        loader_tls_heap_free(temp);                   \
1680        }
1681        GET_JSON_ITEM(layer_node, name)
1682        GET_JSON_ITEM(layer_node, type)
1683        GET_JSON_ITEM(layer_node, library_path)
1684        GET_JSON_ITEM(layer_node, api_version)
1685        GET_JSON_ITEM(layer_node, implementation_version)
1686        GET_JSON_ITEM(layer_node, description)
1687        if (is_implicit) {
1688            GET_JSON_OBJECT(layer_node, disable_environment)
1689        }
1690#undef GET_JSON_ITEM
1691#undef GET_JSON_OBJECT
1692
1693        // add list entry
1694        struct loader_layer_properties *props=NULL;
1695        if (!strcmp(type, "DEVICE")) {
1696            if (layer_device_list == NULL) {
1697                layer_node = layer_node->next;
1698                continue;
1699            }
1700            props = loader_get_next_layer_property(inst, layer_device_list);
1701            props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
1702        }
1703        if (!strcmp(type, "INSTANCE")) {
1704            if (layer_instance_list == NULL) {
1705                layer_node = layer_node->next;
1706                continue;
1707            }
1708            props = loader_get_next_layer_property(inst, layer_instance_list);
1709            props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
1710        }
1711        if (!strcmp(type, "GLOBAL")) {
1712            if (layer_instance_list != NULL)
1713                props = loader_get_next_layer_property(inst, layer_instance_list);
1714            else if (layer_device_list != NULL)
1715                props = loader_get_next_layer_property(inst, layer_device_list);
1716            else {
1717                layer_node = layer_node->next;
1718                continue;
1719            }
1720            props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1721        }
1722
1723        if (props == NULL) {
1724            layer_node = layer_node->next;
1725            continue;
1726        }
1727
1728        strncpy(props->info.layerName, name, sizeof (props->info.layerName));
1729        props->info.layerName[sizeof (props->info.layerName) - 1] = '\0';
1730
1731        char *fullpath = props->lib_name;
1732        char *rel_base;
1733        if (loader_platform_is_path(library_path)) {
1734            // a relative or absolute path
1735            char *name_copy = loader_stack_alloc(strlen(filename) + 1);
1736            strcpy(name_copy, filename);
1737            rel_base = loader_platform_dirname(name_copy);
1738            loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, fullpath);
1739        } else {
1740            // a filename which is assumed in a system directory
1741            loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH, MAX_STRING_SIZE, fullpath);
1742        }
1743        props->info.specVersion = loader_make_version(api_version);
1744        props->info.implementationVersion = atoi(implementation_version);
1745        strncpy((char *) props->info.description, description, sizeof (props->info.description));
1746        props->info.description[sizeof (props->info.description) - 1] = '\0';
1747        if (is_implicit) {
1748            strncpy(props->disable_env_var.name, disable_environment->child->string, sizeof (props->disable_env_var.name));
1749            props->disable_env_var.name[sizeof (props->disable_env_var.name) - 1] = '\0';
1750            strncpy(props->disable_env_var.value, disable_environment->child->valuestring, sizeof (props->disable_env_var.value));
1751            props->disable_env_var.value[sizeof (props->disable_env_var.value) - 1] = '\0';
1752        }
1753
1754        /**
1755         * Now get all optional items and objects and put in list:
1756         * functions
1757         * instance_extensions
1758         * device_extensions
1759         * enable_environment (implicit layers only)
1760         * disable_environment (implicit_layers_only)
1761         */
1762#define GET_JSON_OBJECT(node, var) {                  \
1763        var = cJSON_GetObjectItem(node, #var);        \
1764        }
1765#define GET_JSON_ITEM(node, var) {                    \
1766        item = cJSON_GetObjectItem(node, #var);       \
1767        if (item != NULL) {                           \
1768            temp = cJSON_Print(item);                 \
1769            temp[strlen(temp) - 1] = '\0';            \
1770            var = loader_stack_alloc(strlen(temp) + 1);\
1771            strcpy(var, &temp[1]);                    \
1772            loader_tls_heap_free(temp);               \
1773        }                                             \
1774        }
1775
1776        cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1777        cJSON *entrypoints;
1778        char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version;
1779        char **entry_array;
1780        vkGetInstanceProcAddr = NULL;
1781        vkGetDeviceProcAddr = NULL;
1782        spec_version = NULL;
1783        entrypoints = NULL;
1784        entry_array = NULL;
1785        /**
1786         * functions
1787         *     vkGetInstanceProcAddr
1788         *     vkGetDeviceProcAddr
1789         */
1790        GET_JSON_OBJECT(layer_node, functions)
1791        if (functions != NULL) {
1792            GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1793            GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1794            if (vkGetInstanceProcAddr != NULL)
1795                strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, sizeof (props->functions.str_gipa));
1796            props->functions.str_gipa[sizeof (props->functions.str_gipa) - 1] = '\0';
1797            if (vkGetDeviceProcAddr != NULL)
1798                strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, sizeof (props->functions.str_gdpa));
1799            props->functions.str_gdpa[sizeof (props->functions.str_gdpa) - 1] = '\0';
1800        }
1801        /**
1802         * instance_extensions
1803         * array of
1804         *     name
1805         *     spec_version
1806         */
1807        GET_JSON_OBJECT(layer_node, instance_extensions)
1808        if (instance_extensions != NULL) {
1809            int count = cJSON_GetArraySize(instance_extensions);
1810            for (i = 0; i < count; i++) {
1811                ext_item = cJSON_GetArrayItem(instance_extensions, i);
1812                GET_JSON_ITEM(ext_item, name)
1813                GET_JSON_ITEM(ext_item, spec_version)
1814                if (name != NULL) {
1815                    strncpy(ext_prop.extensionName, name, sizeof (ext_prop.extensionName));
1816                    ext_prop.extensionName[sizeof (ext_prop.extensionName) - 1] = '\0';
1817                }
1818                ext_prop.specVersion = atoi(spec_version);
1819                loader_add_to_ext_list(inst, &props->instance_extension_list, 1, &ext_prop);
1820            }
1821        }
1822        /**
1823         * device_extensions
1824         * array of
1825         *     name
1826         *     spec_version
1827         *     entrypoints
1828         */
1829        GET_JSON_OBJECT(layer_node, device_extensions)
1830        if (device_extensions != NULL) {
1831            int count = cJSON_GetArraySize(device_extensions);
1832            for (i = 0; i < count; i++) {
1833                ext_item = cJSON_GetArrayItem(device_extensions, i);
1834                GET_JSON_ITEM(ext_item, name)
1835                GET_JSON_ITEM(ext_item, spec_version)
1836                if (name != NULL) {
1837                    strncpy(ext_prop.extensionName, name, sizeof (ext_prop.extensionName));
1838                    ext_prop.extensionName[sizeof (ext_prop.extensionName) - 1] = '\0';
1839                }
1840                ext_prop.specVersion = atoi(spec_version);
1841                //entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
1842                GET_JSON_OBJECT(ext_item, entrypoints)
1843                int entry_count;
1844                if (entrypoints == NULL)
1845                    continue;
1846                entry_count = cJSON_GetArraySize(entrypoints);
1847                if (entry_count)
1848                    entry_array = (char **) loader_stack_alloc(sizeof(char *) * entry_count);
1849                for (j = 0; j < entry_count; j++) {
1850                    ext_item = cJSON_GetArrayItem(entrypoints, j);
1851                    if (ext_item != NULL) {
1852                        temp = cJSON_Print(ext_item);
1853                        temp[strlen(temp) - 1] = '\0';
1854                        entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
1855                        strcpy(entry_array[j], &temp[1]);
1856                        loader_tls_heap_free(temp);
1857                    }
1858                }
1859                loader_add_to_dev_ext_list(inst, &props->device_extension_list,
1860                                       &ext_prop, entry_count, entry_array);
1861            }
1862        }
1863        if (is_implicit) {
1864            GET_JSON_OBJECT(layer_node, enable_environment)
1865            strncpy(props->enable_env_var.name, enable_environment->child->string, sizeof (props->enable_env_var.name));
1866            props->enable_env_var.name[sizeof (props->enable_env_var.name) - 1] = '\0';
1867            strncpy(props->enable_env_var.value, enable_environment->child->valuestring, sizeof (props->enable_env_var.value));
1868            props->enable_env_var.value[sizeof (props->enable_env_var.value) - 1] = '\0';
1869            //TODO add disable_environment for implicit layers
1870        }
1871#undef GET_JSON_ITEM
1872#undef GET_JSON_OBJECT
1873        // for global layers need to add them to both device and instance list
1874        if (!strcmp(type, "GLOBAL")) {
1875            struct loader_layer_properties *dev_props;
1876            if (layer_instance_list == NULL || layer_device_list == NULL) {
1877                layer_node = layer_node->next;
1878                continue;
1879            }
1880            dev_props = loader_get_next_layer_property(inst, layer_device_list);
1881            //copy into device layer list
1882            loader_copy_layer_properties(inst, dev_props, props);
1883        }
1884        layer_node = layer_node->next;
1885    } while (layer_node != NULL);
1886    return;
1887}
1888
1889/**
1890 * Find the Vulkan library manifest files.
1891 *
1892 * This function scans the location or env_override directories/files
1893 * for a list of JSON manifest files.  If env_override is non-NULL
1894 * and has a valid value. Then the location is ignored.  Otherwise
1895 * location is used to look for manifest files. The location
1896 * is interpreted as  Registry path on Windows and a directory path(s)
1897 * on Linux.
1898 *
1899 * \returns
1900 * A string list of manifest files to be opened in out_files param.
1901 * List has a pointer to string for each manifest filename.
1902 * When done using the list in out_files, pointers should be freed.
1903 * Location or override  string lists can be either files or directories as follows:
1904 *            | location | override
1905 * --------------------------------
1906 * Win ICD    | files    | files
1907 * Win Layer  | files    | dirs
1908 * Linux ICD  | dirs     | files
1909 * Linux Layer| dirs     | dirs
1910 */
1911static void loader_get_manifest_files(const struct loader_instance *inst,
1912                                      const char *env_override,
1913                                      bool is_layer,
1914                                      const char *location,
1915                                      struct loader_manifest_files *out_files)
1916{
1917    char *override = NULL;
1918    char *loc;
1919    char *file, *next_file, *name;
1920    size_t alloced_count = 64;
1921    char full_path[2048];
1922    DIR *sysdir = NULL;
1923    bool list_is_dirs = false;
1924    struct dirent *dent;
1925
1926    out_files->count = 0;
1927    out_files->filename_list = NULL;
1928
1929    if (env_override != NULL && (override = getenv(env_override))) {
1930#if !defined(_WIN32)
1931        if (geteuid() != getuid()) {
1932            /* Don't allow setuid apps to use the env var: */
1933            override = NULL;
1934        }
1935#endif
1936    }
1937
1938    if (location == NULL) {
1939        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1940            "Can't get manifest files with NULL location, env_override=%s",
1941            env_override);
1942        return;
1943    }
1944
1945#if defined(_WIN32)
1946    list_is_dirs = (is_layer && override != NULL) ? true : false;
1947#else
1948    list_is_dirs = (override == NULL || is_layer) ? true : false;
1949#endif
1950    // Make a copy of the input we are using so it is not modified
1951    // Also handle getting the location(s) from registry on Windows
1952    if (override == NULL) {
1953        loc = loader_stack_alloc(strlen(location) + 1);
1954        if (loc == NULL) {
1955            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1956            return;
1957        }
1958        strcpy(loc, location);
1959#if defined(_WIN32)
1960        loc = loader_get_registry_files(inst, loc);
1961        if (loc == NULL) {
1962            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1963            return;
1964        }
1965#endif
1966    }
1967    else {
1968        loc = loader_stack_alloc(strlen(override) + 1);
1969        if (loc == NULL) {
1970            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1971            return;
1972        }
1973        strcpy(loc, override);
1974    }
1975
1976    // Print out the paths being searched if debugging is enabled
1977    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching the following paths for manifest files: %s\n", loc);
1978
1979    file = loc;
1980    while (*file) {
1981        next_file = loader_get_next_path(file);
1982        if (list_is_dirs) {
1983            sysdir = opendir(file);
1984            name = NULL;
1985            if (sysdir) {
1986                dent = readdir(sysdir);
1987                if (dent == NULL)
1988                    break;
1989                name = &(dent->d_name[0]);
1990                loader_get_fullpath(name, file, sizeof(full_path), full_path);
1991                name = full_path;
1992            }
1993        }
1994        else {
1995#if defined(_WIN32)
1996            name = file;
1997#else
1998            // only Linux has relative paths
1999            char *dir;
2000            // make a copy of location so it isn't modified
2001            dir = loader_stack_alloc(strlen(loc) + 1);
2002            if (dir == NULL) {
2003                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
2004                return;
2005            }
2006            strcpy(dir, loc);
2007
2008            loader_get_fullpath(file, dir, sizeof(full_path), full_path);
2009
2010            name = full_path;
2011#endif
2012        }
2013        while (name) {
2014                /* Look for files ending with ".json" suffix */
2015                uint32_t nlen = (uint32_t) strlen(name);
2016                const char *suf = name + nlen - 5;
2017                if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
2018                    if (out_files->count == 0) {
2019                        out_files->filename_list = loader_heap_alloc(inst,
2020                                              alloced_count * sizeof(char *),
2021                                              VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2022                    }
2023                    else if (out_files->count == alloced_count) {
2024                        out_files->filename_list = loader_heap_realloc(inst,
2025                                        out_files->filename_list,
2026                                        alloced_count * sizeof(char *),
2027                                        alloced_count * sizeof(char *) * 2,
2028                                        VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2029                        alloced_count *= 2;
2030                    }
2031                    if (out_files->filename_list == NULL) {
2032                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
2033                        return;
2034                    }
2035                    out_files->filename_list[out_files->count] = loader_heap_alloc(
2036                                                inst,
2037                                                strlen(name) + 1,
2038                                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2039                    if (out_files->filename_list[out_files->count] == NULL) {
2040                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
2041                        return;
2042                    }
2043                    strcpy(out_files->filename_list[out_files->count], name);
2044                    out_files->count++;
2045                } else if (!list_is_dirs) {
2046                    loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
2047                }
2048                if (list_is_dirs) {
2049                    dent = readdir(sysdir);
2050                    if (dent == NULL)
2051                        break;
2052                    name = &(dent->d_name[0]);
2053                    loader_get_fullpath(name, file, sizeof(full_path), full_path);
2054                    name = full_path;
2055                }
2056                else {
2057                    break;
2058                }
2059        }
2060        if (sysdir)
2061            closedir(sysdir);
2062        file = next_file;
2063    }
2064    return;
2065}
2066
2067void loader_init_icd_lib_list()
2068{
2069
2070}
2071
2072void loader_destroy_icd_lib_list()
2073{
2074
2075}
2076/**
2077 * Try to find the Vulkan ICD driver(s).
2078 *
2079 * This function scans the default system loader path(s) or path
2080 * specified by the \c VK_ICD_FILENAMES environment variable in
2081 * order to find loadable VK ICDs manifest files. From these
2082 * manifest files it finds the ICD libraries.
2083 *
2084 * \returns
2085 * a list of icds that were discovered
2086 */
2087void loader_icd_scan(
2088                     const struct loader_instance *inst,
2089                     struct loader_icd_libs *icds)
2090{
2091    char *file_str;
2092    struct loader_manifest_files manifest_files;
2093
2094    loader_scanned_icd_init(inst, icds);
2095    // Get a list of manifest files for ICDs
2096    loader_get_manifest_files(inst, "VK_ICD_FILENAMES", false,
2097                              DEFAULT_VK_DRIVERS_INFO, &manifest_files);
2098    if (manifest_files.count == 0)
2099        return;
2100    loader_platform_thread_lock_mutex(&loader_json_lock);
2101    for (uint32_t i = 0; i < manifest_files.count; i++) {
2102        file_str = manifest_files.filename_list[i];
2103        if (file_str == NULL)
2104            continue;
2105
2106        cJSON *json;
2107        json = loader_get_json(file_str);
2108        if (!json)
2109            continue;
2110        cJSON *item, *itemICD;
2111        item = cJSON_GetObjectItem(json, "file_format_version");
2112        if (item == NULL) {
2113            loader_platform_thread_unlock_mutex(&loader_json_lock);
2114            return;
2115        }
2116        char *file_vers = cJSON_Print(item);
2117        loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
2118                   file_str, file_vers);
2119        if (strcmp(file_vers, "\"1.0.0\"") != 0)
2120            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
2121        loader_tls_heap_free(file_vers);
2122        itemICD = cJSON_GetObjectItem(json, "ICD");
2123        if (itemICD != NULL) {
2124            item = cJSON_GetObjectItem(itemICD, "library_path");
2125            if (item != NULL) {
2126                char *temp= cJSON_Print(item);
2127                if (!temp || strlen(temp) == 0) {
2128                    loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
2129                    loader_tls_heap_free(temp);
2130                    loader_heap_free(inst, file_str);
2131                    cJSON_Delete(json);
2132                    continue;
2133                }
2134                //strip out extra quotes
2135                temp[strlen(temp) - 1] = '\0';
2136                char *library_path = loader_stack_alloc(strlen(temp) + 1);
2137                strcpy(library_path, &temp[1]);
2138                loader_tls_heap_free(temp);
2139                if (!library_path || strlen(library_path) == 0) {
2140                    loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
2141                    loader_heap_free(inst, file_str);
2142                    cJSON_Delete(json);
2143                    continue;
2144                }
2145                char fullpath[MAX_STRING_SIZE];
2146                // Print out the paths being searched if debugging is enabled
2147                loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching for ICD drivers named %s default dir %s\n", library_path, DEFAULT_VK_DRIVERS_PATH);
2148                if (loader_platform_is_path(library_path)) {
2149                    // a relative or absolute path
2150                    char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
2151                    char *rel_base;
2152                    strcpy(name_copy, file_str);
2153                    rel_base = loader_platform_dirname(name_copy);
2154                    loader_expand_path(library_path, rel_base, sizeof(fullpath), fullpath);
2155                } else {
2156                    // a filename which is assumed in a system directory
2157                    loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH, sizeof(fullpath), fullpath);
2158                }
2159
2160                uint32_t vers = 0;
2161                item = cJSON_GetObjectItem(itemICD, "api_version");
2162                if (item != NULL) {
2163                    temp= cJSON_Print(item);
2164                    vers = loader_make_version(temp);
2165                    loader_tls_heap_free(temp);
2166                }
2167                loader_scanned_icd_add(inst, icds, fullpath, vers);
2168            }
2169            else
2170                loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" object in ICD JSON file %s, skipping", file_str);
2171        }
2172        else
2173            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
2174
2175        loader_heap_free(inst, file_str);
2176        cJSON_Delete(json);
2177    }
2178    loader_heap_free(inst, manifest_files.filename_list);
2179    loader_platform_thread_unlock_mutex(&loader_json_lock);
2180}
2181
2182
2183void loader_layer_scan(
2184                       const struct loader_instance *inst,
2185                       struct loader_layer_list *instance_layers,
2186                       struct loader_layer_list *device_layers)
2187{
2188    char *file_str;
2189    struct loader_manifest_files manifest_files;
2190    cJSON *json;
2191    uint32_t i;
2192
2193    // Get a list of manifest files for layers
2194    loader_get_manifest_files(inst, LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
2195                              &manifest_files);
2196    if (manifest_files.count == 0)
2197        return;
2198
2199#if 0 //TODO
2200    /**
2201     * We need a list of the layer libraries, not just a list of
2202     * the layer properties (a layer library could expose more than
2203     * one layer property). This list of scanned layers would be
2204     * used to check for global and physicaldevice layer properties.
2205     */
2206    if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
2207        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2208                   "Alloc for layer list failed: %s line: %d", __FILE__, __LINE__);
2209        return;
2210    }
2211#endif
2212
2213    /* cleanup any previously scanned libraries */
2214    loader_delete_layer_properties(inst, instance_layers);
2215    loader_delete_layer_properties(inst, device_layers);
2216
2217    loader_platform_thread_lock_mutex(&loader_json_lock);
2218    for (i = 0; i < manifest_files.count; i++) {
2219        file_str = manifest_files.filename_list[i];
2220        if (file_str == NULL)
2221            continue;
2222
2223        // parse file into JSON struct
2224        json = loader_get_json(file_str);
2225        if (!json) {
2226            continue;
2227        }
2228
2229        //TODO pass in implicit versus explicit bool
2230        //TODO error if device layers expose instance_extensions
2231        //TODO error if instance layers expose device extensions
2232        loader_add_layer_properties(inst,
2233                                    instance_layers,
2234                                    device_layers,
2235                                    json,
2236                                    false,
2237                                    file_str);
2238
2239        loader_heap_free(inst, file_str);
2240        cJSON_Delete(json);
2241    }
2242    loader_heap_free(inst, manifest_files.filename_list);
2243    loader_platform_thread_unlock_mutex(&loader_json_lock);
2244}
2245
2246static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_internal(VkInstance inst, const char * pName)
2247{
2248    // inst is not wrapped
2249    if (inst == VK_NULL_HANDLE) {
2250        return NULL;
2251    }
2252    VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
2253    void *addr;
2254
2255    if (!strcmp(pName, "vkGetInstanceProcAddr"))
2256        return (void *) loader_gpa_instance_internal;
2257
2258    if (disp_table == NULL)
2259        return NULL;
2260
2261    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2262    if (addr) {
2263        return addr;
2264    }
2265
2266    if (disp_table->GetInstanceProcAddr == NULL) {
2267        return NULL;
2268    }
2269    return disp_table->GetInstanceProcAddr(inst, pName);
2270}
2271
2272/**
2273 * Initialize device_ext dispatch table entry as follows:
2274 * If dev == NULL find all logical devices created within this instance and
2275 *  init the entry (given by idx) in the ext dispatch table.
2276 * If dev != NULL only initialize the entry in the given dev's dispatch table.
2277 * The initialization value is gotten by calling down the device chain with GDPA.
2278 * If GDPA returns NULL then don't initialize the dispatch table entry.
2279 */
2280static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst,
2281                                         struct loader_device *dev,
2282                                         uint32_t idx,
2283                                         const char *funcName)
2284
2285 {
2286    void *gdpa_value;
2287    if (dev != NULL) {
2288        gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
2289                                                    dev->device, funcName);
2290        if (gdpa_value != NULL)
2291            dev->loader_dispatch.ext_dispatch.DevExt[idx] = (PFN_vkDevExt) gdpa_value;
2292    } else {
2293        for (uint32_t i = 0; i < inst->total_icd_count; i++) {
2294            struct loader_icd *icd = &inst->icds[i];
2295            struct loader_device *dev = icd->logical_device_list;
2296            while (dev) {
2297                gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
2298                                                    dev->device, funcName);
2299                if (gdpa_value != NULL)
2300                    dev->loader_dispatch.ext_dispatch.DevExt[idx] =
2301                                                    (PFN_vkDevExt) gdpa_value;
2302                dev = dev->next;
2303            }
2304        }
2305    }
2306
2307}
2308
2309/**
2310 * Find all dev extension in the hash table  and initialize the dispatch table
2311 * for dev  for each of those extension entrypoints found in hash table.
2312
2313 */
2314static void loader_init_dispatch_dev_ext(struct loader_instance *inst,
2315                                         struct loader_device *dev)
2316{
2317    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
2318        if (inst->disp_hash[i].func_name != NULL)
2319            loader_init_dispatch_dev_ext_entry(inst, dev, i,
2320                                               inst->disp_hash[i].func_name);
2321    }
2322}
2323
2324static bool loader_check_icds_for_address(struct loader_instance *inst,
2325                                          const char *funcName)
2326{
2327    struct loader_icd *icd;
2328    icd = inst->icds;
2329    while (icd) {
2330        if (icd->this_icd_lib->GetInstanceProcAddr(icd->instance, funcName))
2331            // this icd supports funcName
2332            return true;
2333        icd = icd->next;
2334    }
2335
2336    return false;
2337}
2338
2339static void loader_free_dev_ext_table(struct loader_instance *inst)
2340{
2341    for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
2342        loader_heap_free(inst, inst->disp_hash[i].func_name);
2343        loader_heap_free(inst, inst->disp_hash[i].list.index);
2344
2345    }
2346    memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
2347}
2348
2349static bool loader_add_dev_ext_table(struct loader_instance *inst,
2350                                     uint32_t *ptr_idx,
2351                                     const char *funcName)
2352{
2353    uint32_t i;
2354    uint32_t idx = *ptr_idx;
2355    struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
2356
2357    if (!inst->disp_hash[idx].func_name) {
2358        // no entry here at this idx, so use it
2359        assert(list->capacity == 0);
2360        inst->disp_hash[idx].func_name = (char *) loader_heap_alloc(inst,
2361                                         strlen(funcName) + 1,
2362                                         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2363        if (inst->disp_hash[idx].func_name == NULL) {
2364            loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2365                       "loader_add_dev_ext_table() can't allocate memory for func_name");
2366            return false;
2367        }
2368        strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
2369        return true;
2370    }
2371
2372    // check for enough capacity
2373    if (list->capacity == 0) {
2374        list->index = loader_heap_alloc(inst, 8 * sizeof(*(list->index)),
2375                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2376        if (list->index == NULL) {
2377            loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2378                       "loader_add_dev_ext_table() can't allocate list memory");
2379            return false;
2380        }
2381        list->capacity = 8 * sizeof(*(list->index));
2382    } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
2383        list->index = loader_heap_realloc(inst, list->index, list->capacity,
2384                            list->capacity * 2,
2385                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2386        if (list->index == NULL) {
2387            loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2388                       "loader_add_dev_ext_table() can't reallocate list memory");
2389            return false;
2390        }
2391        list->capacity *= 2;
2392    }
2393
2394    //find an unused index in the hash table and use it
2395    i = (idx + 1) % MAX_NUM_DEV_EXTS;
2396    do {
2397        if (!inst->disp_hash[i].func_name) {
2398            assert(inst->disp_hash[i].list.capacity == 0);
2399            inst->disp_hash[i].func_name = (char *) loader_heap_alloc(inst,
2400                                            strlen(funcName) + 1,
2401                                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2402            if (inst->disp_hash[i].func_name == NULL) {
2403                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2404                       "loader_add_dev_ext_table() can't rallocate func_name memory");
2405                return false;
2406            }
2407            strncpy(inst->disp_hash[i].func_name, funcName, strlen(funcName) + 1);
2408            list->index[list->count] = i;
2409            list->count++;
2410            *ptr_idx = i;
2411            return true;
2412        }
2413        i = (i + 1) % MAX_NUM_DEV_EXTS;
2414    } while (i != idx);
2415
2416    loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2417               "loader_add_dev_ext_table() couldn't insert into hash table; is it full?");
2418    return false;
2419}
2420
2421static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
2422                                         uint32_t *idx,
2423                                         const char *funcName)
2424{
2425    uint32_t alt_idx;
2426    if (inst->disp_hash[*idx].func_name && !strcmp(
2427                                                inst->disp_hash[*idx].func_name,
2428                                                funcName))
2429        return true;
2430
2431    // funcName wasn't at the primary spot in the hash table
2432    // search the list of secondary locations (shallow search, not deep search)
2433    for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
2434        alt_idx = inst->disp_hash[*idx].list.index[i];
2435        if (!strcmp(inst->disp_hash[*idx].func_name, funcName)) {
2436            *idx = alt_idx;
2437            return true;
2438        }
2439    }
2440
2441    return false;
2442}
2443
2444/**
2445 * This function returns generic trampoline code address for unknown entry points.
2446 * Presumably, these unknown entry points (as given by funcName) are device
2447 * extension entrypoints.  A hash table is used to keep a list of unknown entry
2448 * points and their mapping to the device extension dispatch table
2449 * (struct loader_dev_ext_dispatch_table).
2450 * \returns
2451 * For a given entry point string (funcName), if an existing mapping is found the
2452 * trampoline address for that mapping is returned. Otherwise, this unknown entry point
2453 * has not been seen yet. Next check if a layer or ICD supports it.  If so then a
2454 * new entry in the hash table is initialized and that trampoline address for
2455 * the new entry is returned. Null is returned if the hash table is full or
2456 * if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
2457 */
2458void *loader_dev_ext_gpa(struct loader_instance *inst,
2459                         const char *funcName)
2460{
2461    uint32_t idx;
2462    uint32_t seed = 0;
2463
2464    idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
2465
2466    if (loader_name_in_dev_ext_table(inst, &idx, funcName))
2467        // found funcName already in hash
2468        return loader_get_dev_ext_trampoline(idx);
2469
2470    // Check if funcName is supported in either ICDs or a layer library
2471    if (!loader_check_icds_for_address(inst, funcName)) {
2472        // TODO Add check in layer libraries for support of address
2473        // if support found in layers continue on
2474        return NULL;
2475    }
2476
2477    if (loader_add_dev_ext_table(inst, &idx, funcName)) {
2478        // successfully added new table entry
2479        // init any dev dispatch table entrys as needed
2480        loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
2481        return loader_get_dev_ext_trampoline(idx);
2482    }
2483
2484    return NULL;
2485}
2486
2487struct loader_instance *loader_get_instance(const VkInstance instance)
2488{
2489    /* look up the loader_instance in our list by comparing dispatch tables, as
2490     * there is no guarantee the instance is still a loader_instance* after any
2491     * layers which wrap the instance object.
2492     */
2493    const VkLayerInstanceDispatchTable *disp;
2494    struct loader_instance *ptr_instance = NULL;
2495    disp = loader_get_instance_dispatch(instance);
2496    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
2497        if (inst->disp == disp) {
2498            ptr_instance = inst;
2499            break;
2500        }
2501    }
2502    return ptr_instance;
2503}
2504
2505static loader_platform_dl_handle loader_add_layer_lib(
2506        const struct loader_instance *inst,
2507        const char *chain_type,
2508        struct loader_layer_properties *layer_prop)
2509{
2510    struct loader_lib_info *new_layer_lib_list, *my_lib;
2511    size_t new_alloc_size;
2512    /*
2513     * TODO: We can now track this information in the
2514     * scanned_layer_libraries list.
2515     */
2516    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
2517        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_name) == 0) {
2518            /* Have already loaded this library, just increment ref count */
2519            loader.loaded_layer_lib_list[i].ref_count++;
2520            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2521                       "%s Chain: Increment layer reference count for layer library %s",
2522                       chain_type, layer_prop->lib_name);
2523            return loader.loaded_layer_lib_list[i].lib_handle;
2524        }
2525    }
2526
2527    /* Haven't seen this library so load it */
2528    new_alloc_size = 0;
2529    if (loader.loaded_layer_lib_capacity == 0)
2530        new_alloc_size = 8 * sizeof(struct loader_lib_info);
2531    else if (loader.loaded_layer_lib_capacity <= loader.loaded_layer_lib_count *
2532                                            sizeof(struct loader_lib_info))
2533        new_alloc_size = loader.loaded_layer_lib_capacity * 2;
2534
2535    if (new_alloc_size) {
2536        new_layer_lib_list = loader_heap_realloc(
2537                                            inst, loader.loaded_layer_lib_list,
2538                                            loader.loaded_layer_lib_capacity,
2539                                            new_alloc_size,
2540                                            VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2541        if (!new_layer_lib_list) {
2542            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: realloc failed in loader_add_layer_lib");
2543            return NULL;
2544        }
2545        loader.loaded_layer_lib_capacity = new_alloc_size;
2546    } else
2547        new_layer_lib_list = loader.loaded_layer_lib_list;
2548    my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
2549
2550    strncpy(my_lib->lib_name, layer_prop->lib_name, sizeof(my_lib->lib_name));
2551    my_lib->lib_name[sizeof(my_lib->lib_name) - 1] = '\0';
2552    my_lib->ref_count = 0;
2553    my_lib->lib_handle = NULL;
2554
2555    if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
2556        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2557                   loader_platform_open_library_error(my_lib->lib_name));
2558        return NULL;
2559    } else {
2560        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2561                   "Chain: %s: Loading layer library %s",
2562                   chain_type, layer_prop->lib_name);
2563    }
2564    loader.loaded_layer_lib_count++;
2565    loader.loaded_layer_lib_list = new_layer_lib_list;
2566    my_lib->ref_count++;
2567
2568    return my_lib->lib_handle;
2569}
2570
2571static void loader_remove_layer_lib(
2572        struct loader_instance *inst,
2573        struct loader_layer_properties *layer_prop)
2574{
2575    uint32_t idx;
2576    struct loader_lib_info *new_layer_lib_list, *my_lib = NULL;
2577
2578    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
2579        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_name) == 0) {
2580            /* found matching library */
2581            idx = i;
2582            my_lib = &loader.loaded_layer_lib_list[i];
2583            break;
2584        }
2585    }
2586
2587    if (my_lib) {
2588        my_lib->ref_count--;
2589        if (my_lib->ref_count > 0) {
2590            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2591                       "Decrement reference count for layer library %s", layer_prop->lib_name);
2592            return;
2593        }
2594    }
2595    loader_platform_close_library(my_lib->lib_handle);
2596    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2597               "Unloading layer library %s", layer_prop->lib_name);
2598
2599    /* Need to remove unused library from list */
2600    new_layer_lib_list = loader_heap_alloc(inst,
2601                                           loader.loaded_layer_lib_capacity,
2602                                           VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2603    if (!new_layer_lib_list) {
2604        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: heap alloc failed loader_remove_layer_library");
2605        return;
2606    }
2607
2608    if (idx > 0) {
2609        /* Copy records before idx */
2610        memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
2611               sizeof(struct loader_lib_info) * idx);
2612    }
2613    if (idx < (loader.loaded_layer_lib_count - 1)) {
2614        /* Copy records after idx */
2615        memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
2616                sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
2617    }
2618
2619    loader_heap_free(inst, loader.loaded_layer_lib_list);
2620    loader.loaded_layer_lib_count--;
2621    loader.loaded_layer_lib_list = new_layer_lib_list;
2622}
2623
2624
2625/**
2626 * Go through the search_list and find any layers which match type. If layer
2627 * type match is found in then add it to ext_list.
2628 */
2629//TODO need to handle implict layer enable env var and disable env var
2630static void loader_add_layer_implicit(
2631                const struct loader_instance *inst,
2632                const enum layer_type type,
2633                struct loader_layer_list *list,
2634                const struct loader_layer_list *search_list)
2635{
2636    uint32_t i;
2637    for (i = 0; i < search_list->count; i++) {
2638        const struct loader_layer_properties *prop = &search_list->list[i];
2639        if (prop->type & type) {
2640            /* Found an layer with the same type, add to layer_list */
2641            loader_add_to_layer_list(inst, list, 1, prop);
2642        }
2643    }
2644
2645}
2646
2647/**
2648 * Get the layer name(s) from the env_name environment variable. If layer
2649 * is found in search_list then add it to layer_list.  But only add it to
2650 * layer_list if type matches.
2651 */
2652static void loader_add_layer_env(
2653                const struct loader_instance *inst,
2654                const enum layer_type type,
2655                const char *env_name,
2656                struct loader_layer_list *layer_list,
2657                const struct loader_layer_list *search_list)
2658{
2659    char *layerEnv;
2660    char *next, *name;
2661
2662    layerEnv = getenv(env_name);
2663    if (layerEnv == NULL) {
2664        return;
2665    }
2666    name = loader_stack_alloc(strlen(layerEnv) + 1);
2667    if (name == NULL) {
2668        return;
2669    }
2670    strcpy(name, layerEnv);
2671
2672    while (name && *name ) {
2673        next = loader_get_next_path(name);
2674        loader_find_layer_name_add_list(inst, name, type, search_list, layer_list);
2675        name = next;
2676    }
2677
2678    return;
2679}
2680
2681void loader_deactivate_instance_layers(struct loader_instance *instance)
2682{
2683    if (!instance->activated_layer_list.count) {
2684        return;
2685    }
2686
2687    /* Create instance chain of enabled layers */
2688    for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
2689        struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
2690
2691        loader_remove_layer_lib(instance, layer_prop);
2692    }
2693    loader_destroy_layer_list(instance, &instance->activated_layer_list);
2694}
2695
2696VkResult loader_enable_instance_layers(
2697                    struct loader_instance *inst,
2698                    const VkInstanceCreateInfo *pCreateInfo,
2699                    const struct loader_layer_list *instance_layers)
2700{
2701    VkResult err;
2702
2703    assert(inst && "Cannot have null instance");
2704
2705    if (!loader_init_layer_list(inst, &inst->activated_layer_list)) {
2706        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to alloc Instance activated layer list");
2707        return VK_ERROR_OUT_OF_HOST_MEMORY;
2708    }
2709
2710    /* Add any implicit layers first */
2711    loader_add_layer_implicit(
2712                                inst,
2713                                VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2714                                &inst->activated_layer_list,
2715                                instance_layers);
2716
2717    /* Add any layers specified via environment variable next */
2718    loader_add_layer_env(
2719                            inst,
2720                            VK_LAYER_TYPE_INSTANCE_EXPLICIT,
2721                            "VK_INSTANCE_LAYERS",
2722                            &inst->activated_layer_list,
2723                            instance_layers);
2724
2725    /* Add layers specified by the application */
2726    err = loader_add_layer_names_to_list(
2727                inst,
2728                &inst->activated_layer_list,
2729                pCreateInfo->enabledLayerNameCount,
2730                pCreateInfo->ppEnabledLayerNames,
2731                instance_layers);
2732
2733    return err;
2734}
2735
2736uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2737{
2738    uint32_t layer_idx;
2739    VkBaseLayerObject *wrappedInstance;
2740
2741    if (inst == NULL) {
2742        return 0;
2743    }
2744
2745    // NOTE inst is unwrapped at this point in time
2746    void* baseObj = (void*) inst;
2747    void* nextObj = (void*) inst;
2748    VkBaseLayerObject *nextInstObj;
2749    PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2750
2751    if (!inst->activated_layer_list.count) {
2752        loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
2753        return 0;
2754    }
2755
2756    wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
2757                                   * inst->activated_layer_list.count);
2758    if (!wrappedInstance) {
2759        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to alloc Instance objects for layer");
2760        return 0;
2761    }
2762
2763    /* Create instance chain of enabled layers */
2764    layer_idx = inst->activated_layer_list.count - 1;
2765    for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
2766        struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
2767        loader_platform_dl_handle lib_handle;
2768
2769         /*
2770         * Note: An extension's Get*ProcAddr should not return a function pointer for
2771         * any extension entry points until the extension has been enabled.
2772         * To do this requires a different behavior from Get*ProcAddr functions implemented
2773         * in layers.
2774         * The very first call to a layer will be it's Get*ProcAddr function requesting
2775         * the layer's vkGet*ProcAddr. The layer should initialize its internal dispatch table
2776         * with the wrapped object given (either Instance or Device) and return the layer's
2777         * Get*ProcAddr function. The layer should also use this opportunity to record the
2778         * baseObject so that it can find the correct local dispatch table on future calls.
2779         * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2780         * will not use a wrapped object and must look up their local dispatch table from
2781         * the given baseObject.
2782         */
2783        nextInstObj = (wrappedInstance + layer_idx);
2784        nextInstObj->pGPA = (PFN_vkGPA) nextGPA;
2785        nextInstObj->baseObject = baseObj;
2786        nextInstObj->nextObject = nextObj;
2787        nextObj = (void*) nextInstObj;
2788
2789        lib_handle = loader_add_layer_lib(inst, "instance", layer_prop);
2790        if (!lib_handle)
2791            continue;   // TODO what should we do in this case
2792        if ((nextGPA = layer_prop->functions.get_instance_proc_addr) == NULL) {
2793            if (layer_prop->functions.str_gipa == NULL || strlen(layer_prop->functions.str_gipa) == 0) {
2794                nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
2795                layer_prop->functions.get_instance_proc_addr = nextGPA;
2796            } else
2797                nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
2798            if (!nextGPA) {
2799                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_name);
2800
2801                /* TODO: Should we return nextObj, nextGPA to previous? or decrement layer_list count*/
2802                continue;
2803            }
2804        }
2805
2806        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
2807                   "Insert instance layer %s (%s)",
2808                   layer_prop->info.layerName,
2809                   layer_prop->lib_name);
2810
2811        layer_idx--;
2812    }
2813
2814    loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
2815
2816    return inst->activated_layer_list.count;
2817}
2818
2819void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2820{
2821
2822    loader_init_instance_extension_dispatch_table(inst->disp,
2823                                                  inst->disp->GetInstanceProcAddr,
2824                                                  (VkInstance) inst);
2825}
2826
2827static VkResult loader_enable_device_layers(
2828                        const struct loader_instance *inst,
2829                        struct loader_icd *icd,
2830                        struct loader_device *dev,
2831                        const VkDeviceCreateInfo *pCreateInfo,
2832                        const struct loader_layer_list *device_layers)
2833
2834{
2835    VkResult err;
2836
2837    assert(dev && "Cannot have null device");
2838
2839    if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
2840        loader_init_layer_list(inst, &dev->activated_layer_list);
2841    }
2842
2843    if (dev->activated_layer_list.list == NULL) {
2844        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to alloc device activated layer list");
2845        return VK_ERROR_OUT_OF_HOST_MEMORY;
2846    }
2847
2848    /* Add any implicit layers first */
2849    loader_add_layer_implicit(
2850                inst,
2851                VK_LAYER_TYPE_DEVICE_IMPLICIT,
2852                &dev->activated_layer_list,
2853                device_layers);
2854
2855    /* Add any layers specified via environment variable next */
2856    loader_add_layer_env(
2857                inst,
2858                VK_LAYER_TYPE_DEVICE_EXPLICIT,
2859                "VK_DEVICE_LAYERS",
2860                &dev->activated_layer_list,
2861                device_layers);
2862
2863    /* Add layers specified by the application */
2864    err = loader_add_layer_names_to_list(
2865                inst,
2866                &dev->activated_layer_list,
2867                pCreateInfo->enabledLayerNameCount,
2868                pCreateInfo->ppEnabledLayerNames,
2869                device_layers);
2870
2871    return err;
2872}
2873
2874/*
2875 * This function terminates the device chain for CreateDevice.
2876 * CreateDevice is a special case and so the loader call's
2877 * the ICD's CreateDevice before creating the chain. Since
2878 * we can't call CreateDevice twice we must terminate the
2879 * device chain with something else.
2880 */
2881static VKAPI_ATTR VkResult VKAPI_CALL scratch_vkCreateDevice(
2882    VkPhysicalDevice          physicalDevice,
2883    const VkDeviceCreateInfo *pCreateInfo,
2884    const VkAllocationCallbacks*   pAllocator,
2885    VkDevice                 *pDevice)
2886{
2887    return VK_SUCCESS;
2888}
2889
2890static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2891{
2892    if (!strcmp(name, "vkGetDeviceProcAddr"))
2893        return (PFN_vkVoidFunction) loader_GetDeviceChainProcAddr;
2894    if (!strcmp(name, "vkCreateDevice"))
2895        return (PFN_vkVoidFunction) scratch_vkCreateDevice;
2896
2897    struct loader_device *found_dev;
2898    struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2899    return icd->GetDeviceProcAddr(device, name);
2900}
2901
2902static uint32_t loader_activate_device_layers(
2903        const struct loader_instance *inst,
2904        struct loader_device *dev,
2905        VkDevice device)
2906{
2907    if (!dev) {
2908        return 0;
2909    }
2910
2911    /* activate any layer libraries */
2912    void* nextObj = (void*) device;
2913    void* baseObj = nextObj;
2914    VkBaseLayerObject *nextGpuObj;
2915    PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
2916    VkBaseLayerObject *wrappedGpus;
2917
2918    if (!dev->activated_layer_list.count) {
2919        loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2920            (VkDevice) nextObj, (VkDevice) baseObj);
2921        return 0;
2922    }
2923
2924    wrappedGpus = loader_heap_alloc(inst,
2925                    sizeof (VkBaseLayerObject) * dev->activated_layer_list.count,
2926                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2927    if (!wrappedGpus) {
2928        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to alloc Gpu objects for layer");
2929        return 0;
2930    }
2931
2932    for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2933
2934        struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
2935        loader_platform_dl_handle lib_handle;
2936
2937        nextGpuObj = (wrappedGpus + i);
2938        nextGpuObj->pGPA = (PFN_vkGPA)nextGPA;
2939        nextGpuObj->baseObject = baseObj;
2940        nextGpuObj->nextObject = nextObj;
2941        nextObj = (void*) nextGpuObj;
2942
2943        lib_handle = loader_add_layer_lib(inst, "device", layer_prop);
2944        if ((nextGPA = layer_prop->functions.get_device_proc_addr) == NULL) {
2945            if (layer_prop->functions.str_gdpa == NULL || strlen(layer_prop->functions.str_gdpa) == 0) {
2946                nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2947                layer_prop->functions.get_device_proc_addr = nextGPA;
2948            } else
2949                nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
2950            if (!nextGPA) {
2951                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->lib_name);
2952                continue;
2953            }
2954        }
2955
2956        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
2957                   "Insert device layer library %s (%s)",
2958                   layer_prop->info.layerName,
2959                   layer_prop->lib_name);
2960
2961    }
2962
2963    loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2964            (VkDevice) nextObj, (VkDevice) baseObj);
2965    loader_heap_free(inst, wrappedGpus);
2966
2967    return dev->activated_layer_list.count;
2968}
2969
2970VkResult loader_validate_layers(
2971        const uint32_t                  layer_count,
2972        const char * const             *ppEnabledLayerNames,
2973        const struct loader_layer_list *list)
2974{
2975    struct loader_layer_properties *prop;
2976
2977    for (uint32_t i = 0; i < layer_count; i++) {
2978        prop = loader_get_layer_property(ppEnabledLayerNames[i],
2979                                  list);
2980        if (!prop) {
2981            return VK_ERROR_LAYER_NOT_PRESENT;
2982        }
2983    }
2984
2985    return VK_SUCCESS;
2986}
2987
2988VkResult loader_validate_instance_extensions(
2989                        const struct loader_extension_list *icd_exts,
2990                        const struct loader_layer_list *instance_layer,
2991                        const VkInstanceCreateInfo     *pCreateInfo)
2992{
2993    VkExtensionProperties *extension_prop;
2994    struct loader_layer_properties *layer_prop;
2995
2996    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) {
2997        extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2998                                                icd_exts);
2999
3000        if (extension_prop) {
3001            continue;
3002        }
3003
3004        extension_prop = NULL;
3005
3006        /* Not in global list, search layer extension lists */
3007        for (uint32_t j = 0; j < pCreateInfo->enabledLayerNameCount; j++) {
3008            layer_prop = loader_get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
3009                                            instance_layer);
3010            if (!layer_prop) {
3011                /* Should NOT get here, loader_validate_layers
3012                 * should have already filtered this case out.
3013                 */
3014                continue;
3015            }
3016
3017            extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
3018                                          &layer_prop->instance_extension_list);
3019            if (extension_prop) {
3020                /* Found the extension in one of the layers enabled by the app. */
3021                break;
3022            }
3023        }
3024
3025        if (!extension_prop) {
3026            /* Didn't find extension name in any of the global layers, error out */
3027            return VK_ERROR_EXTENSION_NOT_PRESENT;
3028        }
3029    }
3030    return VK_SUCCESS;
3031}
3032
3033VkResult loader_validate_device_extensions(
3034                                struct loader_physical_device *phys_dev,
3035                                const struct loader_layer_list *device_layer,
3036                                const VkDeviceCreateInfo *pCreateInfo)
3037{
3038    VkExtensionProperties *extension_prop;
3039    struct loader_layer_properties *layer_prop;
3040
3041    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) {
3042        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
3043        extension_prop = get_extension_property(extension_name,
3044                                                &phys_dev->device_extension_cache);
3045
3046        if (extension_prop) {
3047            continue;
3048        }
3049
3050        /* Not in global list, search layer extension lists */
3051        for (uint32_t j = 0; j < pCreateInfo->enabledLayerNameCount; j++) {
3052            const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
3053            layer_prop = loader_get_layer_property(layer_name,
3054                                  device_layer);
3055
3056            if (!layer_prop) {
3057                /* Should NOT get here, loader_validate_instance_layers
3058                 * should have already filtered this case out.
3059                 */
3060                continue;
3061            }
3062
3063            extension_prop = get_dev_extension_property(extension_name,
3064                                          &layer_prop->device_extension_list);
3065            if (extension_prop) {
3066                /* Found the extension in one of the layers enabled by the app. */
3067                break;
3068            }
3069        }
3070
3071        if (!extension_prop) {
3072            /* Didn't find extension name in any of the device layers, error out */
3073            return VK_ERROR_EXTENSION_NOT_PRESENT;
3074        }
3075    }
3076    return VK_SUCCESS;
3077}
3078
3079VKAPI_ATTR VkResult VKAPI_CALL loader_CreateInstance(
3080        const VkInstanceCreateInfo*     pCreateInfo,
3081        const VkAllocationCallbacks*         pAllocator,
3082        VkInstance*                     pInstance)
3083{
3084    struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
3085    struct loader_icd *icd;
3086    VkExtensionProperties *prop;
3087    char **filtered_extension_names = NULL;
3088    VkInstanceCreateInfo icd_create_info;
3089    VkResult res = VK_SUCCESS;
3090    bool success = false;
3091
3092    memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
3093
3094    icd_create_info.enabledLayerNameCount = 0;
3095    icd_create_info.ppEnabledLayerNames = NULL;
3096
3097    /*
3098     * NOTE: Need to filter the extensions to only those
3099     * supported by the ICD.
3100     * No ICD will advertise support for layers. An ICD
3101     * library could support a layer, but it would be
3102     * independent of the actual ICD, just in the same library.
3103     */
3104    filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionNameCount * sizeof(char *));
3105    if (!filtered_extension_names) {
3106        return VK_ERROR_OUT_OF_HOST_MEMORY;
3107    }
3108    icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
3109
3110    for (uint32_t i = 0; i < ptr_instance->icd_libs.count; i++) {
3111        icd = loader_icd_add(ptr_instance, &ptr_instance->icd_libs.list[i]);
3112        if (icd) {
3113            icd_create_info.enabledExtensionNameCount = 0;
3114            for (uint32_t i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) {
3115                prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
3116                                              &ptr_instance->ext_list);
3117                if (prop) {
3118                    filtered_extension_names[icd_create_info.enabledExtensionNameCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
3119                    icd_create_info.enabledExtensionNameCount++;
3120                }
3121            }
3122
3123            res = ptr_instance->icd_libs.list[i].CreateInstance(&icd_create_info,
3124                                           pAllocator,
3125                                           &(icd->instance));
3126            if (res == VK_SUCCESS)
3127                success = loader_icd_init_entrys(
3128                                icd,
3129                                icd->instance,
3130                                ptr_instance->icd_libs.list[i].GetInstanceProcAddr);
3131
3132            if (res != VK_SUCCESS || !success)
3133            {
3134                ptr_instance->icds = ptr_instance->icds->next;
3135                loader_icd_destroy(ptr_instance, icd);
3136                icd->instance = VK_NULL_HANDLE;
3137                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
3138                        "ICD ignored: failed to CreateInstance and find entrypoints with ICD");
3139            }
3140        }
3141    }
3142
3143    /*
3144     * If no ICDs were added to instance list and res is unchanged
3145     * from it's initial value, the loader was unable to find
3146     * a suitable ICD.
3147     */
3148    if (ptr_instance->icds == NULL) {
3149        if (res == VK_SUCCESS) {
3150            return VK_ERROR_INCOMPATIBLE_DRIVER;
3151        } else {
3152            return res;
3153        }
3154    }
3155
3156    return VK_SUCCESS;
3157}
3158
3159VKAPI_ATTR void VKAPI_CALL loader_DestroyInstance(
3160        VkInstance                                instance,
3161        const VkAllocationCallbacks*                   pAllocator)
3162{
3163    struct loader_instance *ptr_instance = loader_instance(instance);
3164    struct loader_icd *icds = ptr_instance->icds;
3165    struct loader_icd *next_icd;
3166
3167    // Remove this instance from the list of instances:
3168    struct loader_instance *prev = NULL;
3169    struct loader_instance *next = loader.instances;
3170    while (next != NULL) {
3171        if (next == ptr_instance) {
3172            // Remove this instance from the list:
3173            if (prev)
3174                prev->next = next->next;
3175            else
3176                loader.instances = next->next;
3177            break;
3178        }
3179        prev = next;
3180        next = next->next;
3181    }
3182
3183    while (icds) {
3184        if (icds->instance) {
3185            icds->DestroyInstance(icds->instance, pAllocator);
3186        }
3187        next_icd = icds->next;
3188        icds->instance = VK_NULL_HANDLE;
3189        loader_icd_destroy(ptr_instance, icds);
3190
3191        icds = next_icd;
3192    }
3193    loader_delete_layer_properties(ptr_instance, &ptr_instance->device_layer_list);
3194    loader_delete_layer_properties(ptr_instance, &ptr_instance->instance_layer_list);
3195    loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_libs);
3196    loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)
3197                                &ptr_instance->ext_list);
3198    for (uint32_t i = 0; i < ptr_instance->total_gpu_count; i++)
3199        loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)
3200                            &ptr_instance->phys_devs[i].device_extension_cache);
3201    loader_heap_free(ptr_instance, ptr_instance->phys_devs);
3202    loader_free_dev_ext_table(ptr_instance);
3203}
3204
3205VkResult loader_init_physical_device_info(struct loader_instance *ptr_instance)
3206{
3207    struct loader_icd *icd;
3208    uint32_t i, j, idx, count = 0;
3209    VkResult res;
3210    struct loader_phys_dev_per_icd *phys_devs;
3211
3212    ptr_instance->total_gpu_count = 0;
3213    phys_devs = (struct loader_phys_dev_per_icd *) loader_stack_alloc(
3214                            sizeof(struct loader_phys_dev_per_icd) *
3215                            ptr_instance->total_icd_count);
3216    if (!phys_devs)
3217        return VK_ERROR_OUT_OF_HOST_MEMORY;
3218
3219    icd = ptr_instance->icds;
3220    for (i = 0; i < ptr_instance->total_icd_count; i++) {
3221        assert(icd);
3222        res = icd->EnumeratePhysicalDevices(icd->instance, &phys_devs[i].count, NULL);
3223        if (res != VK_SUCCESS)
3224            return res;
3225        count += phys_devs[i].count;
3226        icd = icd->next;
3227    }
3228
3229    ptr_instance->phys_devs = (struct loader_physical_device *) loader_heap_alloc(
3230                                        ptr_instance,
3231                                        count * sizeof(struct loader_physical_device),
3232                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3233    if (!ptr_instance->phys_devs)
3234        return VK_ERROR_OUT_OF_HOST_MEMORY;
3235
3236    icd = ptr_instance->icds;
3237
3238    struct loader_physical_device *inst_phys_devs = ptr_instance->phys_devs;
3239    idx = 0;
3240    for (i = 0; i < ptr_instance->total_icd_count; i++) {
3241        assert(icd);
3242
3243        phys_devs[i].phys_devs = (VkPhysicalDevice *) loader_stack_alloc(
3244                        phys_devs[i].count * sizeof(VkPhysicalDevice));
3245        if (!phys_devs[i].phys_devs) {
3246            loader_heap_free(ptr_instance, ptr_instance->phys_devs);
3247            ptr_instance->phys_devs = NULL;
3248            return VK_ERROR_OUT_OF_HOST_MEMORY;
3249        }
3250        res = icd->EnumeratePhysicalDevices(
3251                                        icd->instance,
3252                                        &(phys_devs[i].count),
3253                                        phys_devs[i].phys_devs);
3254        if ((res == VK_SUCCESS)) {
3255            ptr_instance->total_gpu_count += phys_devs[i].count;
3256            for (j = 0; j < phys_devs[i].count; j++) {
3257
3258                // initialize the loader's physicalDevice object
3259                loader_set_dispatch((void *) &inst_phys_devs[idx], ptr_instance->disp);
3260                inst_phys_devs[idx].this_instance = ptr_instance;
3261                inst_phys_devs[idx].this_icd = icd;
3262                inst_phys_devs[idx].phys_dev = phys_devs[i].phys_devs[j];
3263                memset(&inst_phys_devs[idx].device_extension_cache, 0, sizeof(struct loader_extension_list));
3264
3265                idx++;
3266            }
3267        } else {
3268            loader_heap_free(ptr_instance, ptr_instance->phys_devs);
3269            ptr_instance->phys_devs = NULL;
3270            return res;
3271        }
3272
3273        icd = icd->next;
3274    }
3275
3276    return VK_SUCCESS;
3277}
3278
3279VKAPI_ATTR VkResult VKAPI_CALL loader_EnumeratePhysicalDevices(
3280        VkInstance                              instance,
3281        uint32_t*                               pPhysicalDeviceCount,
3282        VkPhysicalDevice*                       pPhysicalDevices)
3283{
3284    uint32_t i;
3285    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
3286    VkResult res = VK_SUCCESS;
3287
3288    if (ptr_instance->total_gpu_count == 0) {
3289        res = loader_init_physical_device_info(ptr_instance);
3290    }
3291
3292    *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
3293    if (!pPhysicalDevices) {
3294        return res;
3295    }
3296
3297    for (i = 0; i < ptr_instance->total_gpu_count; i++) {
3298        pPhysicalDevices[i] = (VkPhysicalDevice) &ptr_instance->phys_devs[i];
3299    }
3300
3301    return res;
3302}
3303
3304VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceProperties(
3305        VkPhysicalDevice                        physicalDevice,
3306        VkPhysicalDeviceProperties*             pProperties)
3307{
3308    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3309    struct loader_icd *icd = phys_dev->this_icd;
3310
3311    if (icd->GetPhysicalDeviceProperties)
3312        icd->GetPhysicalDeviceProperties(phys_dev->phys_dev, pProperties);
3313}
3314
3315VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceQueueFamilyProperties (
3316        VkPhysicalDevice                        physicalDevice,
3317        uint32_t*                               pQueueFamilyPropertyCount,
3318        VkQueueFamilyProperties*                pProperties)
3319{
3320    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3321    struct loader_icd *icd = phys_dev->this_icd;
3322
3323    if (icd->GetPhysicalDeviceQueueFamilyProperties)
3324        icd->GetPhysicalDeviceQueueFamilyProperties(phys_dev->phys_dev, pQueueFamilyPropertyCount, pProperties);
3325}
3326
3327VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceMemoryProperties (
3328        VkPhysicalDevice physicalDevice,
3329        VkPhysicalDeviceMemoryProperties* pProperties)
3330{
3331    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3332    struct loader_icd *icd = phys_dev->this_icd;
3333
3334    if (icd->GetPhysicalDeviceMemoryProperties)
3335        icd->GetPhysicalDeviceMemoryProperties(phys_dev->phys_dev, pProperties);
3336}
3337
3338VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceFeatures(
3339        VkPhysicalDevice                        physicalDevice,
3340        VkPhysicalDeviceFeatures*               pFeatures)
3341{
3342    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3343    struct loader_icd *icd = phys_dev->this_icd;
3344
3345    if (icd->GetPhysicalDeviceFeatures)
3346        icd->GetPhysicalDeviceFeatures(phys_dev->phys_dev, pFeatures);
3347}
3348
3349VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceFormatProperties(
3350        VkPhysicalDevice                        physicalDevice,
3351        VkFormat                                format,
3352        VkFormatProperties*                     pFormatInfo)
3353{
3354    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3355    struct loader_icd *icd = phys_dev->this_icd;
3356
3357    if (icd->GetPhysicalDeviceFormatProperties)
3358        icd->GetPhysicalDeviceFormatProperties(phys_dev->phys_dev, format, pFormatInfo);
3359}
3360
3361VKAPI_ATTR VkResult VKAPI_CALL loader_GetPhysicalDeviceImageFormatProperties(
3362        VkPhysicalDevice                        physicalDevice,
3363        VkFormat                                format,
3364        VkImageType                             type,
3365        VkImageTiling                           tiling,
3366        VkImageUsageFlags                       usage,
3367        VkImageCreateFlags                      flags,
3368        VkImageFormatProperties*                pImageFormatProperties)
3369{
3370    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3371    struct loader_icd *icd = phys_dev->this_icd;
3372
3373    if (!icd->GetPhysicalDeviceImageFormatProperties)
3374        return VK_ERROR_INITIALIZATION_FAILED;
3375
3376    return icd->GetPhysicalDeviceImageFormatProperties(phys_dev->phys_dev, format,
3377            type, tiling, usage, flags, pImageFormatProperties);
3378}
3379
3380VKAPI_ATTR void VKAPI_CALL loader_GetPhysicalDeviceSparseImageFormatProperties(
3381        VkPhysicalDevice                        physicalDevice,
3382        VkFormat                                format,
3383        VkImageType                             type,
3384        VkSampleCountFlagBits                   samples,
3385        VkImageUsageFlags                       usage,
3386        VkImageTiling                           tiling,
3387        uint32_t*                               pNumProperties,
3388        VkSparseImageFormatProperties*          pProperties)
3389{
3390    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3391    struct loader_icd *icd = phys_dev->this_icd;
3392
3393    if (icd->GetPhysicalDeviceSparseImageFormatProperties)
3394        icd->GetPhysicalDeviceSparseImageFormatProperties(phys_dev->phys_dev, format, type, samples, usage, tiling, pNumProperties, pProperties);
3395}
3396
3397VKAPI_ATTR VkResult VKAPI_CALL loader_CreateDevice(
3398        VkPhysicalDevice                        physicalDevice,
3399        const VkDeviceCreateInfo*               pCreateInfo,
3400        const VkAllocationCallbacks*            pAllocator,
3401        VkDevice*                               pDevice)
3402{
3403    struct loader_physical_device *phys_dev;
3404    struct loader_icd *icd;
3405    struct loader_device *dev;
3406    struct loader_instance *inst;
3407    VkDeviceCreateInfo device_create_info;
3408    char **filtered_extension_names = NULL;
3409    VkResult res;
3410
3411    assert(pCreateInfo->queueCreateInfoCount >= 1);
3412
3413    //TODO this only works for one physical device per instance
3414    // once CreateDevice layer bootstrapping is done via DeviceCreateInfo
3415    // hopefully don't need this anymore in trampoline code
3416    phys_dev = loader_get_physical_device(physicalDevice);
3417    icd = phys_dev->this_icd;
3418    if (!icd)
3419        return VK_ERROR_INITIALIZATION_FAILED;
3420
3421    inst = phys_dev->this_instance;
3422
3423    if (!icd->CreateDevice) {
3424        return VK_ERROR_INITIALIZATION_FAILED;
3425    }
3426
3427    /* validate any app enabled layers are available */
3428    if (pCreateInfo->enabledLayerNameCount > 0) {
3429        res = loader_validate_layers(pCreateInfo->enabledLayerNameCount,
3430                pCreateInfo->ppEnabledLayerNames,
3431                &inst->device_layer_list);
3432        if (res != VK_SUCCESS) {
3433            return res;
3434        }
3435    }
3436
3437    /* Get the physical device extensions if they haven't been retrieved yet */
3438    if (phys_dev->device_extension_cache.capacity == 0) {
3439        if (!loader_init_generic_list(inst, (struct loader_generic_list *)
3440                                      &phys_dev->device_extension_cache,
3441                                      sizeof(VkExtensionProperties))) {
3442            return VK_ERROR_OUT_OF_HOST_MEMORY;
3443        }
3444        res = loader_add_physical_device_extensions(
3445                            inst, physicalDevice,
3446                            phys_dev->this_icd->this_icd_lib->lib_name,
3447                            &phys_dev->device_extension_cache);
3448        if (res != VK_SUCCESS) {
3449            return res;
3450        }
3451    }
3452    /* make sure requested extensions to be enabled are supported */
3453    res = loader_validate_device_extensions(phys_dev, &inst->device_layer_list, pCreateInfo);
3454    if (res != VK_SUCCESS) {
3455        return res;
3456    }
3457
3458    /*
3459     * NOTE: Need to filter the extensions to only those
3460     * supported by the ICD.
3461     * No ICD will advertise support for layers. An ICD
3462     * library could support a layer, but it would be
3463     * independent of the actual ICD, just in the same library.
3464     */
3465    filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionNameCount * sizeof(char *));
3466    if (!filtered_extension_names) {
3467        return VK_ERROR_OUT_OF_HOST_MEMORY;
3468    }
3469
3470    /* Copy user's data */
3471    memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
3472
3473    /* ICD's do not use layers */
3474    device_create_info.enabledLayerNameCount = 0;
3475    device_create_info.ppEnabledLayerNames = NULL;
3476
3477    device_create_info.enabledExtensionNameCount = 0;
3478    device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
3479
3480    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) {
3481        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
3482        VkExtensionProperties *prop = get_extension_property(extension_name,
3483                                      &phys_dev->device_extension_cache);
3484        if (prop) {
3485            filtered_extension_names[device_create_info.enabledExtensionNameCount] = (char *) extension_name;
3486            device_create_info.enabledExtensionNameCount++;
3487        }
3488    }
3489
3490    // since physicalDevice object maybe wrapped by a layer need to get unwrapped version
3491    // we haven't yet called down the chain for the layer to unwrap the object
3492    res = icd->CreateDevice(phys_dev->phys_dev, pCreateInfo, pAllocator, pDevice);
3493    if (res != VK_SUCCESS) {
3494        return res;
3495    }
3496
3497    dev = loader_add_logical_device(inst, *pDevice, &icd->logical_device_list);
3498    if (dev == NULL) {
3499        return VK_ERROR_OUT_OF_HOST_MEMORY;
3500    }
3501
3502    loader_init_dispatch(*pDevice, &dev->loader_dispatch);
3503
3504    /* activate any layers on device chain which terminates with device*/
3505    res = loader_enable_device_layers(inst, icd, dev, pCreateInfo, &inst->device_layer_list);
3506    if (res != VK_SUCCESS) {
3507        loader_destroy_logical_device(inst, dev);
3508        return res;
3509    }
3510    loader_activate_device_layers(inst, dev, *pDevice);
3511
3512    /* finally can call down the chain */
3513    res = dev->loader_dispatch.core_dispatch.CreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
3514
3515    /* initialize any device extension dispatch entry's from the instance list*/
3516    loader_init_dispatch_dev_ext(inst, dev);
3517
3518    /* initialize WSI device extensions as part of core dispatch since loader has
3519     * dedicated trampoline code for these*/
3520    loader_init_device_extension_dispatch_table(&dev->loader_dispatch,
3521                                                dev->loader_dispatch.core_dispatch.GetDeviceProcAddr,
3522                                                *pDevice);
3523    dev->loader_dispatch.core_dispatch.CreateDevice = icd->CreateDevice;
3524
3525    return res;
3526}
3527
3528/**
3529 * Get an instance level or global level entry point address.
3530 * @param instance
3531 * @param pName
3532 * @return
3533 *    If instance == NULL returns a global level functions only
3534 *    If instance is valid returns a trampoline entry point for all dispatchable Vulkan
3535 *    functions both core and extensions.
3536 */
3537LOADER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char * pName)
3538{
3539
3540    void *addr;
3541
3542    addr = globalGetProcAddr(pName);
3543    if (instance == VK_NULL_HANDLE) {
3544        // get entrypoint addresses that are global (no dispatchable object)
3545
3546        return addr;
3547    } else {
3548        // if a global entrypoint return NULL
3549        if (addr)
3550            return NULL;
3551    }
3552
3553    struct loader_instance *ptr_instance = loader_get_instance(instance);
3554    if (ptr_instance == NULL)
3555        return NULL;
3556    // Return trampoline code for non-global entrypoints including any extensions.
3557    // Device extensions are returned if a layer or ICD supports the extension.
3558    // Instance extensions are returned if the extension is enabled and the loader
3559    // or someone else supports the extension
3560    return trampolineGetProcAddr(ptr_instance, pName);
3561
3562}
3563
3564/**
3565 * Get a device level or global level entry point address.
3566 * @param device
3567 * @param pName
3568 * @return
3569 *    If device is valid, returns a device relative entry point for device level
3570 *    entry points both core and extensions.
3571 *    Device relative means call down the device chain.
3572 */
3573LOADER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char * pName)
3574{
3575    void *addr;
3576
3577    /* for entrypoints that loader must handle (ie non-dispatchable or create object)
3578       make sure the loader entrypoint is returned */
3579    addr = loader_non_passthrough_gdpa(pName);
3580    if (addr) {
3581        return addr;
3582    }
3583
3584    /* Although CreateDevice is on device chain it's dispatchable object isn't
3585     * a VkDevice or child of VkDevice so return NULL.
3586     */
3587    if (!strcmp(pName, "CreateDevice"))
3588        return NULL;
3589
3590    /* return the dispatch table entrypoint for the fastest case */
3591    const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
3592    if (disp_table == NULL)
3593        return NULL;
3594
3595    addr = loader_lookup_device_dispatch_table(disp_table, pName);
3596    if (addr)
3597        return addr;
3598
3599    if (disp_table->GetDeviceProcAddr == NULL)
3600        return NULL;
3601    return disp_table->GetDeviceProcAddr(device, pName);
3602}
3603
3604LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(
3605    const char*                                 pLayerName,
3606    uint32_t*                                   pPropertyCount,
3607    VkExtensionProperties*                      pProperties)
3608{
3609    struct loader_extension_list *global_ext_list=NULL;
3610    struct loader_layer_list instance_layers;
3611    struct loader_extension_list icd_extensions;
3612    struct loader_icd_libs icd_libs;
3613    uint32_t copy_size;
3614
3615    tls_instance = NULL;
3616    memset(&icd_extensions, 0, sizeof(icd_extensions));
3617    memset(&instance_layers, 0, sizeof(instance_layers));
3618    loader_platform_thread_once(&once_init, loader_initialize);
3619
3620    /* get layer libraries if needed */
3621    if (pLayerName && strlen(pLayerName) != 0) {
3622        loader_layer_scan(NULL, &instance_layers, NULL);
3623        for (uint32_t i = 0; i < instance_layers.count; i++) {
3624            struct loader_layer_properties *props = &instance_layers.list[i];
3625            if (strcmp(props->info.layerName, pLayerName) == 0) {
3626               global_ext_list = &props->instance_extension_list;
3627            }
3628        }
3629    }
3630    else {
3631        /* Scan/discover all ICD libraries */
3632        memset(&icd_libs, 0 , sizeof(struct loader_icd_libs));
3633        loader_icd_scan(NULL, &icd_libs);
3634        /* get extensions from all ICD's, merge so no duplicates */
3635        loader_get_icd_loader_instance_extensions(NULL, &icd_libs, &icd_extensions);
3636        loader_scanned_icd_clear(NULL, &icd_libs);
3637        global_ext_list = &icd_extensions;
3638    }
3639
3640    if (global_ext_list == NULL) {
3641	loader_destroy_layer_list(NULL, &instance_layers);
3642        return VK_ERROR_LAYER_NOT_PRESENT;
3643    }
3644
3645    if (pProperties == NULL) {
3646	*pPropertyCount = global_ext_list->count;
3647	loader_destroy_layer_list(NULL, &instance_layers);
3648        loader_destroy_generic_list(NULL, (struct loader_generic_list *)
3649                                    &icd_extensions);
3650        return VK_SUCCESS;
3651    }
3652
3653    copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count;
3654    for (uint32_t i = 0; i < copy_size; i++) {
3655        memcpy(&pProperties[i],
3656               &global_ext_list->list[i],
3657               sizeof(VkExtensionProperties));
3658    }
3659    *pPropertyCount = copy_size;
3660    loader_destroy_generic_list(NULL, (struct loader_generic_list *)
3661                                &icd_extensions);
3662
3663    if (copy_size < global_ext_list->count) {
3664	loader_destroy_layer_list(NULL, &instance_layers);
3665        return VK_INCOMPLETE;
3666    }
3667
3668    loader_destroy_layer_list(NULL, &instance_layers);
3669    return VK_SUCCESS;
3670}
3671
3672LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(
3673    uint32_t*                                   pPropertyCount,
3674    VkLayerProperties*                          pProperties)
3675{
3676
3677    struct loader_layer_list instance_layer_list;
3678    tls_instance = NULL;
3679
3680    loader_platform_thread_once(&once_init, loader_initialize);
3681
3682    uint32_t copy_size;
3683
3684    /* get layer libraries */
3685    memset(&instance_layer_list, 0, sizeof(instance_layer_list));
3686    loader_layer_scan(NULL, &instance_layer_list, NULL);
3687
3688    if (pProperties == NULL) {
3689        *pPropertyCount = instance_layer_list.count;
3690        loader_destroy_layer_list(NULL, &instance_layer_list);
3691        return VK_SUCCESS;
3692    }
3693
3694    copy_size = (*pPropertyCount < instance_layer_list.count) ? *pPropertyCount : instance_layer_list.count;
3695    for (uint32_t i = 0; i < copy_size; i++) {
3696        memcpy(&pProperties[i], &instance_layer_list.list[i].info, sizeof(VkLayerProperties));
3697    }
3698    *pPropertyCount = copy_size;
3699    loader_destroy_layer_list(NULL, &instance_layer_list);
3700
3701    if (copy_size < instance_layer_list.count) {
3702        return VK_INCOMPLETE;
3703    }
3704
3705    return VK_SUCCESS;
3706}
3707
3708VKAPI_ATTR VkResult VKAPI_CALL loader_EnumerateDeviceExtensionProperties(
3709        VkPhysicalDevice                        physicalDevice,
3710        const char*                             pLayerName,
3711        uint32_t*                               pPropertyCount,
3712        VkExtensionProperties*                  pProperties)
3713{
3714    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3715    uint32_t copy_size;
3716
3717    uint32_t count;
3718    struct loader_device_extension_list *dev_ext_list=NULL;
3719
3720    /* get layer libraries if needed */
3721    if (pLayerName && strlen(pLayerName) != 0) {
3722        for (uint32_t i = 0; i < phys_dev->this_instance->device_layer_list.count; i++) {
3723            struct loader_layer_properties *props = &phys_dev->this_instance->device_layer_list.list[i];
3724            if (strcmp(props->info.layerName, pLayerName) == 0) {
3725               dev_ext_list = &props->device_extension_list;
3726            }
3727        }
3728    }
3729    else {
3730        /* this case is during the call down the instance chain */
3731        struct loader_icd *icd = phys_dev->this_icd;
3732        VkResult res;
3733        res = icd->EnumerateDeviceExtensionProperties(phys_dev->phys_dev, NULL, pPropertyCount, pProperties);
3734        if (pProperties != NULL  && res == VK_SUCCESS) {
3735            /* initialize dev_extension list within the physicalDevice object */
3736            res = loader_init_physical_device_extensions(phys_dev->this_instance,
3737                               phys_dev, *pPropertyCount, pProperties,
3738                               &phys_dev->device_extension_cache);
3739        }
3740        return res;
3741    }
3742
3743    count = (dev_ext_list == NULL) ? 0: dev_ext_list->count;
3744    if (pProperties == NULL) {
3745        *pPropertyCount = count;
3746        return VK_SUCCESS;
3747    }
3748
3749    copy_size = *pPropertyCount < count ? *pPropertyCount : count;
3750    for (uint32_t i = 0; i < copy_size; i++) {
3751        memcpy(&pProperties[i],
3752               &dev_ext_list->list[i].props,
3753               sizeof(VkExtensionProperties));
3754    }
3755    *pPropertyCount = copy_size;
3756
3757    if (copy_size < count) {
3758        return VK_INCOMPLETE;
3759    }
3760
3761    return VK_SUCCESS;
3762}
3763
3764VKAPI_ATTR VkResult VKAPI_CALL loader_EnumerateDeviceLayerProperties(
3765        VkPhysicalDevice                        physicalDevice,
3766        uint32_t*                               pPropertyCount,
3767        VkLayerProperties*                      pProperties)
3768{
3769    uint32_t copy_size;
3770    struct loader_physical_device *phys_dev = (struct loader_physical_device *) physicalDevice;
3771
3772    uint32_t count = phys_dev->this_instance->device_layer_list.count;
3773
3774    if (pProperties == NULL) {
3775        *pPropertyCount = count;
3776        return VK_SUCCESS;
3777    }
3778
3779    copy_size = (*pPropertyCount < count) ? *pPropertyCount : count;
3780    for (uint32_t i = 0; i < copy_size; i++) {
3781        memcpy(&pProperties[i], &(phys_dev->this_instance->device_layer_list.list[i].info), sizeof(VkLayerProperties));
3782    }
3783    *pPropertyCount = copy_size;
3784
3785    if (copy_size < count) {
3786        return VK_INCOMPLETE;
3787    }
3788
3789    return VK_SUCCESS;
3790}
3791