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