loader.c revision 4b7f35fc3bb104e0607102798b4e3cff9990ade3
11be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania/*
21be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Vulkan
31be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *
41be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Copyright (C) 2014 LunarG, Inc.
51be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *
61be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Permission is hereby granted, free of charge, to any person obtaining a
71be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * copy of this software and associated documentation files (the "Software"),
81be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * to deal in the Software without restriction, including without limitation
91be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * and/or sell copies of the Software, and to permit persons to whom the
111be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Software is furnished to do so, subject to the following conditions:
121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *
131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * The above copyright notice and this permission notice shall be included
141be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * in all copies or substantial portions of the Software.
151be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *
161be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
211be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
221be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * DEALINGS IN THE SOFTWARE.
231be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *
241be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Authors:
251be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *   Chia-I Wu <olv@lunarg.com>
261be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *   Jon Ashburn <jon@lunarg.com>
271be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *   Courtney Goeltzenleuchter <courtney@lunarg.com>
281be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *   Ian Elliott <ian@lunarg.com>
291be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania */
301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#define _GNU_SOURCE
311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdio.h>
321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdlib.h>
331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdarg.h>
341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdbool.h>
351be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <string.h>
3641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
371be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <sys/types.h>
3841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#if defined(WIN32)
391be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "dirent_on_windows.h"
4041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#else // WIN32
411be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <dirent.h>
4241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#endif // WIN32
431be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "vk_loader_platform.h"
4441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#include "loader.h"
4541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#include "gpa_helper.h"
461be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "table_ops.h"
471be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "debug_report.h"
481be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "vk_icd.h"
491be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "cJSON.h"
501be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
511be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniavoid loader_add_to_ext_list(
5241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        struct loader_extension_list *ext_list,
531be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        uint32_t prop_list_count,
5441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        const struct loader_extension_property *prop_list);
551be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
5641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic loader_platform_dl_handle loader_add_layer_lib(
5741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        const char *chain_type,
5841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        struct loader_layer_properties *layer_prop);
59fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes
60fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstatic void loader_remove_layer_lib(
61fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes        struct loader_instance *inst,
62fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes        struct loader_layer_properties *layer_prop);
63fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes
64fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstruct loader_struct loader = {0};
65fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes
66fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstatic PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
67fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstatic bool loader_init_ext_list(struct loader_extension_list *ext_info);
68fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes
69fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesenum loader_debug {
70fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes    LOADER_INFO_BIT       = 0x01,
71fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes    LOADER_WARN_BIT       = 0x02,
72fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes    LOADER_PERF_BIT       = 0x04,
73fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes    LOADER_ERROR_BIT      = 0x08,
7441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    LOADER_DEBUG_BIT      = 0x10,
7541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot};
7641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
7741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotuint32_t g_loader_debug = 0;
7841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotuint32_t g_loader_log_msgs = 0;
7941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
8041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot//thread safety lock for accessing global data structures such as "loader"
8141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot// all entrypoints on the instance chain need to be locked except GPA
8241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot// additionally CreateDevice and DestroyDevice needs to be locked
831be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catanialoader_platform_thread_mutex loader_lock;
841be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
851be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania// This table contains the loader's instance dispatch table, which contains
861be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania// default functions if no instance layers are activated.  This contains
871be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania// pointers to "terminator functions".
881be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniaconst VkLayerInstanceDispatchTable instance_disp = {
8941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    .GetInstanceProcAddr = loader_GetInstanceProcAddr,
9041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    .CreateInstance = loader_CreateInstance,
9141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    .DestroyInstance = loader_DestroyInstance,
921be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
931be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceFormatProperties = loader_GetPhysicalDeviceFormatProperties,
951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceImageFormatProperties = loader_GetPhysicalDeviceImageFormatProperties,
961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
971be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
981be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
991be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
1001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
1011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
1021be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
1031be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
1041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .GetPhysicalDeviceSurfaceSupportWSI = loader_GetPhysicalDeviceSurfaceSupportWSI,
1051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
1061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
1071be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania};
1081be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
1091be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
1101be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
1111be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
1121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
1131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniavoid* loader_heap_alloc(
1141be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    struct loader_instance     *instance,
1151be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    size_t                      size,
1161be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    VkSystemAllocType           alloc_type)
1171be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{
1181be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    if (instance && instance->alloc_callbacks.pfnAlloc) {
1191be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        /* TODO: What should default alignment be? 1, 4, 8, other? */
1201be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
1211be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    }
1221be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    return malloc(size);
1231be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania}
1241be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
1251be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniavoid* loader_aligned_heap_alloc(
1261be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    struct loader_instance     *instance,
1271be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    size_t                      size,
1281be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    size_t                      alignment,
12941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    VkSystemAllocType           alloc_type)
1301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{
1311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    if (!instance && instance->alloc_callbacks.pfnAlloc) {
1321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
1331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    }
1341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#if defined(_WIN32)
13541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    return _aligned_malloc(alignment, size);
13641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#else
13741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    return aligned_alloc(alignment, size);
13841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#endif
13941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot}
14041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
14141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotvoid loader_heap_free(
14241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    struct loader_instance     *instance,
14341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    void                       *pMem)
14441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot{
14541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    if (!instance && instance->alloc_callbacks.pfnFree) {
14641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
14741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    }
14841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    free(pMem);
14941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot}
15041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
15141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic void loader_log(VkFlags msg_type, int32_t msg_code,
15241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    const char *format, ...)
15341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot{
15441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    char msg[512];
15541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    va_list ap;
15641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    int ret;
15741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
15841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    if (!(msg_type & g_loader_log_msgs)) {
15941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        return;
16041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    }
16141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
16241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    va_start(ap, format);
16341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    ret = vsnprintf(msg, sizeof(msg), format, ap);
16441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    if ((ret >= (int) sizeof(msg)) || ret < 0) {
16541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        msg[sizeof(msg)-1] = '\0';
16641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    }
16741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    va_end(ap);
16841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
16941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#if defined(WIN32)
17041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    OutputDebugString(msg);
17141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    OutputDebugString("\n");
17241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#endif
17341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    fputs(msg, stderr);
17441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    fputc('\n', stderr);
17541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot}
17641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
17741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#if defined(WIN32)
17841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic char *loader_get_next_path(char *path);
17941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot/**
18041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* Find the list of registry files (names within a key) in key "location".
18141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot*
18241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
18341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* for a list or name/values which are added to a returned list (function return value).
18441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* The DWORD values within the key must be 0 or they are skipped.
1851be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* Function return is a string with a ';'  seperated list of filenames.
1861be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* Function return is NULL if no valid name/value pairs  are found in the key,
1871be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* or the key is not found.
1881be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania*
1891be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* \returns
1901be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* A string list of filenames as pointer.
1911be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* When done using the returned string list, pointer should be freed.
1921be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania*/
1931be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniastatic char *loader_get_registry_files(char *location)
1941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{
1951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    LONG rtn_value;
1961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    HKEY hive, key;
1971be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    DWORD access_flags = KEY_QUERY_VALUE;
1981be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    char name[2048];
1991be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    char *out = NULL;
2001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    char *loc = location;
2011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    char *next;
2021be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    DWORD idx = 0;
2031be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    DWORD name_size = sizeof(name);
2041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    DWORD value;
2051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    DWORD total_size = 4096;
2061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    DWORD value_size = sizeof(value);
2071be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
20841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    while(*loc)
2091be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    {
21041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        next = loader_get_next_path(loc);
21141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        hive = DEFAULT_VK_REGISTRY_HIVE;
2121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
2131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        if (rtn_value != ERROR_SUCCESS) {
21441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            // We didn't find the key.  Try the 32-bit hive (where we've seen the
21541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            // key end up on some people's systems):
21641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            access_flags |= KEY_WOW64_32KEY;
21741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
21841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            if (rtn_value != ERROR_SUCCESS) {
21941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                // We still couldn't find the key, so give up:
22041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                loc = next;
22141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                continue;
22241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            }
22341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        }
22441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
22541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
22641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            if (value_size == sizeof(value) && value == 0) {
22741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                if (out == NULL) {
22841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                    out = malloc(total_size);
22941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                    out[0] = '\0';
2301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                }
2311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                else if (strlen(out) + name_size + 1 > total_size) {
2321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                    out = realloc(out, total_size * 2);
2331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                    total_size *= 2;
2341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                }
2351be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                if (out == NULL) {
2361be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                    loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
2371be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                    return NULL;
2381be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                }
2391be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania                if (strlen(out) == 0)
24041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                     snprintf(out, name_size + 1, "%s", name);
24141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                else
24241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot                     snprintf(out + strlen(out), name_size + 2, "%c%s", PATH_SEPERATOR, name);
24341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            }
24441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            name_size = 2048;
2451be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        }
24641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        loc = next;
24741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    }
2481be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
2491be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    return out;
2501be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania}
2511be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
2521be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#endif // WIN32
2531be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
25441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot/**
25541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * Given string of three part form "maj.min.pat" convert to a vulkan version
25641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * number.
25741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot */
25841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic uint32_t loader_make_version(const char *vers_str)
259fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes{
26041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    uint32_t vers = 0, major, minor, patch;
26141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    char *minor_str= NULL;
26241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    char *patch_str = NULL;
26341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    char *cstr;
26441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    char *str;
26541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
26641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    if (!vers_str)
26741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        return vers;
26841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    cstr = loader_stack_alloc(strlen(vers_str) + 1);
26941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    strcpy(cstr, vers_str);
27041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    while ((str = strchr(cstr, '.')) != NULL) {
2711be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        if (minor_str == NULL) {
2721be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania            minor_str = str + 1;
2731be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania            *str = '\0';
27441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            major = atoi(cstr);
27541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        }
27641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        else if (patch_str == NULL) {
27741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot            patch_str = str + 1;
2781be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania            *str = '\0';
2791be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania            minor = atoi(minor_str);
2801be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        }
2811be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        else {
2821be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania            return vers;
28341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        }
28441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        cstr = str + 1;
28541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    }
28641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    patch = atoi(patch_str);
28741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot
28841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot    return VK_MAKE_VERSION(major, minor, patch);
2891be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
2901be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania}
2911be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
2921be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniabool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
2931be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{
2941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    return strcmp(op1->extName, op2->extName) == 0 ? true : false;
2951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania}
2961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
2971be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania/**
2981be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Search the given ext_array for an extension
2991be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * matching the given vk_ext_prop
3001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania */
3011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniabool has_vk_extension_property_array(
3021be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        const VkExtensionProperties *vk_ext_prop,
3031be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        const uint32_t count,
3041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        const VkExtensionProperties *ext_array)
3051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{
3061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    for (uint32_t i = 0; i < count; i++) {
3071be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania        if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
3081be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania            return true;
3091be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    }
3101be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania    return false;
3111be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania}
3121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania
31341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot/**
31441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * Search the given ext_list for an extension
31541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * matching the given vk_ext_prop
31641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot */
31741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotbool has_vk_extension_property(
31841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        const VkExtensionProperties *vk_ext_prop,
31941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot        const struct loader_extension_list *ext_list)
32041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot{
321    for (uint32_t i = 0; i < ext_list->count; i++) {
322        if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
323            return true;
324    }
325    return false;
326}
327
328static inline bool loader_is_layer_type_device(const enum layer_type type) {
329    if ((type & VK_LAYER_TYPE_DEVICE_EXPLICIT) ||
330                (type & VK_LAYER_TYPE_DEVICE_IMPLICIT))
331        return true;
332    return false;
333}
334
335/*
336 * Search the given layer list for a layer matching the given layer name
337 */
338static struct loader_layer_properties *get_layer_property(
339        const char *name,
340        const struct loader_layer_list *layer_list)
341{
342    for (uint32_t i = 0; i < layer_list->count; i++) {
343        const VkLayerProperties *item = &layer_list->list[i].info;
344        if (strcmp(name, item->layerName) == 0)
345            return &layer_list->list[i];
346    }
347    return NULL;
348}
349
350static void loader_add_global_extensions(
351        const PFN_vkGetGlobalExtensionProperties fp_get_props,
352        const char *lib_name,
353        const loader_platform_dl_handle lib_handle,
354        const enum extension_origin origin,
355        struct loader_extension_list *ext_list)
356{
357    uint32_t i, count;
358    struct loader_extension_property ext_props;
359    VkExtensionProperties *extension_properties;
360    VkResult res;
361
362    if (!fp_get_props) {
363        /* No GetGlobalExtensionProperties defined */
364        return;
365    }
366
367    res = fp_get_props(NULL, &count, NULL);
368    if (res != VK_SUCCESS) {
369        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
370        return;
371    }
372
373    if (count == 0) {
374        /* No ExtensionProperties to report */
375        return;
376    }
377
378    extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
379
380    res = fp_get_props(NULL, &count, extension_properties);
381    if (res != VK_SUCCESS) {
382        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
383        return;
384    }
385
386    for (i = 0; i < count; i++) {
387        memset(&ext_props, 0, sizeof(ext_props));
388        memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
389        //TODO eventually get this from the layer config file
390        ext_props.origin = origin;
391        ext_props.lib_name = lib_name;
392
393        char spec_version[64];
394
395        snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
396                 VK_MAJOR(ext_props.info.specVersion),
397                 VK_MINOR(ext_props.info.specVersion),
398                 VK_PATCH(ext_props.info.specVersion));
399
400        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
401                   "Global Extension: %s (%s) version %s",
402                   ext_props.info.extName, lib_name, spec_version);
403        loader_add_to_ext_list(ext_list, 1, &ext_props);
404    }
405
406    return;
407}
408
409static void loader_add_physical_device_extensions(
410        PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
411        VkPhysicalDevice physical_device,
412        const enum extension_origin origin,
413        const char *lib_name,
414        struct loader_extension_list *ext_list)
415{
416    uint32_t i, count;
417    VkResult res;
418    struct loader_extension_property ext_props;
419    VkExtensionProperties *extension_properties;
420
421    memset(&ext_props, 0, sizeof(ext_props));
422    ext_props.origin = origin;
423    ext_props.lib_name = lib_name;
424
425    if (get_phys_dev_ext_props) {
426        res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
427        if (res == VK_SUCCESS && count > 0) {
428
429            extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
430
431            res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
432            for (i = 0; i < count; i++) {
433                char spec_version[64];
434
435                memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
436
437                snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
438                         VK_MAJOR(ext_props.info.specVersion),
439                         VK_MINOR(ext_props.info.specVersion),
440                         VK_PATCH(ext_props.info.specVersion));
441
442                loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
443                           "PhysicalDevice Extension: %s (%s) version %s",
444                           ext_props.info.extName, lib_name, spec_version);
445                loader_add_to_ext_list(ext_list, 1, &ext_props);
446            }
447        } else {
448            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
449        }
450    }
451
452    return;
453}
454
455static bool loader_init_ext_list(struct loader_extension_list *ext_info)
456{
457    ext_info->capacity = 32 * sizeof(struct loader_extension_property);
458    /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
459    ext_info->list = malloc(ext_info->capacity);
460    if (ext_info->list == NULL) {
461        return false;
462    }
463    memset(ext_info->list, 0, ext_info->capacity);
464    ext_info->count = 0;
465    return true;
466}
467
468void loader_destroy_ext_list(struct loader_extension_list *ext_info)
469{
470    free(ext_info->list);
471    ext_info->count = 0;
472    ext_info->capacity = 0;
473}
474
475/**
476 * Search the given search_list for any layers in the props list.
477 * Add these to the output layer_list.  Don't add duplicates to the output layer_list.
478 */
479static VkResult loader_add_layer_names_to_list(
480        struct loader_layer_list *output_list,
481        uint32_t name_count,
482        const char * const *names,
483        const struct loader_layer_list *search_list)
484{
485    struct loader_layer_properties *layer_prop;
486    VkResult err = VK_SUCCESS;
487
488    for (uint32_t i = 0; i < name_count; i++) {
489        const char *search_target = names[i];
490        layer_prop = get_layer_property(search_target, search_list);
491        if (!layer_prop) {
492            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
493            err = VK_ERROR_INVALID_LAYER;
494            continue;
495        }
496
497        loader_add_to_layer_list(output_list, 1, layer_prop);
498    }
499
500    return err;
501}
502
503/*
504 * Append non-duplicate extension properties defined in props
505 * to the given ext_list.
506 */
507void loader_add_to_ext_list(
508        struct loader_extension_list *ext_list,
509        uint32_t prop_list_count,
510        const struct loader_extension_property *props)
511{
512    uint32_t i;
513    struct loader_extension_property *cur_ext;
514
515    if (ext_list->list == NULL || ext_list->capacity == 0) {
516        loader_init_ext_list(ext_list);
517    }
518
519    if (ext_list->list == NULL)
520        return;
521
522    for (i = 0; i < prop_list_count; i++) {
523        cur_ext = (struct loader_extension_property *) &props[i];
524
525        // look for duplicates
526        if (has_vk_extension_property(&cur_ext->info, ext_list)) {
527            continue;
528        }
529
530        // add to list at end
531        // check for enough capacity
532        if (ext_list->count * sizeof(struct loader_extension_property)
533                        >= ext_list->capacity) {
534            // double capacity
535            ext_list->capacity *= 2;
536            /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
537            ext_list->list = realloc(ext_list->list, ext_list->capacity);
538        }
539
540        memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
541        ext_list->count++;
542    }
543}
544
545/*
546 * Manage lists of VkLayerProperties
547 */
548static bool loader_init_layer_list(struct loader_layer_list *list)
549{
550    list->capacity = 32 * sizeof(struct loader_layer_properties);
551    /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
552    list->list = malloc(list->capacity);
553    if (list->list == NULL) {
554        return false;
555    }
556    memset(list->list, 0, list->capacity);
557    list->count = 0;
558    return true;
559}
560
561void loader_destroy_layer_list(struct loader_layer_list *layer_list)
562{
563    free(layer_list->list);
564    layer_list->count = 0;
565    layer_list->capacity = 0;
566}
567
568/*
569 * Manage list of layer libraries (loader_lib_info)
570 */
571static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
572{
573    list->capacity = 32 * sizeof(struct loader_lib_info);
574    /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
575    list->list = malloc(list->capacity);
576    if (list->list == NULL) {
577        return false;
578    }
579    memset(list->list, 0, list->capacity);
580    list->count = 0;
581    return true;
582}
583
584void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
585{
586    for (uint32_t i = 0; i < list->count; i++) {
587        free(list->list[i].lib_name);
588    }
589    free(list->list);
590    list->count = 0;
591    list->capacity = 0;
592}
593
594void loader_add_to_layer_library_list(
595        struct loader_layer_library_list *list,
596        uint32_t item_count,
597        const struct loader_lib_info *new_items)
598{
599    uint32_t i;
600    struct loader_lib_info *item;
601
602    if (list->list == NULL || list->capacity == 0) {
603        loader_init_layer_library_list(list);
604    }
605
606    if (list->list == NULL)
607        return;
608
609    for (i = 0; i < item_count; i++) {
610        item = (struct loader_lib_info *) &new_items[i];
611
612        // look for duplicates
613        for (uint32_t j = 0; j < list->count; j++) {
614            if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
615                continue;
616            }
617        }
618
619        // add to list at end
620        // check for enough capacity
621        if (list->count * sizeof(struct loader_lib_info)
622                        >= list->capacity) {
623            // double capacity
624            list->capacity *= 2;
625            /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
626            list->list = realloc(list->list, list->capacity);
627        }
628
629        memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
630        list->count++;
631    }
632}
633
634
635/*
636 * Search the given layer list for a list
637 * matching the given VkLayerProperties
638 */
639bool has_vk_layer_property(
640        const VkLayerProperties *vk_layer_prop,
641        const struct loader_layer_list *list)
642{
643    for (uint32_t i = 0; i < list->count; i++) {
644        if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
645            return true;
646    }
647    return false;
648}
649
650/*
651 * Search the given layer list for a layer
652 * matching the given name
653 */
654bool has_layer_name(
655        const char *name,
656        const struct loader_layer_list *list)
657{
658    for (uint32_t i = 0; i < list->count; i++) {
659        if (strcmp(name, list->list[i].info.layerName) == 0)
660            return true;
661    }
662    return false;
663}
664
665/*
666 * Append non-duplicate layer properties defined in prop_list
667 * to the given layer_info list
668 */
669void loader_add_to_layer_list(
670        struct loader_layer_list *list,
671        uint32_t prop_list_count,
672        const struct loader_layer_properties *props)
673{
674    uint32_t i;
675    struct loader_layer_properties *layer;
676
677    if (list->list == NULL || list->capacity == 0) {
678        loader_init_layer_list(list);
679    }
680
681    if (list->list == NULL)
682        return;
683
684    for (i = 0; i < prop_list_count; i++) {
685        layer = (struct loader_layer_properties *) &props[i];
686
687        // look for duplicates
688        if (has_vk_layer_property(&layer->info, list)) {
689            continue;
690        }
691
692        // add to list at end
693        // check for enough capacity
694        if (list->count * sizeof(struct loader_layer_properties)
695                        >= list->capacity) {
696            // double capacity
697            list->capacity *= 2;
698            list->list = realloc(list->list, list->capacity);
699        }
700
701        memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
702        list->count++;
703    }
704}
705
706/**
707 * Search the search_list for any layer with a name
708 * that matches the given name and a type that matches the given type
709 * Add all matching layers to the found_list
710 * Do not add if found loader_layer_properties is already
711 * on the found_list.
712 */
713static void loader_find_layer_name_add_list(
714        const char *name,
715        const enum layer_type type,
716        const struct loader_layer_list *search_list,
717        struct loader_layer_list *found_list)
718{
719    for (uint32_t i = 0; i < search_list->count; i++) {
720        struct loader_layer_properties *layer_prop = &search_list->list[i];
721        if (0 == strcmp(layer_prop->info.layerName, name) &&
722                (layer_prop->type & type)) {
723            /* Found a layer with the same name, add to found_list */
724            loader_add_to_layer_list(found_list, 1, layer_prop);
725        }
726    }
727}
728
729static struct loader_extension_property *get_extension_property(
730        const char *name,
731        const struct loader_extension_list *list)
732{
733    for (uint32_t i = 0; i < list->count; i++) {
734        const VkExtensionProperties *item = &list->list[i].info;
735        if (strcmp(name, item->extName) == 0)
736            return &list->list[i];
737    }
738    return NULL;
739}
740
741/*
742 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
743 * the extension must provide two entry points for the loader to use:
744 * - "trampoline" entry point - this is the address returned by GetProcAddr
745 * and will always do what's necessary to support a global call.
746 * - "terminator" function - this function will be put at the end of the
747 * instance chain and will contain the necessary logica to call / process
748 * the extension for the appropriate ICDs that are available.
749 * There is no generic mechanism for including these functions, the references
750 * must be placed into the appropriate loader entry points.
751 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
752 * loader_coalesce_extensions(void) - add extension records to the list of global
753 * extension available to the app.
754 * instance_disp - add function pointer for terminator function to this array.
755 * The extension itself should be in a separate file that will be
756 * linked directly with the loader.
757 */
758void loader_coalesce_extensions(void)
759{
760    struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
761
762    // traverse scanned icd list adding non-duplicate extensions to the list
763    while (icd_list != NULL) {
764        loader_add_to_ext_list(&loader.global_extensions,
765                               icd_list->global_extension_list.count,
766                               icd_list->global_extension_list.list);
767        icd_list = icd_list->next;
768    };
769
770    // Traverse loader's extensions, adding non-duplicate extensions to the list
771    wsi_swapchain_add_instance_extensions(&loader.global_extensions);
772    debug_report_add_instance_extensions(&loader.global_extensions);
773}
774
775static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
776                                                    struct loader_device **found_dev)
777{
778    *found_dev = NULL;
779    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
780        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
781            for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
782                if (dev->device == device) {
783                    *found_dev = dev;
784                    return icd;
785                }
786        }
787    }
788    return NULL;
789}
790
791static void loader_destroy_logical_device(struct loader_device *dev)
792{
793    free(dev->app_extension_props);
794    if (dev->activated_layer_list.count)
795        loader_destroy_layer_list(&dev->activated_layer_list);
796    free(dev);
797}
798
799static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
800{
801    struct loader_device *new_dev;
802
803    new_dev = malloc(sizeof(struct loader_device));
804    if (!new_dev) {
805        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
806        return NULL;
807    }
808
809    memset(new_dev, 0, sizeof(struct loader_device));
810
811    new_dev->next = *device_list;
812    new_dev->device = dev;
813    *device_list = new_dev;
814    return new_dev;
815}
816
817void loader_remove_logical_device(VkDevice device)
818{
819    struct loader_device *found_dev, *dev, *prev_dev;
820    struct loader_icd *icd;
821    icd = loader_get_icd_and_device(device, &found_dev);
822
823    if (!icd || !found_dev)
824        return;
825
826    prev_dev = NULL;
827    dev = icd->logical_device_list;
828    while (dev && dev != found_dev) {
829        prev_dev = dev;
830        dev = dev->next;
831    }
832
833    if (prev_dev)
834        prev_dev->next = found_dev->next;
835    else
836        icd->logical_device_list = found_dev->next;
837    loader_destroy_logical_device(found_dev);
838}
839
840
841static void loader_icd_destroy(
842        struct loader_instance *ptr_inst,
843        struct loader_icd *icd)
844{
845    ptr_inst->total_icd_count--;
846    free(icd->gpus);
847    for (struct loader_device *dev = icd->logical_device_list; dev; ) {
848        struct loader_device *next_dev = dev->next;
849        loader_destroy_logical_device(dev);
850        dev = next_dev;
851    }
852
853    free(icd);
854}
855
856static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
857{
858    struct loader_icd *icd;
859
860    icd = malloc(sizeof(*icd));
861    if (!icd)
862        return NULL;
863
864    memset(icd, 0, sizeof(*icd));
865
866    icd->scanned_icds = scanned;
867
868    return icd;
869}
870
871static struct loader_icd *loader_icd_add(
872        struct loader_instance *ptr_inst,
873        const struct loader_scanned_icds *scanned)
874{
875    struct loader_icd *icd;
876
877    icd = loader_icd_create(scanned);
878    if (!icd)
879        return NULL;
880
881    /* prepend to the list */
882    icd->next = ptr_inst->icds;
883    ptr_inst->icds = icd;
884    ptr_inst->total_icd_count++;
885
886    return icd;
887}
888
889static void loader_scanned_icd_add(const char *filename)
890{
891    loader_platform_dl_handle handle;
892    PFN_vkCreateInstance fp_create_inst;
893    PFN_vkGetGlobalExtensionProperties fp_get_global_ext_props;
894    PFN_vkGetInstanceProcAddr fp_get_proc_addr;
895    struct loader_scanned_icds *new_node;
896
897    // Used to call: dlopen(filename, RTLD_LAZY);
898    handle = loader_platform_open_library(filename);
899    if (!handle) {
900        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
901        return;
902    }
903
904#define LOOKUP_LD(func_ptr, func) do {                            \
905    func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
906    if (!func_ptr) {                                           \
907        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
908        return;                                                \
909    }                                                          \
910} while (0)
911
912    LOOKUP_LD(fp_get_proc_addr, GetInstanceProcAddr);
913    LOOKUP_LD(fp_create_inst, CreateInstance);
914    LOOKUP_LD(fp_get_global_ext_props, GetGlobalExtensionProperties);
915
916#undef LOOKUP_LD
917
918    new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
919                                                     + strlen(filename) + 1);
920    if (!new_node) {
921        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
922        return;
923    }
924
925    new_node->handle = handle;
926    new_node->GetInstanceProcAddr = fp_get_proc_addr;
927    new_node->CreateInstance = fp_create_inst;
928    new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
929    loader_init_ext_list(&new_node->global_extension_list);
930    loader_init_ext_list(&new_node->device_extension_list);
931    new_node->next = loader.scanned_icd_list;
932
933    new_node->lib_name = (char *) (new_node + 1);
934    if (!new_node->lib_name) {
935        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
936        return;
937    }
938    strcpy(new_node->lib_name, filename);
939
940    loader.scanned_icd_list = new_node;
941
942    loader_add_global_extensions(
943                (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
944                new_node->lib_name,
945                handle,
946                VK_EXTENSION_ORIGIN_ICD,
947                &new_node->global_extension_list);
948}
949
950static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
951{
952    if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
953        return &loader.global_extensions;
954    }
955
956    /* Find and return global extension list for given layer */
957    for (uint32_t i = 0; i < loader.scanned_instance_layers.count; i++) {
958        struct loader_layer_properties *props = &loader.scanned_instance_layers.list[i];
959        if (strcmp(props->info.layerName, pLayerName) == 0) {
960            return &props->instance_extension_list;
961        }
962    }
963
964    return NULL;
965}
966
967
968static void loader_physical_device_extensions(
969        struct loader_icd *icd,
970        uint32_t gpu_idx,
971        const char *layer_name,
972        uint32_t *count,
973        struct loader_extension_list **list)
974{
975    *count = 0;
976    if (layer_name == NULL || (strlen(layer_name) == 0)) {
977        *count = icd->device_extension_cache[gpu_idx].count;
978        *list = &icd->device_extension_cache[gpu_idx];
979        return;
980    }
981    for (uint32_t i = 0; i < loader.scanned_device_layers.count; i++) {
982        struct loader_layer_properties *props = &(loader.scanned_device_layers.list[i]);
983        if ((strcmp(layer_name, props->info.layerName) == 0)) {
984            *count = props->device_extension_list.count;
985            *list = &props->device_extension_list;
986            break;
987        }
988    }
989}
990
991static bool loader_icd_init_entrys(struct loader_icd *icd,
992                                   VkInstance inst,
993                                   const PFN_vkGetInstanceProcAddr fp_gipa)
994{
995    /* initialize entrypoint function pointers */
996
997    #define LOOKUP_GIPA(func, required) do {                       \
998    icd->func = (PFN_vk ##func) fp_gipa(inst, "vk" #func);         \
999    if (!icd->func && required) {                                  \
1000        loader_log(VK_DBG_REPORT_WARN_BIT, 0,                      \
1001              loader_platform_get_proc_address_error("vk" #func)); \
1002        return false;                                              \
1003    }                                                              \
1004    } while (0)
1005
1006    LOOKUP_GIPA(GetDeviceProcAddr, true);
1007    LOOKUP_GIPA(DestroyInstance, true);
1008    LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1009    LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1010    LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
1011    LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
1012    LOOKUP_GIPA(GetPhysicalDeviceLimits, true);
1013    LOOKUP_GIPA(CreateDevice, true);
1014    LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1015    LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
1016    LOOKUP_GIPA(GetPhysicalDeviceQueueCount, true);
1017    LOOKUP_GIPA(GetPhysicalDeviceQueueProperties, true);
1018    LOOKUP_GIPA(GetPhysicalDeviceExtensionProperties, true);
1019    LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
1020    LOOKUP_GIPA(DbgCreateMsgCallback, false);
1021    LOOKUP_GIPA(DbgDestroyMsgCallback, false);
1022    LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportWSI, false);
1023
1024#undef LOOKUP_GIPA
1025
1026    return true;
1027}
1028
1029static void loader_debug_init(void)
1030{
1031    const char *env;
1032
1033    if (g_loader_debug > 0)
1034        return;
1035
1036    g_loader_debug = 0;
1037
1038    /* parse comma-separated debug options */
1039    env = getenv("VK_LOADER_DEBUG");
1040    while (env) {
1041        const char *p = strchr(env, ',');
1042        size_t len;
1043
1044        if (p)
1045            len = p - env;
1046        else
1047            len = strlen(env);
1048
1049        if (len > 0) {
1050            if (strncmp(env, "warn", len) == 0) {
1051                g_loader_debug |= LOADER_WARN_BIT;
1052                g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1053            } else if (strncmp(env, "info", len) == 0) {
1054                g_loader_debug |= LOADER_INFO_BIT;
1055                g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1056            } else if (strncmp(env, "perf", len) == 0) {
1057                g_loader_debug |= LOADER_PERF_BIT;
1058                g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1059            } else if (strncmp(env, "error", len) == 0) {
1060                g_loader_debug |= LOADER_ERROR_BIT;
1061                g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1062            } else if (strncmp(env, "debug", len) == 0) {
1063                g_loader_debug |= LOADER_DEBUG_BIT;
1064                g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1065            }
1066        }
1067
1068        if (!p)
1069            break;
1070
1071        env = p + 1;
1072    }
1073}
1074
1075struct loader_manifest_files {
1076    uint32_t count;
1077    char **filename_list;
1078};
1079
1080/**
1081 * Get next file or dirname given a string list or registry key path
1082 *
1083 * \returns
1084 * A pointer to first char in the next path.
1085 * The next path (or NULL) in the list is returned in next_path.
1086 * Note: input string is modified in some cases. PASS IN A COPY!
1087 */
1088static char *loader_get_next_path(char *path)
1089{
1090    uint32_t len;
1091    char *next;
1092
1093    if (path == NULL)
1094        return NULL;
1095    next = strchr(path, PATH_SEPERATOR);
1096    if (next == NULL) {
1097        len = (uint32_t) strlen(path);
1098        next = path + len;
1099    }
1100    else {
1101        *next = '\0';
1102        next++;
1103    }
1104
1105    return next;
1106}
1107
1108/**
1109 * Given a path which is absolute or relative. Expand the path if relative otherwise
1110 * leave the path unmodified if absolute. The path which is relative from is
1111 * given in rel_base and should include trailing directory seperator '/'
1112 *
1113 * \returns
1114 * A string in out_fullpath of the full absolute path
1115 * Side effect is that dir string maybe modified.
1116 */
1117static void loader_expand_path(const char *path,
1118                               const char *rel_base,
1119                               size_t out_size,
1120                               char *out_fullpath)
1121{
1122    if (loader_platform_is_path_absolute(path)) {
1123        strncpy(out_fullpath, path, out_size);
1124        out_fullpath[out_size - 1] = '\0';
1125    }
1126    else {
1127        // convert relative to absolute path based on rel_base
1128        size_t len = strlen(path);
1129        strncpy(out_fullpath, rel_base, out_size);
1130        out_fullpath[out_size - 1] = '\0';
1131        assert(out_size >= strlen(out_fullpath) + len + 1);
1132        strncat(out_fullpath, path, len);
1133    }
1134}
1135
1136/**
1137 * Given a filename (file)  and a list of paths (dir), try to find an existing
1138 * file in the paths.  If filename already is a path then no
1139 * searching in the given paths.
1140 *
1141 * \returns
1142 * A string in out_fullpath of either the full path or file.
1143 * Side effect is that dir string maybe modified.
1144 */
1145static void loader_get_fullpath(const char *file,
1146                                char *dir,
1147                                size_t out_size,
1148                                char *out_fullpath)
1149{
1150    char *next_dir;
1151    if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1152        //find file exists with prepending given path
1153        while (*dir) {
1154            next_dir = loader_get_next_path(dir);
1155            snprintf(out_fullpath, out_size, "%s%c%s",
1156                     dir, DIRECTORY_SYMBOL, file);
1157            if (loader_platform_file_exists(out_fullpath)) {
1158                return;
1159            }
1160            dir = next_dir;
1161        }
1162    }
1163    snprintf(out_fullpath, out_size, "%s", file);
1164}
1165
1166/**
1167 * Read a JSON file into a buffer.
1168 *
1169 * \returns
1170 * A pointer to a cJSON object representing the JSON parse tree.
1171 * This returned buffer should be freed by caller.
1172 */
1173static cJSON *loader_get_json(const char *filename)
1174{
1175    FILE *file;
1176    char *json_buf;
1177    cJSON *json;
1178    uint64_t len;
1179    file = fopen(filename,"rb");
1180    fseek(file, 0, SEEK_END);
1181    len = ftell(file);
1182    fseek(file, 0, SEEK_SET);
1183    json_buf = (char*) loader_stack_alloc(len+1);
1184    if (json_buf == NULL) {
1185        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1186        fclose(file);
1187        return NULL;
1188    }
1189    if (fread(json_buf, sizeof(char), len, file) != len) {
1190        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1191        fclose(file);
1192        return NULL;
1193    }
1194    fclose(file);
1195    json_buf[len] = '\0';
1196
1197    //parse text from file
1198    json = cJSON_Parse(json_buf);
1199    if (json == NULL)
1200        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1201    return json;
1202}
1203
1204/**
1205 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1206 * file, add entry to the layer_list.
1207 * Fill out the layer_properties in this list entry from the input cHJSON object.
1208 *
1209 * \returns
1210 * void
1211 * layer_list has a new entry and initialized accordingly.
1212 * If the json input object does not have all the required fields no entry
1213 * is added to the list.
1214 */
1215static void loader_add_layer_properties(struct loader_layer_list *layer_instance_list,
1216                                        struct loader_layer_list *layer_device_list,
1217                                        cJSON *json,
1218                                        bool is_implicit,
1219                                        char *filename)
1220{
1221    /* Fields in layer manifest file that are required:
1222     * (required) “file_format_version”
1223     * following are required in the "layer" object:
1224     * (required) "name"
1225     * (required) "type"
1226     * (required) “library_path”
1227     * (required) “abi_versions”
1228     * (required) “implementation_version”
1229     * (required) “description”
1230     * (required for implicit layers) “disable_environment”
1231     *
1232     * First get all required items and if any missing abort
1233     */
1234
1235    struct loader_layer_list *layer_list;
1236    cJSON *item, *layer_node, *ext_item;
1237    char *temp;
1238    char *name, *type, *library_path, *abi_versions;
1239    char *implementation_version, *description;
1240    cJSON *disable_environment;
1241    int i;
1242    struct loader_extension_property ext_prop;
1243    item = cJSON_GetObjectItem(json, "file_format_version");
1244    if (item == NULL) {
1245        return;
1246    }
1247    char *file_vers = cJSON_PrintUnformatted(item);
1248    loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1249               filename, file_vers);
1250    if (strcmp(file_vers, "\"0.9.0\"") != 0)
1251        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1252    free(file_vers);
1253
1254    //TODO handle freeing the allocations: disable_env , enable_env, GIPA, GDPA, library_path
1255    //TODO handle multiple layer nodes in the file
1256    //TODO handle scanned libraries not one per layer property
1257    layer_node = cJSON_GetObjectItem(json, "layer");
1258    if (layer_node == NULL) {
1259        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
1260        return;
1261    }
1262#define GET_JSON_OBJECT(node, var) {                  \
1263        var = cJSON_GetObjectItem(node, #var);        \
1264        if (var == NULL)                              \
1265            return;                                   \
1266        }
1267#define GET_JSON_ITEM(node, var) {                    \
1268        item = cJSON_GetObjectItem(node, #var);       \
1269        if (item == NULL)                             \
1270            return;                                   \
1271        temp = cJSON_Print(item);                     \
1272        temp[strlen(temp) - 1] = '\0';                \
1273        var = malloc(strlen(temp) + 1);               \
1274        strcpy(var, &temp[1]);                        \
1275        free(temp);                                   \
1276        }
1277    GET_JSON_ITEM(layer_node, name)
1278    GET_JSON_ITEM(layer_node, type)
1279    GET_JSON_ITEM(layer_node, library_path)
1280    GET_JSON_ITEM(layer_node, abi_versions)
1281    GET_JSON_ITEM(layer_node, implementation_version)
1282    GET_JSON_ITEM(layer_node, description)
1283    if (is_implicit) {
1284        GET_JSON_OBJECT(layer_node, disable_environment)
1285    }
1286#undef GET_JSON_ITEM
1287#undef GET_JSON_OBJECT
1288
1289    //TODO move layer_XXXX_list capacity check into this spot so know what type it is
1290    assert((layer_instance_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_instance_list->capacity);
1291    assert((layer_device_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_device_list->capacity);
1292
1293   // add list entry
1294    struct loader_layer_properties *props;
1295    if (!strcmp(type, "DEVICE")) {
1296        layer_list = layer_device_list;
1297        props = &(layer_list->list[layer_list->count]);
1298        props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
1299    }
1300    if (!strcmp(type, "INSTANCE")) {
1301        layer_list = layer_instance_list;
1302        props = &(layer_list->list[layer_list->count]);
1303        props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
1304        layer_list = layer_instance_list;
1305    }
1306    if (!strcmp(type, "GLOBAL")) {
1307        layer_list = layer_instance_list;
1308        props = &(layer_list->list[layer_list->count]);
1309        props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1310    }
1311    free(type);
1312
1313    strncpy(props->info.layerName, name, sizeof(props->info.layerName));
1314    props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
1315    free(name);
1316
1317    char *fullpath = malloc(2048);
1318    char *rel_base;
1319    if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) {
1320        // a filename which is assumed in the system directory
1321        char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1);
1322        strcpy(def_path, DEFAULT_VK_LAYERS_PATH);
1323        loader_get_fullpath(library_path, def_path, 2048, fullpath);
1324    }
1325    else {
1326        // a relative or absolute path
1327        char *name_copy = loader_stack_alloc(strlen(filename) + 2);
1328        size_t len;
1329        strcpy(name_copy, filename);
1330        rel_base = loader_platform_dirname(name_copy);
1331        len = strlen(rel_base);
1332        rel_base[len] =  DIRECTORY_SYMBOL;
1333        rel_base[len + 1] = '\0';
1334        loader_expand_path(library_path, rel_base, 2048, fullpath);
1335    }
1336    props->lib_info.lib_name = fullpath;
1337    props->info.specVersion  = loader_make_version(abi_versions);
1338    props->info.implVersion  = loader_make_version(implementation_version);
1339    free(abi_versions);
1340    free(implementation_version);
1341    strncpy((char *) props->info.description, description, sizeof(props->info.description));
1342    props->info.description[sizeof(props->info.description) - 1] = '\0';
1343    free(description);
1344    if (is_implicit) {
1345        props->disable_env_var.name = disable_environment->child->string;
1346        props->disable_env_var.value = disable_environment->child->valuestring;
1347    }
1348    layer_list->count++;
1349
1350    /**
1351     * Now get all optional items and objects and put in list:
1352     * functions
1353     * instance_extensions
1354     * device_extensions
1355     * enable_environment (implicit layers only)
1356     */
1357#define GET_JSON_OBJECT(node, var) {                  \
1358        var = cJSON_GetObjectItem(node, #var);        \
1359        }
1360#define GET_JSON_ITEM(node, var) {                    \
1361        item = cJSON_GetObjectItem(node, #var);       \
1362        if (item != NULL)                             \
1363            temp = cJSON_Print(item);                 \
1364        temp[strlen(temp) - 1] = '\0';                \
1365        var = malloc(strlen(temp) + 1);               \
1366        strcpy(var, &temp[1]);                        \
1367        free(temp);                                   \
1368        }
1369
1370    cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1371    char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
1372    GET_JSON_OBJECT(layer_node, functions)
1373    if (functions != NULL) {
1374        GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1375        GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1376        props->functions.str_gipa = vkGetInstanceProcAddr;
1377        props->functions.str_gdpa = vkGetDeviceProcAddr;
1378    }
1379    GET_JSON_OBJECT(layer_node, instance_extensions)
1380    if (instance_extensions != NULL) {
1381        int count = cJSON_GetArraySize(instance_extensions);
1382        for (i = 0; i < count; i++) {
1383            ext_item = cJSON_GetArrayItem(instance_extensions, i);
1384            GET_JSON_ITEM(ext_item, name)
1385            GET_JSON_ITEM(ext_item, version)
1386            ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1387            ext_prop.lib_name = library_path;
1388            strcpy(ext_prop.info.extName, name);
1389            ext_prop.info.specVersion = loader_make_version(version);
1390            free(version);
1391            free(name);
1392            loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
1393        }
1394    }
1395    GET_JSON_OBJECT(layer_node, device_extensions)
1396    if (device_extensions != NULL) {
1397        int count = cJSON_GetArraySize(device_extensions);
1398        for (i = 0; i < count; i++) {
1399            ext_item = cJSON_GetArrayItem(device_extensions, i);
1400            GET_JSON_ITEM(ext_item, name);
1401            GET_JSON_ITEM(ext_item, version);
1402            ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1403            ext_prop.lib_name = library_path;
1404            strcpy(ext_prop.info.extName, name);
1405            ext_prop.info.specVersion = loader_make_version(version);
1406            free(version);
1407            free(name);
1408            loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
1409        }
1410    }
1411    if (is_implicit) {
1412        GET_JSON_OBJECT(layer_node, enable_environment)
1413        props->enable_env_var.name = enable_environment->child->string;
1414        props->enable_env_var.value = enable_environment->child->valuestring;
1415    }
1416#undef GET_JSON_ITEM
1417#undef GET_JSON_OBJECT
1418    // for global layers need to add them to both device and instance list
1419    if (props->type & (VK_LAYER_TYPE_GLOBAL_IMPLICIT | VK_LAYER_TYPE_GLOBAL_EXPLICIT)) {
1420        //copy into device layer list
1421        memcpy(&(layer_device_list->list[layer_device_list->count++]), props, sizeof(*props));
1422    }
1423
1424}
1425
1426/**
1427 * Find the Vulkan library manifest files.
1428 *
1429 * This function scans the location or env_override directories/files
1430 * for a list of JSON manifest files.  If env_override is non-NULL
1431 * and has a valid value. Then the location is ignored.  Otherwise
1432 * location is used to look for manifest files. The location
1433 * is interpreted as  Registry path on Windows and a directory path(s)
1434 * on Linux.
1435 *
1436 * \returns
1437 * A string list of manifest files to be opened in out_files param.
1438 * List has a pointer to string for each manifest filename.
1439 * When done using the list in out_files, pointers should be freed.
1440 * Location or override  string lists can be either files or directories as follows:
1441 *            | location | override
1442 * --------------------------------
1443 * Win ICD    | files    | files
1444 * Win Layer  | files    | dirs
1445 * Linux ICD  | dirs     | files
1446 * Linux Layer| dirs     | dirs
1447 */
1448static void loader_get_manifest_files(const char *env_override,
1449                                      bool is_layer,
1450                                      const char *location,
1451                                      struct loader_manifest_files *out_files)
1452{
1453    char *override = NULL;
1454    char *loc;
1455    char *file, *next_file, *name;
1456    size_t alloced_count = 64;
1457    char full_path[2048];
1458    DIR *sysdir = NULL;
1459    bool list_is_dirs = false;
1460    struct dirent *dent;
1461
1462    out_files->count = 0;
1463    out_files->filename_list = NULL;
1464
1465    if (env_override != NULL && (override = getenv(env_override))) {
1466#if defined(__linux__)
1467        if (geteuid() != getuid()) {
1468            /* Don't allow setuid apps to use the env var: */
1469            override = NULL;
1470        }
1471#endif
1472    }
1473
1474    if (location == NULL) {
1475        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1476            "Can't get manifest files with NULL location, env_override=%s",
1477            env_override);
1478        return;
1479    }
1480
1481#if defined(__linux__)
1482    list_is_dirs = (override == NULL || is_layer) ? true : false;
1483#else //WIN32
1484    list_is_dirs = (is_layer && override != NULL) ? true : false;
1485#endif
1486    // Make a copy of the input we are using so it is not modified
1487    // Also handle getting the location(s) from registry on Windows
1488    if (override == NULL) {
1489        loc = loader_stack_alloc(strlen(location) + 1);
1490        if (loc == NULL) {
1491            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1492            return;
1493        }
1494        strcpy(loc, location);
1495#if defined (_WIN32)
1496        loc = loader_get_registry_files(loc);
1497        if (loc == NULL) {
1498            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1499            return;
1500        }
1501#endif
1502    }
1503    else {
1504        loc = loader_stack_alloc(strlen(override) + 1);
1505        if (loc == NULL) {
1506            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1507            return;
1508        }
1509        strcpy(loc, override);
1510    }
1511
1512    // Print out the paths being searched if debugging is enabled
1513    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching the following paths for manifest files: %s\n", loc);
1514
1515    file = loc;
1516    while (*file) {
1517        next_file = loader_get_next_path(file);
1518        if (list_is_dirs) {
1519            sysdir = opendir(file);
1520            name = NULL;
1521            if (sysdir) {
1522                dent = readdir(sysdir);
1523                if (dent == NULL)
1524                    break;
1525                name = &(dent->d_name[0]);
1526                loader_get_fullpath(name, file, sizeof(full_path), full_path);
1527                name = full_path;
1528            }
1529        }
1530        else {
1531#if defined(__linux__)
1532            // only Linux has relative paths
1533            char *dir;
1534            // make a copy of location so it isn't modified
1535            dir = alloca(strlen(location) + 1);
1536            if (dir == NULL) {
1537                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1538                return;
1539            }
1540            strcpy(dir, location);
1541
1542            loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1543
1544            name = full_path;
1545#else  // WIN32
1546            name = file;
1547#endif
1548        }
1549        while (name) {
1550                /* Look for files ending with ".json" suffix */
1551                uint32_t nlen = (uint32_t) strlen(name);
1552                const char *suf = name + nlen - 5;
1553                if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1554                    if (out_files->count == 0) {
1555                        out_files->filename_list = malloc(alloced_count * sizeof(char *));
1556                    }
1557                    else if (out_files->count == alloced_count) {
1558                        out_files->filename_list = realloc(out_files->filename_list,
1559                                        alloced_count * sizeof(char *) * 2);
1560                        alloced_count *= 2;
1561                    }
1562                    if (out_files->filename_list == NULL) {
1563                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1564                        return;
1565                    }
1566                    out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1567                    if (out_files->filename_list[out_files->count] == NULL) {
1568                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1569                        return;
1570                    }
1571                    strcpy(out_files->filename_list[out_files->count], name);
1572                    out_files->count++;
1573                } else if (!list_is_dirs) {
1574                    loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
1575                }
1576                if (list_is_dirs) {
1577                    dent = readdir(sysdir);
1578                    if (dent == NULL)
1579                        break;
1580                    name = &(dent->d_name[0]);
1581                    loader_get_fullpath(name, file, sizeof(full_path), full_path);
1582                    name = full_path;
1583                }
1584                else {
1585                    break;
1586                }
1587        }
1588        if (sysdir)
1589            closedir(sysdir);
1590        file = next_file;
1591    }
1592    return;
1593}
1594
1595/**
1596 * Try to find the Vulkan ICD driver(s).
1597 *
1598 * This function scans the default system loader path(s) or path
1599 * specified by the \c VK_ICD_FILENAMES environment variable in
1600 * order to find loadable VK ICDs manifest files. From these
1601 * manifest files it finds the ICD libraries.
1602 *
1603 * \returns
1604 * void
1605 */
1606void loader_icd_scan(void)
1607{
1608    char *file_str;
1609    struct loader_manifest_files manifest_files;
1610
1611
1612    // convenient place to initialize a mutex
1613    loader_platform_thread_create_mutex(&loader_lock);
1614
1615    // convenient place to initialize logging
1616    loader_debug_init();
1617
1618    // Get a list of manifest files for ICDs
1619    loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1620                              &manifest_files);
1621    if (manifest_files.count == 0)
1622        return;
1623    for (uint32_t i = 0; i < manifest_files.count; i++) {
1624        file_str = manifest_files.filename_list[i];
1625        if (file_str == NULL)
1626            continue;
1627
1628        cJSON *json;
1629        json = loader_get_json(file_str);
1630        cJSON *item;
1631        item = cJSON_GetObjectItem(json, "file_format_version");
1632        if (item == NULL)
1633            return;
1634        char *file_vers = cJSON_Print(item);
1635        loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1636                   file_str, file_vers);
1637        if (strcmp(file_vers, "\"1.0.0\"") != 0)
1638            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1639        free(file_vers);
1640        item = cJSON_GetObjectItem(json, "ICD");
1641        if (item != NULL) {
1642            item = cJSON_GetObjectItem(item, "library_path");
1643            if (item != NULL) {
1644                char *icd_filename = cJSON_PrintUnformatted(item);
1645                char *icd_file = icd_filename;
1646                if (icd_filename != NULL) {
1647                    char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1648                    char *dir = def_dir;
1649
1650                    // Print out the paths being searched if debugging is enabled
1651                    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching for ICD drivers named %s at %s\n", icd_file, dir);
1652
1653                    // strip off extra quotes
1654                    if (icd_filename[strlen(icd_filename)  - 1] == '"')
1655                        icd_filename[strlen(icd_filename) - 1] = '\0';
1656                    if (icd_filename[0] == '"')
1657                        icd_filename++;
1658#if defined(__linux__)
1659                    char full_path[2048];
1660                    loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1661                    loader_scanned_icd_add(full_path);
1662#else // WIN32
1663                    loader_scanned_icd_add(icd_filename);
1664#endif
1665                    free(icd_file);
1666                }
1667            }
1668            else
1669                loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1670        }
1671        else
1672            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1673
1674        free(file_str);
1675        cJSON_Delete(json);
1676    }
1677    free(manifest_files.filename_list);
1678
1679}
1680
1681
1682void loader_layer_scan(void)
1683{
1684    char *file_str;
1685    struct loader_manifest_files manifest_files;
1686    cJSON *json;
1687    uint32_t i;
1688
1689    // Get a list of manifest files for layers
1690    loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
1691                              &manifest_files);
1692    if (manifest_files.count == 0)
1693        return;
1694
1695#if 0
1696    /**
1697     * We need a list of the layer libraries, not just a list of
1698     * the layer properties (a layer library could expose more than
1699     * one layer property). This list of scanned layers would be
1700     * used to check for global and physicaldevice layer properties.
1701     */
1702    if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1703        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1704                   "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1705        return;
1706    }
1707#endif
1708
1709    // TODO use global_layer add and delete functions instead
1710    if (loader.scanned_instance_layers.capacity == 0) {
1711        loader.scanned_instance_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1712        if (loader.scanned_instance_layers.list == NULL) {
1713            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
1714            return;
1715        }
1716        memset(loader.scanned_instance_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1717        loader.scanned_instance_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1718    }
1719    else {
1720        /* cleanup any previously scanned libraries */
1721        //TODO make sure everything is cleaned up properly
1722        for (i = 0; i < loader.scanned_instance_layers.count; i++) {
1723            if (loader.scanned_instance_layers.list[i].lib_info.lib_name != NULL)
1724                free(loader.scanned_instance_layers.list[i].lib_info.lib_name);
1725            loader_destroy_ext_list(&loader.scanned_instance_layers.list[i].instance_extension_list);
1726            loader_destroy_ext_list(&loader.scanned_instance_layers.list[i].device_extension_list);
1727            loader.scanned_instance_layers.list[i].lib_info.lib_name = NULL;
1728        }
1729        loader.scanned_instance_layers.count = 0;
1730    }
1731    if (loader.scanned_device_layers.capacity == 0) {
1732        loader.scanned_device_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1733        if (loader.scanned_device_layers.list == NULL) {
1734            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
1735            return;
1736        }
1737        memset(loader.scanned_device_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1738        loader.scanned_device_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1739    }
1740    else {
1741        /* cleanup any previously scanned libraries */
1742        //TODO make sure everything is cleaned up properly
1743        for (i = 0; i < loader.scanned_device_layers.count; i++) {
1744            if (loader.scanned_device_layers.list[i].lib_info.lib_name != NULL)
1745                free(loader.scanned_device_layers.list[i].lib_info.lib_name);
1746            loader_destroy_ext_list(&loader.scanned_device_layers.list[i].instance_extension_list);
1747            loader_destroy_ext_list(&loader.scanned_device_layers.list[i].device_extension_list);
1748            loader.scanned_device_layers.list[i].lib_info.lib_name = NULL;
1749        }
1750        loader.scanned_device_layers.count = 0;
1751    }
1752
1753
1754    for (i = 0; i < manifest_files.count; i++) {
1755        file_str = manifest_files.filename_list[i];
1756        if (file_str == NULL)
1757            continue;
1758
1759        // parse file into JSON struct
1760        json = loader_get_json(file_str);
1761        if (!json) {
1762            continue;
1763        }
1764        // ensure enough room to add an entry
1765        if ((loader.scanned_instance_layers.count + 1) * sizeof (struct loader_layer_properties)
1766                > loader.scanned_instance_layers.capacity) {
1767            loader.scanned_instance_layers.list = realloc(loader.scanned_instance_layers.list,
1768                    loader.scanned_instance_layers.capacity * 2);
1769            if (loader.scanned_instance_layers.list == NULL) {
1770                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1771                        "realloc failed for scanned layers");
1772                break;
1773            }
1774            loader.scanned_instance_layers.capacity *= 2;
1775        }
1776        // ensure enough room to add an entry
1777        if ((loader.scanned_device_layers.count + 1) * sizeof (struct loader_layer_properties)
1778                > loader.scanned_device_layers.capacity) {
1779            loader.scanned_device_layers.list = realloc(loader.scanned_device_layers.list,
1780                    loader.scanned_device_layers.capacity * 2);
1781            if (loader.scanned_device_layers.list == NULL) {
1782                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1783                        "realloc failed for scanned layers");
1784                break;
1785            }
1786            loader.scanned_device_layers.capacity *= 2;
1787        }
1788        //TODO pass in implicit versus explicit bool
1789        //TODO error if device layers expose instance_extensions
1790        //TODO error if instance layers expose device extensions
1791        loader_add_layer_properties(&loader.scanned_instance_layers,
1792                                    &loader.scanned_device_layers,
1793                                    json,
1794                                    false,
1795                                    file_str);
1796
1797
1798        free(file_str);
1799        cJSON_Delete(json);
1800    }
1801    free(manifest_files.filename_list);
1802
1803}
1804
1805static PFN_vkVoidFunction VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1806{
1807    // inst is not wrapped
1808    if (inst == VK_NULL_HANDLE) {
1809        return NULL;
1810    }
1811    VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1812    void *addr;
1813
1814    if (!strcmp(pName, "vkGetInstanceProcAddr"))
1815        return (void *) loader_gpa_instance_internal;
1816
1817    if (disp_table == NULL)
1818        return NULL;
1819
1820    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1821    if (addr) {
1822        return addr;
1823    }
1824
1825    if (disp_table->GetInstanceProcAddr == NULL) {
1826        return NULL;
1827    }
1828    return disp_table->GetInstanceProcAddr(inst, pName);
1829}
1830
1831struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
1832{
1833
1834    *gpu_index = 0;
1835    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1836        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1837            for (uint32_t i = 0; i < icd->gpu_count; i++)
1838                if (icd->gpus[i] == gpu) {
1839                    *gpu_index = i;
1840                    return icd;
1841                }
1842        }
1843    }
1844    return NULL;
1845}
1846
1847static loader_platform_dl_handle loader_add_layer_lib(
1848        const char *chain_type,
1849        struct loader_layer_properties *layer_prop)
1850{
1851    struct loader_lib_info *new_layer_lib_list, *my_lib;
1852
1853    /*
1854     * TODO: We can now track this information in the
1855     * scanned_layer_libraries list.
1856     */
1857    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1858        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
1859            /* Have already loaded this library, just increment ref count */
1860            loader.loaded_layer_lib_list[i].ref_count++;
1861            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1862                       "%s Chain: Increment layer reference count for layer library %s",
1863                       chain_type, layer_prop->lib_info.lib_name);
1864            return loader.loaded_layer_lib_list[i].lib_handle;
1865        }
1866    }
1867
1868    /* Haven't seen this library so load it */
1869    new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1870                      (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1871    if (!new_layer_lib_list) {
1872        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1873        return NULL;
1874    }
1875
1876    my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1877
1878    /* NOTE: We require that the layer property be immutable */
1879    my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
1880    my_lib->ref_count = 0;
1881    my_lib->lib_handle = NULL;
1882
1883    if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1884        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1885                   loader_platform_open_library_error(my_lib->lib_name));
1886        return NULL;
1887    } else {
1888        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1889                   "Chain: %s: Loading layer library %s",
1890                   chain_type, layer_prop->lib_info.lib_name);
1891    }
1892    loader.loaded_layer_lib_count++;
1893    loader.loaded_layer_lib_list = new_layer_lib_list;
1894    my_lib->ref_count++;
1895
1896    return my_lib->lib_handle;
1897}
1898
1899static void loader_remove_layer_lib(
1900        struct loader_instance *inst,
1901        struct loader_layer_properties *layer_prop)
1902{
1903    uint32_t idx;
1904    struct loader_lib_info *new_layer_lib_list, *my_lib = NULL;
1905
1906    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1907        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
1908            /* found matching library */
1909            idx = i;
1910            my_lib = &loader.loaded_layer_lib_list[i];
1911            break;
1912        }
1913    }
1914
1915    if (my_lib) {
1916        my_lib->ref_count--;
1917        if (my_lib->ref_count > 0) {
1918            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1919                       "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
1920            return;
1921        }
1922    }
1923    loader_platform_close_library(my_lib->lib_handle);
1924    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1925               "Unloading layer library %s", layer_prop->lib_info.lib_name);
1926
1927    /* Need to remove unused library from list */
1928    new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1929    if (!new_layer_lib_list) {
1930        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1931        return;
1932    }
1933
1934    if (idx > 0) {
1935        /* Copy records before idx */
1936        memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1937               sizeof(struct loader_lib_info) * idx);
1938    }
1939    if (idx < (loader.loaded_layer_lib_count - 1)) {
1940        /* Copy records after idx */
1941        memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1942                sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1943    }
1944
1945    free(loader.loaded_layer_lib_list);
1946    loader.loaded_layer_lib_count--;
1947    loader.loaded_layer_lib_list = new_layer_lib_list;
1948}
1949
1950
1951/**
1952 * Go through the search_list and find any layers which match type. If layer
1953 * type match is found in then add it to ext_list.
1954 */
1955//TODO need to handle implict layer enable env var and disable env var
1956static void loader_add_layer_implicit(
1957                const enum layer_type type,
1958                struct loader_layer_list *list,
1959                struct loader_layer_list *search_list)
1960{
1961    uint32_t i;
1962    for (i = 0; i < search_list->count; i++) {
1963        const struct loader_layer_properties *prop = &search_list->list[i];
1964        if (prop->type & type) {
1965            /* Found an layer with the same type, add to layer_list */
1966            loader_add_to_layer_list(list, 1, prop);
1967        }
1968    }
1969
1970}
1971
1972/**
1973 * Get the layer name(s) from the env_name environment variable. If layer
1974 * is found in search_list then add it to layer_list.  But only add it to
1975 * layer_list if type matches.
1976 */
1977static void loader_add_layer_env(
1978                const enum layer_type type,
1979                const char *env_name,
1980                struct loader_layer_list *layer_list,
1981                const struct loader_layer_list *search_list)
1982{
1983    char *layerEnv;
1984    char *next, *name;
1985
1986    layerEnv = getenv(env_name);
1987    if (layerEnv == NULL) {
1988        return;
1989    }
1990    name = loader_stack_alloc(strlen(layerEnv) + 1);
1991    if (name == NULL) {
1992        return;
1993    }
1994    strcpy(name, layerEnv);
1995
1996    while (name && *name ) {
1997        next = loader_get_next_path(name);
1998        loader_find_layer_name_add_list(name, type, search_list, layer_list);
1999        name = next;
2000    }
2001
2002    return;
2003}
2004
2005void loader_deactivate_instance_layers(struct loader_instance *instance)
2006{
2007    if (!instance->activated_layer_list.count) {
2008        return;
2009    }
2010
2011    /* Create instance chain of enabled layers */
2012    for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
2013        struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
2014
2015        loader_remove_layer_lib(instance, layer_prop);
2016    }
2017    loader_destroy_layer_list(&instance->activated_layer_list);
2018}
2019
2020VkResult loader_enable_instance_layers(
2021        struct loader_instance *inst,
2022        const VkInstanceCreateInfo *pCreateInfo)
2023{
2024    VkResult err;
2025
2026    if (inst == NULL)
2027        return VK_ERROR_UNKNOWN;
2028
2029    if (!loader_init_layer_list(&inst->activated_layer_list)) {
2030        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
2031        return VK_ERROR_OUT_OF_HOST_MEMORY;
2032    }
2033
2034    /* Add any implicit layers first */
2035    loader_add_layer_implicit(
2036                                VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2037                                &inst->activated_layer_list,
2038                                &loader.scanned_instance_layers);
2039
2040    /* Add any layers specified via environment variable next */
2041    loader_add_layer_env(
2042                            VK_LAYER_TYPE_INSTANCE_EXPLICIT,
2043                            "VK_INSTANCE_LAYERS",
2044                            &inst->activated_layer_list,
2045                            &loader.scanned_instance_layers);
2046
2047    /* Add layers specified by the application */
2048    err = loader_add_layer_names_to_list(
2049                &inst->activated_layer_list,
2050                pCreateInfo->layerCount,
2051                pCreateInfo->ppEnabledLayerNames,
2052                &loader.scanned_instance_layers);
2053
2054    return err;
2055}
2056
2057uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2058{
2059    uint32_t layer_idx;
2060    VkBaseLayerObject *wrappedInstance;
2061
2062    if (inst == NULL) {
2063        return 0;
2064    }
2065
2066    // NOTE inst is unwrapped at this point in time
2067    void* baseObj = (void*) inst;
2068    void* nextObj = (void*) inst;
2069    VkBaseLayerObject *nextInstObj;
2070    PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2071
2072    if (!inst->activated_layer_list.count) {
2073        return 0;
2074    }
2075
2076    wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
2077                                   * inst->activated_layer_list.count);
2078    if (!wrappedInstance) {
2079        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2080        return 0;
2081    }
2082
2083    /* Create instance chain of enabled layers */
2084    layer_idx = inst->activated_layer_list.count - 1;
2085    for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
2086        struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
2087        loader_platform_dl_handle lib_handle;
2088
2089         /*
2090         * Note: An extension's Get*ProcAddr should not return a function pointer for
2091         * any extension entry points until the extension has been enabled.
2092         * To do this requires a different behavior from Get*ProcAddr functions implemented
2093         * in layers.
2094         * The very first call to a layer will be it's Get*ProcAddr function requesting
2095         * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2096         * with the wrapped object given (either Instance or Device) and return the layer's
2097         * Get*ProcAddr function. The layer should also use this opportunity to record the
2098         * baseObject so that it can find the correct local dispatch table on future calls.
2099         * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2100         * will not use a wrapped object and must look up their local dispatch table from
2101         * the given baseObject.
2102         */
2103        nextInstObj = (wrappedInstance + layer_idx);
2104        nextInstObj->pGPA = (PFN_vkGPA) nextGPA;
2105        nextInstObj->baseObject = baseObj;
2106        nextInstObj->nextObject = nextObj;
2107        nextObj = (void*) nextInstObj;
2108
2109        char funcStr[256];
2110        snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2111        lib_handle = loader_add_layer_lib("instance", layer_prop);
2112        if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2113            nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
2114        if (!nextGPA) {
2115            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name);
2116
2117            /* TODO: Should we return nextObj, nextGPA to previous? */
2118            continue;
2119        }
2120
2121        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
2122                   "Insert instance layer %s (%s)",
2123                   layer_prop->info.layerName,
2124                   layer_prop->lib_info.lib_name);
2125
2126        layer_idx--;
2127    }
2128
2129    loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
2130
2131    return inst->activated_layer_list.count;
2132}
2133
2134void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2135{
2136
2137    loader_init_instance_extension_dispatch_table(inst->disp,
2138                                                  inst->disp->GetInstanceProcAddr,
2139                                                  (VkInstance) inst);
2140}
2141
2142static VkResult loader_enable_device_layers(
2143        struct loader_icd *icd,
2144        struct loader_device *dev,
2145        const VkDeviceCreateInfo *pCreateInfo)
2146{
2147    VkResult err;
2148
2149    if (dev == NULL)
2150        return VK_ERROR_UNKNOWN;
2151
2152    if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
2153        loader_init_layer_list(&dev->activated_layer_list);
2154    }
2155
2156    if (dev->activated_layer_list.list == NULL) {
2157        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
2158        return VK_ERROR_OUT_OF_HOST_MEMORY;
2159    }
2160
2161    /* Add any implicit layers first */
2162    loader_add_layer_implicit(
2163                VK_LAYER_TYPE_DEVICE_IMPLICIT,
2164                &dev->activated_layer_list,
2165                &loader.scanned_device_layers);
2166
2167    /* Add any layers specified via environment variable next */
2168    loader_add_layer_env(
2169                VK_LAYER_TYPE_DEVICE_EXPLICIT,
2170                "VK_DEVICE_LAYERS",
2171                &dev->activated_layer_list,
2172                &loader.scanned_device_layers);
2173
2174    /* Add layers specified by the application */
2175    err = loader_add_layer_names_to_list(
2176                &dev->activated_layer_list,
2177                pCreateInfo->layerCount,
2178                pCreateInfo->ppEnabledLayerNames,
2179                &loader.scanned_device_layers);
2180
2181    return err;
2182}
2183
2184/*
2185 * This function terminates the device chain fro CreateDevice.
2186 * CreateDevice is a special case and so the loader call's
2187 * the ICD's CreateDevice before creating the chain. Since
2188 * we can't call CreateDevice twice we must terminate the
2189 * device chain with something else.
2190 */
2191static VkResult VKAPI scratch_vkCreateDevice(
2192    VkPhysicalDevice          gpu,
2193    const VkDeviceCreateInfo *pCreateInfo,
2194    VkDevice                 *pDevice)
2195{
2196    return VK_SUCCESS;
2197}
2198
2199static PFN_vkVoidFunction VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2200{
2201    if (!strcmp(name, "vkGetDeviceProcAddr"))
2202        return (PFN_vkVoidFunction) loader_GetDeviceChainProcAddr;
2203    if (!strcmp(name, "vkCreateDevice"))
2204        return (PFN_vkVoidFunction) scratch_vkCreateDevice;
2205
2206    struct loader_device *found_dev;
2207    struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2208    return icd->GetDeviceProcAddr(device, name);
2209}
2210
2211static uint32_t loader_activate_device_layers(
2212        struct loader_icd *icd,
2213        struct loader_device *dev,
2214        VkDevice device)
2215{
2216    if (!icd)
2217        return 0;
2218
2219    if (!dev) {
2220        return 0;
2221    }
2222
2223    /* activate any layer libraries */
2224    void* nextObj = (void*) device;
2225    void* baseObj = nextObj;
2226    VkBaseLayerObject *nextGpuObj;
2227    PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
2228    VkBaseLayerObject *wrappedGpus;
2229
2230    if (!dev->activated_layer_list.count)
2231        return 0;
2232
2233    wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2234    if (!wrappedGpus) {
2235        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2236        return 0;
2237    }
2238
2239    for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2240
2241        struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
2242        loader_platform_dl_handle lib_handle;
2243
2244        nextGpuObj = (wrappedGpus + i);
2245        nextGpuObj->pGPA = (PFN_vkGPA)nextGPA;
2246        nextGpuObj->baseObject = baseObj;
2247        nextGpuObj->nextObject = nextObj;
2248        nextObj = (void*) nextGpuObj;
2249
2250        char funcStr[256];
2251        snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2252        lib_handle = loader_add_layer_lib("device", layer_prop);
2253        if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2254            nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2255        if (!nextGPA) {
2256            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName);
2257            continue;
2258        }
2259
2260        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
2261                   "Insert device layer library %s (%s)",
2262                   layer_prop->info.layerName,
2263                   layer_prop->lib_info.lib_name);
2264
2265    }
2266
2267    loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2268            (VkDevice) nextObj, (VkDevice) baseObj);
2269    free(wrappedGpus);
2270
2271    return dev->activated_layer_list.count;
2272}
2273
2274VkResult loader_validate_layers(
2275        const uint32_t                  layer_count,
2276        const char * const             *ppEnabledLayerNames,
2277        struct loader_layer_list       *list)
2278{
2279    struct loader_layer_properties *prop;
2280
2281    for (uint32_t i = 0; i < layer_count; i++) {
2282        prop = get_layer_property(ppEnabledLayerNames[i],
2283                                  list);
2284        if (!prop) {
2285            return VK_ERROR_INVALID_LAYER;
2286        }
2287    }
2288
2289    return VK_SUCCESS;
2290}
2291
2292VkResult loader_validate_instance_extensions(
2293        const VkInstanceCreateInfo     *pCreateInfo)
2294{
2295    struct loader_extension_property *extension_prop;
2296    struct loader_layer_properties *layer_prop;
2297
2298    for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2299        extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2300                                                &loader.global_extensions);
2301
2302        if (extension_prop) {
2303            continue;
2304        }
2305
2306        extension_prop = NULL;
2307
2308        /* Not in global list, search layer extension lists */
2309        for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2310            layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
2311                                  &loader.scanned_instance_layers);
2312
2313            if (!layer_prop) {
2314                /* Should NOT get here, loader_validate_layers
2315                 * should have already filtered this case out.
2316                 */
2317                continue;
2318            }
2319
2320            extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2321                                          &layer_prop->instance_extension_list);
2322            if (extension_prop) {
2323                /* Found the extension in one of the layers enabled by the app. */
2324                break;
2325            }
2326        }
2327
2328        if (!extension_prop) {
2329            /* Didn't find extension name in any of the global layers, error out */
2330            return VK_ERROR_INVALID_EXTENSION;
2331        }
2332    }
2333    return VK_SUCCESS;
2334}
2335
2336VkResult loader_validate_device_extensions(
2337        struct loader_icd              *icd,
2338        uint32_t                       gpu_index,
2339        const VkDeviceCreateInfo       *pCreateInfo)
2340{
2341    struct loader_extension_property *extension_prop;
2342    struct loader_layer_properties *layer_prop;
2343
2344    for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2345        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2346        extension_prop = get_extension_property(extension_name,
2347                                                &icd->device_extension_cache[gpu_index]);
2348
2349        if (extension_prop) {
2350            continue;
2351        }
2352
2353        /* Not in global list, search layer extension lists */
2354        for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2355            const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
2356            layer_prop = get_layer_property(layer_name,
2357                                  &loader.scanned_device_layers);
2358
2359            if (!layer_prop) {
2360                /* Should NOT get here, loader_validate_instance_layers
2361                 * should have already filtered this case out.
2362                 */
2363                continue;
2364            }
2365
2366            extension_prop = get_extension_property(extension_name,
2367                                          &layer_prop->device_extension_list);
2368            if (extension_prop) {
2369                /* Found the extension in one of the layers enabled by the app. */
2370                break;
2371            }
2372        }
2373
2374        if (!extension_prop) {
2375            /* Didn't find extension name in any of the device layers, error out */
2376            return VK_ERROR_INVALID_EXTENSION;
2377        }
2378    }
2379    return VK_SUCCESS;
2380}
2381
2382VkResult VKAPI loader_CreateInstance(
2383        const VkInstanceCreateInfo*     pCreateInfo,
2384        VkInstance*                     pInstance)
2385{
2386    struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
2387    struct loader_scanned_icds *scanned_icds;
2388    struct loader_icd *icd;
2389    struct loader_extension_property *prop;
2390    char **filtered_extension_names = NULL;
2391    VkInstanceCreateInfo icd_create_info;
2392    VkResult res = VK_SUCCESS;
2393    bool success;
2394
2395    icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2396    icd_create_info.layerCount = 0;
2397    icd_create_info.ppEnabledLayerNames = NULL;
2398    icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2399    icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2400    icd_create_info.pNext = pCreateInfo->pNext;
2401
2402    /*
2403     * NOTE: Need to filter the extensions to only those
2404     * supported by the ICD.
2405     * No ICD will advertise support for layers. An ICD
2406     * library could support a layer, but it would be
2407     * independent of the actual ICD, just in the same library.
2408     */
2409    filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2410    if (!filtered_extension_names) {
2411        return VK_ERROR_OUT_OF_HOST_MEMORY;
2412    }
2413    icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2414
2415    scanned_icds = loader.scanned_icd_list;
2416    while (scanned_icds) {
2417        icd = loader_icd_add(ptr_instance, scanned_icds);
2418        if (icd) {
2419            icd_create_info.extensionCount = 0;
2420            for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2421                prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2422                                              &scanned_icds->global_extension_list);
2423                if (prop) {
2424                    filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2425                    icd_create_info.extensionCount++;
2426                }
2427            }
2428
2429            res = scanned_icds->CreateInstance(&icd_create_info,
2430                                           &(icd->instance));
2431            success = loader_icd_init_entrys(
2432                                icd,
2433                                icd->instance,
2434                                scanned_icds->GetInstanceProcAddr);
2435
2436            if (res != VK_SUCCESS || !success)
2437            {
2438                ptr_instance->icds = ptr_instance->icds->next;
2439                loader_icd_destroy(ptr_instance, icd);
2440                icd->instance = VK_NULL_HANDLE;
2441                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
2442                        "ICD ignored: failed to CreateInstance and find entrypoints with ICD");
2443            }
2444        }
2445        scanned_icds = scanned_icds->next;
2446    }
2447
2448    /*
2449     * If no ICDs were added to instance list and res is unchanged
2450     * from it's initial value, the loader was unable to find
2451     * a suitable ICD.
2452     */
2453    if (ptr_instance->icds == NULL) {
2454        if (res == VK_SUCCESS) {
2455            return VK_ERROR_INCOMPATIBLE_DRIVER;
2456        } else {
2457            return res;
2458        }
2459    }
2460
2461    return VK_SUCCESS;
2462}
2463
2464VkResult VKAPI loader_DestroyInstance(
2465        VkInstance                                instance)
2466{
2467    struct loader_instance *ptr_instance = loader_instance(instance);
2468    struct loader_icd *icds = ptr_instance->icds;
2469    struct loader_icd *next_icd;
2470    VkResult res;
2471
2472    // Remove this instance from the list of instances:
2473    struct loader_instance *prev = NULL;
2474    struct loader_instance *next = loader.instances;
2475    while (next != NULL) {
2476        if (next == ptr_instance) {
2477            // Remove this instance from the list:
2478            if (prev)
2479                prev->next = next->next;
2480            else
2481                loader.instances = next->next;
2482            break;
2483        }
2484        prev = next;
2485        next = next->next;
2486    }
2487    if (next  == NULL) {
2488        // This must be an invalid instance handle or empty list
2489        return VK_ERROR_INVALID_HANDLE;
2490    }
2491
2492    while (icds) {
2493        if (icds->instance) {
2494            res = icds->DestroyInstance(icds->instance);
2495            if (res != VK_SUCCESS)
2496                loader_log(VK_DBG_REPORT_WARN_BIT, 0,
2497                            "ICD ignored: failed to DestroyInstance on device");
2498        }
2499        next_icd = icds->next;
2500        icds->instance = VK_NULL_HANDLE;
2501        loader_icd_destroy(ptr_instance, icds);
2502
2503        icds = next_icd;
2504    }
2505
2506
2507    return VK_SUCCESS;
2508}
2509
2510VkResult loader_init_physical_device_info(
2511        struct loader_instance *ptr_instance)
2512{
2513    struct loader_icd *icd;
2514    uint32_t n, count = 0;
2515    VkResult res = VK_ERROR_UNKNOWN;
2516
2517    icd = ptr_instance->icds;
2518    while (icd) {
2519        res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2520        if (res != VK_SUCCESS)
2521            return res;
2522        icd->gpu_count = n;
2523        count += n;
2524        icd = icd->next;
2525    }
2526
2527    ptr_instance->total_gpu_count = count;
2528
2529    icd = ptr_instance->icds;
2530    while (icd) {
2531
2532        n = icd->gpu_count;
2533        icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2534        if (!icd->gpus) {
2535            /* TODO: Add cleanup code here */
2536            return VK_ERROR_OUT_OF_HOST_MEMORY;
2537        }
2538        res = icd->EnumeratePhysicalDevices(
2539                                        icd->instance,
2540                                        &n,
2541                                        icd->gpus);
2542        if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
2543
2544            for (unsigned int i = 0; i < n; i++) {
2545
2546                loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
2547
2548                if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2549                    /* TODO: Add cleanup code here */
2550                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
2551                }
2552                if (res == VK_SUCCESS) {
2553
2554                    loader_add_physical_device_extensions(
2555                                icd->GetPhysicalDeviceExtensionProperties,
2556                                icd->gpus[0],
2557                                VK_EXTENSION_ORIGIN_ICD,
2558                                icd->scanned_icds->lib_name,
2559                                &icd->device_extension_cache[i]);
2560
2561                }
2562
2563                if (res != VK_SUCCESS) {
2564                    /* clean up any extension lists previously created before this request failed */
2565                    for (uint32_t j = 0; j < i; j++) {
2566                        loader_destroy_ext_list(&icd->device_extension_cache[i]);
2567                    }
2568
2569                    return res;
2570                }
2571            }
2572
2573            count += n;
2574        }
2575
2576        icd = icd->next;
2577    }
2578
2579    return VK_SUCCESS;
2580}
2581
2582VkResult VKAPI loader_EnumeratePhysicalDevices(
2583        VkInstance                              instance,
2584        uint32_t*                               pPhysicalDeviceCount,
2585        VkPhysicalDevice*                       pPhysicalDevices)
2586{
2587    uint32_t index = 0;
2588    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2589    struct loader_icd *icd = ptr_instance->icds;
2590
2591    if (ptr_instance->total_gpu_count == 0) {
2592        loader_init_physical_device_info(ptr_instance);
2593    }
2594
2595    *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2596    if (!pPhysicalDevices) {
2597        return VK_SUCCESS;
2598    }
2599
2600    while (icd) {
2601        assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
2602        memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
2603        index += icd->gpu_count;
2604        icd = icd->next;
2605    }
2606
2607    return VK_SUCCESS;
2608}
2609
2610VkResult VKAPI loader_GetPhysicalDeviceProperties(
2611        VkPhysicalDevice                        gpu,
2612        VkPhysicalDeviceProperties*             pProperties)
2613{
2614    uint32_t gpu_index;
2615    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2616    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2617
2618    if (icd->GetPhysicalDeviceProperties)
2619        res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2620
2621    return res;
2622}
2623
2624VkResult VKAPI loader_GetPhysicalDeviceQueueCount(
2625        VkPhysicalDevice                        gpu,
2626        uint32_t*                               pCount)
2627{
2628    uint32_t gpu_index;
2629    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2630    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2631
2632    if (icd->GetPhysicalDeviceQueueCount)
2633        res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2634
2635    return res;
2636}
2637
2638VkResult VKAPI loader_GetPhysicalDeviceQueueProperties (
2639        VkPhysicalDevice gpu,
2640        uint32_t count,
2641        VkPhysicalDeviceQueueProperties * pProperties)
2642{
2643    uint32_t gpu_index;
2644    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2645    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2646
2647    if (icd->GetPhysicalDeviceQueueProperties)
2648        res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2649
2650    return res;
2651}
2652
2653VkResult VKAPI loader_GetPhysicalDeviceMemoryProperties (
2654        VkPhysicalDevice gpu,
2655        VkPhysicalDeviceMemoryProperties* pProperties)
2656{
2657    uint32_t gpu_index;
2658    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2659    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2660
2661    if (icd->GetPhysicalDeviceMemoryProperties)
2662        res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
2663
2664    return res;
2665}
2666
2667VkResult VKAPI loader_GetPhysicalDeviceFeatures(
2668        VkPhysicalDevice                        physicalDevice,
2669        VkPhysicalDeviceFeatures*               pFeatures)
2670{
2671    uint32_t gpu_index;
2672    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2673    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2674
2675    if (icd->GetPhysicalDeviceFeatures)
2676        res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2677
2678    return res;
2679}
2680
2681VkResult VKAPI loader_GetPhysicalDeviceFormatProperties(
2682        VkPhysicalDevice                        physicalDevice,
2683        VkFormat                                format,
2684        VkFormatProperties*                     pFormatInfo)
2685{
2686    uint32_t gpu_index;
2687    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2688    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2689
2690    if (icd->GetPhysicalDeviceFormatProperties)
2691        res = icd->GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatInfo);
2692
2693    return res;
2694}
2695
2696VkResult VKAPI loader_GetPhysicalDeviceImageFormatProperties(
2697        VkPhysicalDevice                        physicalDevice,
2698        VkFormat                                format,
2699        VkImageType                             type,
2700        VkImageTiling                           tiling,
2701        VkImageUsageFlags                       usage,
2702        VkImageFormatProperties*                pImageFormatProperties)
2703{
2704    uint32_t gpu_index;
2705    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2706    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2707
2708    if (icd->GetPhysicalDeviceImageFormatProperties)
2709        res = icd->GetPhysicalDeviceImageFormatProperties(physicalDevice, format,
2710                                type, tiling, usage, pImageFormatProperties);
2711
2712    return res;
2713}
2714
2715VkResult VKAPI loader_GetPhysicalDeviceLimits(
2716        VkPhysicalDevice                        physicalDevice,
2717        VkPhysicalDeviceLimits*                 pLimits)
2718{
2719    uint32_t gpu_index;
2720    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2721    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2722
2723    if (icd->GetPhysicalDeviceLimits)
2724        res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2725
2726    return res;
2727}
2728
2729VkResult VKAPI loader_GetPhysicalDeviceSparseImageFormatProperties(
2730        VkPhysicalDevice                        physicalDevice,
2731        VkFormat                                format,
2732        VkImageType                             type,
2733        uint32_t                                samples,
2734        VkImageUsageFlags                       usage,
2735        VkImageTiling                           tiling,
2736        uint32_t*                               pNumProperties,
2737        VkSparseImageFormatProperties*          pProperties)
2738{
2739    uint32_t gpu_index;
2740    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2741    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2742
2743    if (icd->GetPhysicalDeviceSparseImageFormatProperties)
2744        res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
2745
2746    return res;
2747}
2748
2749VkResult VKAPI loader_CreateDevice(
2750        VkPhysicalDevice                        gpu,
2751        const VkDeviceCreateInfo*               pCreateInfo,
2752        VkDevice*                               pDevice)
2753{
2754    uint32_t gpu_index;
2755    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2756    struct loader_device *dev;
2757    VkDeviceCreateInfo device_create_info;
2758    char **filtered_extension_names = NULL;
2759    VkResult res;
2760
2761    if (!icd->CreateDevice) {
2762        return VK_ERROR_INITIALIZATION_FAILED;
2763    }
2764
2765    res = loader_validate_layers(pCreateInfo->layerCount,
2766                           pCreateInfo->ppEnabledLayerNames,
2767                           &loader.scanned_device_layers);
2768    if (res != VK_SUCCESS) {
2769        return res;
2770    }
2771
2772    res = loader_validate_device_extensions(icd, gpu_index, pCreateInfo);
2773    if (res != VK_SUCCESS) {
2774        return res;
2775    }
2776
2777    /*
2778     * NOTE: Need to filter the extensions to only those
2779     * supported by the ICD.
2780     * No ICD will advertise support for layers. An ICD
2781     * library could support a layer, but it would be
2782     * independent of the actual ICD, just in the same library.
2783     */
2784    filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2785    if (!filtered_extension_names) {
2786        return VK_ERROR_OUT_OF_HOST_MEMORY;
2787    }
2788
2789    /* Copy user's data */
2790    memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2791
2792    /* ICD's do not use layers */
2793    device_create_info.layerCount = 0;
2794    device_create_info.ppEnabledLayerNames = NULL;
2795
2796    device_create_info.extensionCount = 0;
2797    device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2798
2799    for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2800        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2801        struct loader_extension_property *prop = get_extension_property(extension_name,
2802                                      &icd->device_extension_cache[gpu_index]);
2803        if (prop) {
2804            filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2805            device_create_info.extensionCount++;
2806        }
2807    }
2808
2809    res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2810    if (res != VK_SUCCESS) {
2811        return res;
2812    }
2813
2814    dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2815    if (dev == NULL) {
2816        return VK_ERROR_OUT_OF_HOST_MEMORY;
2817    }
2818    PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2819    loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2820                                      *pDevice, *pDevice);
2821
2822    dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2823    loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2824
2825    /*
2826     * Put together the complete list of extensions to enable
2827     * This includes extensions requested via environment variables.
2828     */
2829    loader_enable_device_layers(icd, dev, pCreateInfo);
2830
2831    /*
2832     * Load the libraries and build the device chain
2833     * terminating with the selected device.
2834     */
2835    loader_activate_device_layers(icd, dev, *pDevice);
2836
2837    res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2838
2839    dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2840
2841    return res;
2842}
2843
2844static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
2845{
2846    if (instance == VK_NULL_HANDLE)
2847        return NULL;
2848
2849    void *addr;
2850    /* get entrypoint addresses that are global (in the loader)*/
2851    addr = globalGetProcAddr(pName);
2852    if (addr)
2853        return addr;
2854
2855    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2856
2857    /* return any extension global entrypoints */
2858    addr = debug_report_instance_gpa(ptr_instance, pName);
2859    if (addr) {
2860        return addr;
2861    }
2862
2863    addr = wsi_swapchain_GetInstanceProcAddr(ptr_instance, pName);
2864    if (addr) {
2865        return addr;
2866    }
2867
2868    /* return the instance dispatch table entrypoint for extensions */
2869    const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2870    if (disp_table == NULL)
2871        return NULL;
2872
2873    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2874    if (addr)
2875        return addr;
2876
2877    return NULL;
2878}
2879
2880LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2881{
2882    return loader_GetInstanceProcAddr(instance, pName);
2883}
2884
2885static PFN_vkVoidFunction VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
2886{
2887    if (device == VK_NULL_HANDLE) {
2888        return NULL;
2889    }
2890
2891    void *addr;
2892
2893    /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2894       make sure the loader entrypoint is returned */
2895    addr = loader_non_passthrough_gpa(pName);
2896    if (addr) {
2897        return addr;
2898    }
2899
2900    /* return the dispatch table entrypoint for the fastest case */
2901    const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
2902    if (disp_table == NULL)
2903        return NULL;
2904
2905    addr = loader_lookup_device_dispatch_table(disp_table, pName);
2906    if (addr)
2907        return addr;
2908    else  {
2909        if (disp_table->GetDeviceProcAddr == NULL)
2910            return NULL;
2911        return disp_table->GetDeviceProcAddr(device, pName);
2912    }
2913}
2914
2915LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2916{
2917    return loader_GetDeviceProcAddr(device, pName);
2918}
2919
2920LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
2921    const char*                                 pLayerName,
2922    uint32_t*                                   pCount,
2923    VkExtensionProperties*                      pProperties)
2924{
2925    struct loader_extension_list *global_extension_list;
2926
2927    /* Scan/discover all ICD libraries in a single-threaded manner */
2928    loader_platform_thread_once(&once_icd, loader_icd_scan);
2929
2930    /* get layer libraries in a single-threaded manner */
2931    loader_platform_thread_once(&once_layer, loader_layer_scan);
2932
2933    /* merge any duplicate extensions */
2934    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2935
2936    uint32_t copy_size;
2937
2938    if (pCount == NULL) {
2939        return VK_ERROR_INVALID_POINTER;
2940    }
2941
2942    loader_platform_thread_lock_mutex(&loader_lock);
2943
2944    global_extension_list = loader_global_extensions(pLayerName);
2945    if (global_extension_list == NULL) {
2946        loader_platform_thread_unlock_mutex(&loader_lock);
2947        return VK_ERROR_INVALID_LAYER;
2948    }
2949
2950    if (pProperties == NULL) {
2951        *pCount = global_extension_list->count;
2952        loader_platform_thread_unlock_mutex(&loader_lock);
2953        return VK_SUCCESS;
2954    }
2955
2956    copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2957    for (uint32_t i = 0; i < copy_size; i++) {
2958        memcpy(&pProperties[i],
2959               &global_extension_list->list[i].info,
2960               sizeof(VkExtensionProperties));
2961    }
2962    *pCount = copy_size;
2963
2964    loader_platform_thread_unlock_mutex(&loader_lock);
2965
2966    if (copy_size < global_extension_list->count) {
2967        return VK_INCOMPLETE;
2968    }
2969
2970    return VK_SUCCESS;
2971}
2972
2973LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2974    uint32_t*                                   pCount,
2975    VkLayerProperties*                          pProperties)
2976{
2977
2978    /* Scan/discover all ICD libraries in a single-threaded manner */
2979    loader_platform_thread_once(&once_icd, loader_icd_scan);
2980
2981    /* get layer libraries in a single-threaded manner */
2982    loader_platform_thread_once(&once_layer, loader_layer_scan);
2983
2984    /* merge any duplicate extensions */
2985    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2986
2987    uint32_t copy_size;
2988
2989    if (pCount == NULL) {
2990        return VK_ERROR_INVALID_POINTER;
2991    }
2992
2993    /* TODO: do we still need to lock */
2994    loader_platform_thread_lock_mutex(&loader_lock);
2995
2996    struct loader_layer_list *layer_list;
2997    layer_list = &loader.scanned_instance_layers;
2998
2999    if (pProperties == NULL) {
3000        *pCount = layer_list->count;
3001        loader_platform_thread_unlock_mutex(&loader_lock);
3002        return VK_SUCCESS;
3003    }
3004
3005    copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
3006    for (uint32_t i = 0; i < copy_size; i++) {
3007        memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
3008    }
3009    *pCount = copy_size;
3010
3011    loader_platform_thread_unlock_mutex(&loader_lock);
3012
3013    if (copy_size < layer_list->count) {
3014        return VK_INCOMPLETE;
3015    }
3016
3017    return VK_SUCCESS;
3018}
3019
3020VkResult VKAPI loader_GetPhysicalDeviceExtensionProperties(
3021        VkPhysicalDevice                        gpu,
3022        const char*                             pLayerName,
3023        uint32_t*                               pCount,
3024        VkExtensionProperties*                  pProperties)
3025{
3026    uint32_t gpu_index;
3027    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
3028    uint32_t copy_size;
3029
3030    if (pCount == NULL) {
3031        return VK_ERROR_INVALID_POINTER;
3032    }
3033
3034    uint32_t count;
3035    struct loader_extension_list *list;
3036    loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
3037
3038    if (pProperties == NULL) {
3039        *pCount = count;
3040        return VK_SUCCESS;
3041    }
3042
3043    copy_size = *pCount < count ? *pCount : count;
3044    for (uint32_t i = 0; i < copy_size; i++) {
3045        memcpy(&pProperties[i],
3046               &list->list[i].info,
3047               sizeof(VkExtensionProperties));
3048    }
3049    *pCount = copy_size;
3050
3051    if (copy_size < count) {
3052        return VK_INCOMPLETE;
3053    }
3054
3055    return VK_SUCCESS;
3056}
3057
3058VkResult VKAPI loader_GetPhysicalDeviceLayerProperties(
3059        VkPhysicalDevice                        gpu,
3060        uint32_t*                               pCount,
3061        VkLayerProperties*                      pProperties)
3062{
3063    uint32_t copy_size;
3064
3065    if (pCount == NULL) {
3066        return VK_ERROR_INVALID_POINTER;
3067    }
3068
3069    uint32_t count = loader.scanned_device_layers.count;
3070    struct loader_layer_list *layer_list = &loader.scanned_device_layers;
3071
3072    if (pProperties == NULL) {
3073        *pCount = count;
3074        return VK_SUCCESS;
3075    }
3076
3077    copy_size = *pCount < count ? *pCount : count;
3078    for (uint32_t i = 0; i < copy_size; i++) {
3079        memcpy(&pProperties[i],
3080               &layer_list->list[i].info,
3081               sizeof(VkLayerProperties));
3082    }
3083    *pCount = copy_size;
3084
3085    if (copy_size < count) {
3086        return VK_INCOMPLETE;
3087    }
3088
3089    return VK_SUCCESS;
3090}
3091