loader.c revision 70db78736fb002220508fbc8aa79116cd97dc6fe
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    }
593
594    fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
595    if (!fp_get_layer_props) {
596        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
597                   "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
598                   lib_name);
599        return;
600    }
601
602    /*
603     * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
604     * layers and extensions. Thus only ask for info about the first gpu.
605     */
606    res = fp_get_layer_props(gpu, &count, NULL);
607    if (res != VK_SUCCESS) {
608        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
609        return;
610    }
611
612    if (count == 0) {
613        return;
614    }
615
616    layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
617
618    res = fp_get_layer_props(gpu, &count, layer_properties);
619    if (res != VK_SUCCESS) {
620        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
621                   count, lib_name);
622        return;
623    }
624
625    for (i = 0; i < count; i++) {
626        struct loader_layer_properties layer;
627
628        memset(&layer, 0, sizeof(struct loader_layer_properties));
629
630        layer.lib_info.lib_name = lib_name;
631        memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
632
633        loader_init_ext_list(&layer.instance_extension_list);
634        loader_init_ext_list(&layer.device_extension_list);
635
636        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
637                   layer.info.layerName, layer.info.description);
638
639        loader_add_physical_device_extensions(
640                    fp_get_ext_props,
641                    icd->gpus[i],
642                    VK_EXTENSION_ORIGIN_LAYER,
643                    lib_name,
644                    &layer.device_extension_list);
645
646        loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
647    }
648    return;
649}
650
651static bool loader_init_ext_list(struct loader_extension_list *ext_info)
652{
653    ext_info->capacity = 32 * sizeof(struct loader_extension_property);
654    /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
655    ext_info->list = malloc(ext_info->capacity);
656    if (ext_info->list == NULL) {
657        return false;
658    }
659    memset(ext_info->list, 0, ext_info->capacity);
660    ext_info->count = 0;
661    return true;
662}
663
664void loader_destroy_ext_list(struct loader_extension_list *ext_info)
665{
666    free(ext_info->list);
667    ext_info->count = 0;
668    ext_info->capacity = 0;
669}
670
671/**
672 * Search the given search_list for any layers in the props list.
673 * Add these to the output layer_list.  Don't add duplicates to the output layer_list.
674 */
675static VkResult loader_add_layer_names_to_list(
676        struct loader_layer_list *output_list,
677        uint32_t name_count,
678        const char * const *names,
679        const struct loader_layer_list *search_list)
680{
681    struct loader_layer_properties *layer_prop;
682    VkResult err = VK_SUCCESS;
683
684    for (uint32_t i = 0; i < name_count; i++) {
685        const char *search_target = names[i];
686        layer_prop = get_layer_property(search_target, search_list);
687        if (!layer_prop) {
688            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
689            err = VK_ERROR_INVALID_LAYER;
690            continue;
691        }
692
693        loader_add_to_layer_list(output_list, 1, layer_prop);
694    }
695
696    return err;
697}
698
699/*
700 * Append non-duplicate extension properties defined in prop_list
701 * to the given ext_info list
702 */
703void loader_add_to_ext_list(
704        struct loader_extension_list *ext_list,
705        uint32_t prop_list_count,
706        const struct loader_extension_property *props)
707{
708    uint32_t i;
709    struct loader_extension_property *cur_ext;
710
711    if (ext_list->list == NULL || ext_list->capacity == 0) {
712        loader_init_ext_list(ext_list);
713    }
714
715    if (ext_list->list == NULL)
716        return;
717
718    for (i = 0; i < prop_list_count; i++) {
719        cur_ext = (struct loader_extension_property *) &props[i];
720
721        // look for duplicates
722        if (has_vk_extension_property(&cur_ext->info, ext_list)) {
723            continue;
724        }
725
726        // add to list at end
727        // check for enough capacity
728        if (ext_list->count * sizeof(struct loader_extension_property)
729                        >= ext_list->capacity) {
730            // double capacity
731            ext_list->capacity *= 2;
732            /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
733            ext_list->list = realloc(ext_list->list, ext_list->capacity);
734        }
735
736        memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
737        ext_list->count++;
738    }
739}
740
741/*
742 * Manage lists of VkLayerProperties
743 */
744static bool loader_init_layer_list(struct loader_layer_list *list)
745{
746    list->capacity = 32 * sizeof(struct loader_layer_properties);
747    /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
748    list->list = malloc(list->capacity);
749    if (list->list == NULL) {
750        return false;
751    }
752    memset(list->list, 0, list->capacity);
753    list->count = 0;
754    return true;
755}
756
757void loader_destroy_layer_list(struct loader_layer_list *layer_list)
758{
759    free(layer_list->list);
760    layer_list->count = 0;
761    layer_list->capacity = 0;
762}
763
764/*
765 * Manage list of layer libraries (loader_lib_info)
766 */
767static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
768{
769    list->capacity = 32 * sizeof(struct loader_lib_info);
770    /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
771    list->list = malloc(list->capacity);
772    if (list->list == NULL) {
773        return false;
774    }
775    memset(list->list, 0, list->capacity);
776    list->count = 0;
777    return true;
778}
779
780void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
781{
782    for (uint32_t i = 0; i < list->count; i++) {
783        free(list->list[i].lib_name);
784    }
785    free(list->list);
786    list->count = 0;
787    list->capacity = 0;
788}
789
790void loader_add_to_layer_library_list(
791        struct loader_layer_library_list *list,
792        uint32_t item_count,
793        const struct loader_lib_info *new_items)
794{
795    uint32_t i;
796    struct loader_lib_info *item;
797
798    if (list->list == NULL || list->capacity == 0) {
799        loader_init_layer_library_list(list);
800    }
801
802    if (list->list == NULL)
803        return;
804
805    for (i = 0; i < item_count; i++) {
806        item = (struct loader_lib_info *) &new_items[i];
807
808        // look for duplicates
809        for (uint32_t j = 0; j < list->count; j++) {
810            if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
811                continue;
812            }
813        }
814
815        // add to list at end
816        // check for enough capacity
817        if (list->count * sizeof(struct loader_lib_info)
818                        >= list->capacity) {
819            // double capacity
820            list->capacity *= 2;
821            /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
822            list->list = realloc(list->list, list->capacity);
823        }
824
825        memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
826        list->count++;
827    }
828}
829
830/*
831 * Add's library indicated by lib_name to list if it
832 * implements vkGetGlobalLayerProperties or
833 * vkGetPhysicalDeviceLayerProperties.
834 */
835static void loader_add_layer_library(
836        struct loader_instance *instance,
837        const char *lib_name,
838        const loader_platform_dl_handle lib_handle,
839        struct loader_layer_library_list *list)
840{
841    struct loader_lib_info *library_info;
842    PFN_vkGetPhysicalDeviceLayerProperties fp_get_phydev_props;
843    PFN_vkGetGlobalLayerProperties fp_get_layer_props;
844
845    fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
846    fp_get_phydev_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
847
848    if (!fp_get_layer_props && !fp_get_phydev_props)
849        return;
850
851    /*
852     * Allocate enough space for the library name to
853     * immediately follow the loader_lib_info structure
854     */
855    library_info = loader_heap_alloc(instance, sizeof(struct loader_lib_info) + strlen(lib_name) + 1, VK_SYSTEM_ALLOC_TYPE_INTERNAL);
856    if (!library_info) {
857        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
858                   "Malloc for layer library list failed: %s line: %d", __FILE__, __LINE__);
859        return;
860    }
861    memset(library_info, 0, sizeof(struct loader_lib_info));
862    library_info->lib_name = (char *) &library_info[1];
863    strcpy(library_info->lib_name, lib_name);
864
865    loader_add_to_layer_library_list(list, 1, library_info);
866}
867
868/*
869 * Search the given layer list for a list
870 * matching the given VkLayerProperties
871 */
872bool has_vk_layer_property(
873        const VkLayerProperties *vk_layer_prop,
874        const struct loader_layer_list *list)
875{
876    for (uint32_t i = 0; i < list->count; i++) {
877        if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
878            return true;
879    }
880    return false;
881}
882
883/*
884 * Search the given layer list for a layer
885 * matching the given name
886 */
887bool has_layer_name(
888        const char *name,
889        const struct loader_layer_list *list)
890{
891    for (uint32_t i = 0; i < list->count; i++) {
892        if (strcmp(name, list->list[i].info.layerName) == 0)
893            return true;
894    }
895    return false;
896}
897
898/*
899 * Append non-duplicate layer properties defined in prop_list
900 * to the given layer_info list
901 */
902void loader_add_to_layer_list(
903        struct loader_layer_list *list,
904        uint32_t prop_list_count,
905        const struct loader_layer_properties *props)
906{
907    uint32_t i;
908    struct loader_layer_properties *layer;
909
910    if (list->list == NULL || list->capacity == 0) {
911        loader_init_layer_list(list);
912    }
913
914    if (list->list == NULL)
915        return;
916
917    for (i = 0; i < prop_list_count; i++) {
918        layer = (struct loader_layer_properties *) &props[i];
919
920        // look for duplicates
921        if (has_vk_layer_property(&layer->info, list)) {
922            continue;
923        }
924
925        // add to list at end
926        // check for enough capacity
927        if (list->count * sizeof(struct loader_layer_properties)
928                        >= list->capacity) {
929            // double capacity
930            list->capacity *= 2;
931            list->list = realloc(list->list, list->capacity);
932        }
933
934        memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
935        list->count++;
936    }
937}
938
939/*
940 * Search the search_list for any layer with
941 * a name that matches the given layer_name.
942 * Add all matching layers to the found_list
943 * Do not add if found VkLayerProperties is already
944 * on the found_list.
945 */
946static void loader_find_layer_name_add_list(
947        const char *name,
948        const struct loader_layer_list *search_list,
949        struct loader_layer_list *found_list)
950{
951    for (uint32_t i = 0; i < search_list->count; i++) {
952        struct loader_layer_properties *layer_prop = &search_list->list[i];
953        if (0 == strcmp(layer_prop->info.layerName, name)) {
954            /* Found a layer with the same name, add to found_list */
955            loader_add_to_layer_list(found_list, 1, layer_prop);
956        }
957    }
958}
959
960static struct loader_extension_property *get_extension_property(
961        const char *name,
962        const struct loader_extension_list *list)
963{
964    for (uint32_t i = 0; i < list->count; i++) {
965        const VkExtensionProperties *item = &list->list[i].info;
966        if (strcmp(name, item->extName) == 0)
967            return &list->list[i];
968    }
969    return NULL;
970}
971
972/*
973 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
974 * the extension must provide two entry points for the loader to use:
975 * - "trampoline" entry point - this is the address returned by GetProcAddr
976 * and will always do what's necessary to support a global call.
977 * - "terminator" function - this function will be put at the end of the
978 * instance chain and will contain the necessary logica to call / process
979 * the extension for the appropriate ICDs that are available.
980 * There is no generic mechanism for including these functions, the references
981 * must be placed into the appropriate loader entry points.
982 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
983 * loader_coalesce_extensions(void) - add extension records to the list of global
984 * extension available to the app.
985 * instance_disp - add function pointer for terminator function to this array.
986 * The extension itself should be in a separate file that will be
987 * linked directly with the loader.
988 */
989void loader_coalesce_extensions(void)
990{
991    struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
992
993    // traverse scanned icd list adding non-duplicate extensions to the list
994    while (icd_list != NULL) {
995        loader_add_to_ext_list(&loader.global_extensions,
996                               icd_list->global_extension_list.count,
997                               icd_list->global_extension_list.list);
998        icd_list = icd_list->next;
999    };
1000
1001    // Traverse loader's extensions, adding non-duplicate extensions to the list
1002    debug_report_add_instance_extensions(&loader.global_extensions);
1003}
1004
1005static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
1006                                                    struct loader_device **found_dev)
1007{
1008    *found_dev = NULL;
1009    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1010        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1011            for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
1012                if (dev->device == device) {
1013                    *found_dev = dev;
1014                    return icd;
1015                }
1016        }
1017    }
1018    return NULL;
1019}
1020
1021static void loader_destroy_logical_device(struct loader_device *dev)
1022{
1023    free(dev->app_extension_props);
1024    if (dev->activated_layer_list.count)
1025        loader_destroy_layer_list(&dev->activated_layer_list);
1026    free(dev);
1027}
1028
1029static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
1030{
1031    struct loader_device *new_dev;
1032
1033    new_dev = malloc(sizeof(struct loader_device));
1034    if (!new_dev) {
1035        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
1036        return NULL;
1037    }
1038
1039    memset(new_dev, 0, sizeof(struct loader_device));
1040
1041    new_dev->next = *device_list;
1042    new_dev->device = dev;
1043    *device_list = new_dev;
1044    return new_dev;
1045}
1046
1047void loader_remove_logical_device(VkDevice device)
1048{
1049    struct loader_device *found_dev, *dev, *prev_dev;
1050    struct loader_icd *icd;
1051    icd = loader_get_icd_and_device(device, &found_dev);
1052
1053    if (!icd || !found_dev)
1054        return;
1055
1056    prev_dev = NULL;
1057    dev = icd->logical_device_list;
1058    while (dev && dev != found_dev) {
1059        prev_dev = dev;
1060        dev = dev->next;
1061    }
1062
1063    if (prev_dev)
1064        prev_dev->next = found_dev->next;
1065    else
1066        icd->logical_device_list = found_dev->next;
1067    loader_destroy_logical_device(found_dev);
1068}
1069
1070
1071static void loader_icd_destroy(
1072        struct loader_instance *ptr_inst,
1073        struct loader_icd *icd)
1074{
1075    ptr_inst->total_icd_count--;
1076    free(icd->gpus);
1077    for (struct loader_device *dev = icd->logical_device_list; dev; ) {
1078        struct loader_device *next_dev = dev->next;
1079        loader_destroy_logical_device(dev);
1080        dev = next_dev;
1081    }
1082
1083    free(icd);
1084}
1085
1086static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
1087{
1088    struct loader_icd *icd;
1089
1090    icd = malloc(sizeof(*icd));
1091    if (!icd)
1092        return NULL;
1093
1094    memset(icd, 0, sizeof(*icd));
1095
1096    icd->scanned_icds = scanned;
1097
1098    return icd;
1099}
1100
1101static struct loader_icd *loader_icd_add(
1102        struct loader_instance *ptr_inst,
1103        const struct loader_scanned_icds *scanned)
1104{
1105    struct loader_icd *icd;
1106
1107    icd = loader_icd_create(scanned);
1108    if (!icd)
1109        return NULL;
1110
1111    /* prepend to the list */
1112    icd->next = ptr_inst->icds;
1113    ptr_inst->icds = icd;
1114    ptr_inst->total_icd_count++;
1115
1116    return icd;
1117}
1118
1119static void loader_scanned_icd_add(const char *filename)
1120{
1121    loader_platform_dl_handle handle;
1122    void *fp_create_inst;
1123    void *fp_get_global_ext_props;
1124    void *fp_get_device_ext_props;
1125    PFN_vkGPA fp_get_proc_addr;
1126    struct loader_scanned_icds *new_node;
1127
1128    // Used to call: dlopen(filename, RTLD_LAZY);
1129    handle = loader_platform_open_library(filename);
1130    if (!handle) {
1131        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
1132        return;
1133    }
1134
1135#define LOOKUP(func_ptr, func) do {                            \
1136    func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
1137    if (!func_ptr) {                                           \
1138        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
1139        return;                                                \
1140    }                                                          \
1141} while (0)
1142
1143    LOOKUP(fp_create_inst, CreateInstance);
1144    LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
1145    LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
1146    LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
1147#undef LOOKUP
1148
1149    new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
1150                                                     + strlen(filename) + 1);
1151    if (!new_node) {
1152        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
1153        return;
1154    }
1155
1156    new_node->handle = handle;
1157    new_node->CreateInstance = fp_create_inst;
1158    new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
1159    loader_init_ext_list(&new_node->global_extension_list);
1160    loader_init_ext_list(&new_node->device_extension_list);
1161    new_node->next = loader.scanned_icd_list;
1162
1163    new_node->lib_name = (char *) (new_node + 1);
1164    if (!new_node->lib_name) {
1165        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
1166        return;
1167    }
1168    strcpy(new_node->lib_name, filename);
1169
1170    loader.scanned_icd_list = new_node;
1171
1172    loader_add_global_extensions(
1173                (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
1174                new_node->lib_name,
1175                handle,
1176                VK_EXTENSION_ORIGIN_ICD,
1177                &new_node->global_extension_list);
1178}
1179
1180static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1181{
1182    if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1183        return &loader.global_extensions;
1184    }
1185
1186    /* Find and return global extension list for given layer */
1187    for (uint32_t i = 0; i < loader.global_layer_list.count; i++) {
1188        struct loader_layer_properties *work_layer = &loader.global_layer_list.list[i];
1189        if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1190            return &work_layer->instance_extension_list;
1191        }
1192    }
1193
1194    return NULL;
1195}
1196
1197static struct loader_layer_list *loader_global_layers()
1198{
1199    return &loader.global_layer_list;
1200}
1201
1202static void loader_physical_device_layers(
1203        struct loader_icd *icd,
1204        uint32_t *count,
1205        struct loader_layer_list **list)
1206{
1207    *count = icd->layer_properties_cache.count;
1208    *list = &icd->layer_properties_cache;
1209}
1210
1211static void loader_physical_device_extensions(
1212        struct loader_icd *icd,
1213        uint32_t gpu_idx,
1214        const char *layer_name,
1215        uint32_t *count,
1216        struct loader_extension_list **list)
1217{
1218    if (layer_name == NULL || (strlen(layer_name) == 0)) {
1219        *count = icd->device_extension_cache[gpu_idx].count;
1220        *list = &icd->device_extension_cache[gpu_idx];
1221        return;
1222    }
1223    for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1224        if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1225            *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1226            *list = &icd->layer_properties_cache.list[i].device_extension_list;
1227        }
1228    }
1229}
1230
1231static void loader_icd_init_entrys(struct loader_icd *icd,
1232                                   struct loader_scanned_icds *scanned_icds)
1233{
1234    /* initialize entrypoint function pointers */
1235
1236    #define LOOKUP(func) do {                                 \
1237    icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1238    if (!icd->func) {                                           \
1239        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
1240        return;                                                \
1241    }                                                          \
1242    } while (0)
1243
1244    /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1245    LOOKUP(GetDeviceProcAddr);
1246    LOOKUP(DestroyInstance);
1247    LOOKUP(EnumeratePhysicalDevices);
1248    LOOKUP(GetPhysicalDeviceFeatures);
1249    LOOKUP(GetPhysicalDeviceFormatInfo);
1250    LOOKUP(GetPhysicalDeviceLimits);
1251    LOOKUP(CreateDevice);
1252    LOOKUP(GetPhysicalDeviceProperties);
1253    LOOKUP(GetPhysicalDeviceMemoryProperties);
1254    LOOKUP(GetPhysicalDevicePerformance);
1255    LOOKUP(GetPhysicalDeviceQueueCount);
1256    LOOKUP(GetPhysicalDeviceQueueProperties);
1257    LOOKUP(GetPhysicalDeviceExtensionProperties);
1258    LOOKUP(DbgCreateMsgCallback);
1259    LOOKUP(DbgDestroyMsgCallback);
1260#undef LOOKUP
1261
1262    return;
1263}
1264
1265static void loader_debug_init(void)
1266{
1267    const char *env;
1268
1269    if (g_loader_debug > 0)
1270        return;
1271
1272    g_loader_debug = 0;
1273
1274    /* parse comma-separated debug options */
1275    env = getenv("LOADER_DEBUG");
1276    while (env) {
1277        const char *p = strchr(env, ',');
1278        size_t len;
1279
1280        if (p)
1281            len = p - env;
1282        else
1283            len = strlen(env);
1284
1285        if (len > 0) {
1286            if (strncmp(env, "warn", len) == 0) {
1287                g_loader_debug |= LOADER_WARN_BIT;
1288                g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1289            } else if (strncmp(env, "info", len) == 0) {
1290                g_loader_debug |= LOADER_INFO_BIT;
1291                g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1292            } else if (strncmp(env, "perf", len) == 0) {
1293                g_loader_debug |= LOADER_PERF_BIT;
1294                g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1295            } else if (strncmp(env, "error", len) == 0) {
1296                g_loader_debug |= LOADER_ERROR_BIT;
1297                g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1298            } else if (strncmp(env, "debug", len) == 0) {
1299                g_loader_debug |= LOADER_DEBUG_BIT;
1300                g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1301            }
1302        }
1303
1304        if (!p)
1305            break;
1306
1307        env = p + 1;
1308    }
1309}
1310
1311struct loader_manifest_files {
1312    uint32_t count;
1313    char **filename_list;
1314};
1315
1316/**
1317 * Get next file or dirname given a string list or registry key path
1318 *
1319 * \returns
1320 * A pointer to first char in the next path.
1321 * The next path (or NULL) in the list is returned in next_path.
1322 * Note: input string is modified in some cases. PASS IN A COPY!
1323 */
1324static char *loader_get_next_path(char *path)
1325{
1326    uint32_t len;
1327    char *next;
1328
1329    if (path == NULL)
1330        return NULL;
1331    next = strchr(path, PATH_SEPERATOR);
1332    if (next == NULL) {
1333        len = (uint32_t) strlen(path);
1334        next = path + len;
1335    }
1336    else {
1337        *next = '\0';
1338        next++;
1339    }
1340
1341    return next;
1342}
1343
1344/**
1345 * Given a filename (file)  and a list of paths (dir), try to find an existing
1346 * file in the paths.  If filename already is a path then no
1347 * searching in the given paths.
1348 *
1349 * \returns
1350 * A string in out_fullpath of either the full path or file.
1351 * Side effect is that dir string maybe modified.
1352 */
1353static void loader_get_fullpath(const char *file,
1354                                char *dir,
1355                                size_t out_size,
1356                                char *out_fullpath)
1357{
1358    char *next_dir;
1359    if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1360        //find file exists with prepending given path
1361        while (*dir) {
1362            next_dir = loader_get_next_path(dir);
1363            snprintf(out_fullpath, out_size, "%s%c%s",
1364                     dir, DIRECTORY_SYMBOL, file);
1365            if (loader_platform_file_exists(out_fullpath)) {
1366                return;
1367            }
1368            dir = next_dir;
1369        }
1370    }
1371    snprintf(out_fullpath, out_size, "%s", file);
1372}
1373
1374/**
1375 * Read a JSON file into a buffer.
1376 *
1377 * \returns
1378 * A pointer to a cJSON object representing the JSON parse tree.
1379 * This returned buffer should be freed by caller.
1380 */
1381static cJSON *loader_get_json(const char *filename)
1382{
1383    FILE *file;
1384    char *json_buf;
1385    cJSON *json;
1386    uint64_t len;
1387    file = fopen(filename,"rb");
1388    fseek(file, 0, SEEK_END);
1389    len = ftell(file);
1390    fseek(file, 0, SEEK_SET);
1391    json_buf = (char*) loader_stack_alloc(len+1);
1392    if (json_buf == NULL) {
1393        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1394        fclose(file);
1395        return NULL;
1396    }
1397    if (fread(json_buf, sizeof(char), len, file) != len) {
1398        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1399        fclose(file);
1400        return NULL;
1401    }
1402    fclose(file);
1403    json_buf[len] = '\0';
1404
1405    //parse text from file
1406    json = cJSON_Parse(json_buf);
1407    if (json == NULL)
1408        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1409    return json;
1410}
1411
1412/**
1413 * Find the Vulkan library manifest files.
1414 *
1415 * This function scans the location or env_override directories/files
1416 * for a list of JSON manifest files.  If env_override is non-NULL
1417 * and has a valid value. Then the location is ignored.  Otherwise
1418 * location is used to look for manifest files. The location
1419 * is interpreted as  Registry path on Windows and a directory path(s)
1420 * on Linux.
1421 *
1422 * \returns
1423 * A string list of manifest files to be opened in out_files param.
1424 * List has a pointer to string for each manifest filename.
1425 * When done using the list in out_files, pointers should be freed.
1426 * Location or override  string lists can be either files or directories as follows:
1427 *            | location | override
1428 * --------------------------------
1429 * Win ICD    | files    | files
1430 * Win Layer  | files    | dirs
1431 * Linux ICD  | dirs     | files
1432 * Linux Layer| dirs     | dirs
1433 */
1434static void loader_get_manifest_files(const char *env_override,
1435                                      bool is_layer,
1436                                      const char *location,
1437                                      struct loader_manifest_files *out_files)
1438{
1439    char *override = NULL;
1440    char *loc;
1441    char *file, *next_file, *name;
1442    size_t alloced_count = 64;
1443    char full_path[2048];
1444    DIR *sysdir = NULL;
1445    bool list_is_dirs = false;
1446    struct dirent *dent;
1447
1448    out_files->count = 0;
1449    out_files->filename_list = NULL;
1450
1451    if (env_override != NULL && (override = getenv(env_override))) {
1452#if defined(__linux__)
1453        if (geteuid() != getuid()) {
1454            /* Don't allow setuid apps to use the env var: */
1455            override = NULL;
1456        }
1457#endif
1458    }
1459
1460    if (location == NULL) {
1461        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1462            "Can't get manifest files with NULL location, env_override=%s",
1463            env_override);
1464        return;
1465    }
1466
1467#if defined(__linux__)
1468    list_is_dirs = (override == NULL || is_layer) ? true : false;
1469#else //WIN32
1470    list_is_dirs = (is_layer && override != NULL) ? true : false;
1471#endif
1472    // Make a copy of the input we are using so it is not modified
1473    // Also handle getting the location(s) from registry on Windows
1474    if (override == NULL) {
1475#if defined (_WIN32)
1476        loc = loader_get_registry_files(location);
1477        if (loc == NULL) {
1478            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1479            return;
1480        }
1481#else
1482        loc = alloca(strlen(location) + 1);
1483        if (loc == NULL) {
1484            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1485            return;
1486        }
1487        strcpy(loc, location);
1488#endif
1489    }
1490    else {
1491        loc = loader_stack_alloc(strlen(override) + 1);
1492        if (loc == NULL) {
1493            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1494            return;
1495        }
1496        strcpy(loc, override);
1497    }
1498
1499    file = loc;
1500    while (*file) {
1501        next_file = loader_get_next_path(file);
1502        if (list_is_dirs) {
1503            sysdir = opendir(file);
1504            name = NULL;
1505            if (sysdir) {
1506                dent = readdir(sysdir);
1507                if (dent == NULL)
1508                    break;
1509                name = &(dent->d_name[0]);
1510                loader_get_fullpath(name, file, sizeof(full_path), full_path);
1511                name = full_path;
1512            }
1513        }
1514        else {
1515#if defined(__linux__)
1516            // only Linux has relative paths
1517            char *dir;
1518            // make a copy of location so it isn't modified
1519            dir = alloca(strlen(location) + 1);
1520            if (dir == NULL) {
1521                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1522                return;
1523            }
1524            strcpy(dir, location);
1525
1526            loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1527
1528            name = full_path;
1529#else  // WIN32
1530            name = file;
1531#endif
1532        }
1533        while (name) {
1534                /* Look for files ending with ".json" suffix */
1535                uint32_t nlen = (uint32_t) strlen(name);
1536                const char *suf = name + nlen - 5;
1537                if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1538                    if (out_files->count == 0) {
1539                        out_files->filename_list = malloc(alloced_count * sizeof(char *));
1540                    }
1541                    else if (out_files->count == alloced_count) {
1542                        out_files->filename_list = realloc(out_files->filename_list,
1543                                        alloced_count * sizeof(char *) * 2);
1544                        alloced_count *= 2;
1545                    }
1546                    if (out_files->filename_list == NULL) {
1547                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1548                        return;
1549                    }
1550                    out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1551                    if (out_files->filename_list[out_files->count] == NULL) {
1552                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1553                        return;
1554                    }
1555                    strcpy(out_files->filename_list[out_files->count], name);
1556                    out_files->count++;
1557                } else if (!list_is_dirs) {
1558                    loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
1559                }
1560                if (list_is_dirs) {
1561                    dent = readdir(sysdir);
1562                    if (dent == NULL)
1563                        break;
1564                    name = &(dent->d_name[0]);
1565                    loader_get_fullpath(name, file, sizeof(full_path), full_path);
1566                    name = full_path;
1567                }
1568                else {
1569                    break;
1570                }
1571        }
1572        if (sysdir)
1573            closedir(sysdir);
1574        file = next_file;
1575    }
1576    return;
1577}
1578
1579/**
1580 * Try to find the Vulkan ICD driver(s).
1581 *
1582 * This function scans the default system loader path(s) or path
1583 * specified by the \c VK_ICD_FILENAMES environment variable in
1584 * order to find loadable VK ICDs manifest files. From these
1585 * manifest files it finds the ICD libraries.
1586 *
1587 * \returns
1588 * void
1589 */
1590void loader_icd_scan(void)
1591{
1592    char *file_str;
1593    struct loader_manifest_files manifest_files;
1594
1595
1596    // convenient place to initialize a mutex
1597    loader_platform_thread_create_mutex(&loader_lock);
1598
1599    // convenient place to initialize logging
1600    loader_debug_init();
1601
1602    // Get a list of manifest files for ICDs
1603    loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1604                              &manifest_files);
1605    for (uint32_t i = 0; i < manifest_files.count; i++) {
1606        file_str = manifest_files.filename_list[i];
1607        if (file_str == NULL)
1608            continue;
1609
1610        cJSON *json, *icd_json;
1611        json = loader_get_json(file_str);
1612        icd_json = cJSON_GetObjectItem(json, "ICD");
1613        if (icd_json != NULL) {
1614            icd_json = cJSON_GetObjectItem(icd_json, "library_path");
1615            if (icd_json != NULL) {
1616                char *icd_filename = cJSON_PrintUnformatted(icd_json);
1617                char *icd_file = icd_filename;
1618                if (icd_filename != NULL) {
1619                    char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1620                    char *dir = def_dir;
1621                    // strip off extra quotes
1622                    if (icd_filename[strlen(icd_filename)  - 1] == '"')
1623                        icd_filename[strlen(icd_filename) - 1] = '\0';
1624                    if (icd_filename[0] == '"')
1625                        icd_filename++;
1626#if defined(__linux__)
1627                    char full_path[2048];
1628                    loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1629                    loader_scanned_icd_add(full_path);
1630#else // WIN32
1631                    loader_scanned_icd_add(icd_filename);
1632#endif
1633                    free(icd_file);
1634                }
1635            }
1636            else
1637                loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1638        }
1639        else
1640            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1641
1642        free(file_str);
1643        cJSON_Delete(json);
1644    }
1645    free(manifest_files.filename_list);
1646
1647}
1648
1649
1650void loader_layer_scan(void)
1651{
1652    uint32_t len;
1653    const char *p, *next;
1654    char *libPaths = NULL;
1655    DIR *curdir;
1656    struct dirent *dent;
1657    char temp_str[1024];
1658
1659#if defined(WIN32)
1660    bool must_free_libPaths;
1661    libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
1662                                           LAYERS_PATH_REGISTRY_VALUE);
1663    if (libPaths != NULL) {
1664        must_free_libPaths = true;
1665    } else {
1666        must_free_libPaths = false;
1667        libPaths = DEFAULT_VK_LAYERS_PATH;
1668    }
1669#else  // WIN32
1670    if (geteuid() == getuid()) {
1671        /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
1672        libPaths = getenv(LAYERS_PATH_ENV);
1673    }
1674    if (libPaths == NULL) {
1675        libPaths = DEFAULT_VK_LAYERS_PATH;
1676    }
1677#endif // WIN32
1678
1679    if (libPaths == NULL) {
1680        // Have no paths to search:
1681        return;
1682    }
1683    len = strlen(libPaths);
1684    loader.layer_dirs = malloc(len+1);
1685    if (loader.layer_dirs == NULL) {
1686        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
1687
1688        free(libPaths);
1689        return;
1690    }
1691    // Alloc passed, so we know there is enough space to hold the string
1692    strcpy(loader.layer_dirs, libPaths);
1693#if defined(WIN32)
1694    // Free any allocated memory:
1695    if (must_free_libPaths) {
1696        free(libPaths);
1697        must_free_libPaths = false;
1698    }
1699#endif // WIN32
1700    libPaths = loader.layer_dirs;
1701
1702    /*
1703     * We need a list of the layer libraries, not just a list of
1704     * the layer properties (a layer library could expose more than
1705     * one layer property). This list of scanned layers would be
1706     * used to check for global and physicaldevice layer properties.
1707     */
1708    if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1709        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1710                   "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1711        return;
1712    }
1713
1714    for (p = libPaths; *p; p = next) {
1715        next = strchr(p, PATH_SEPERATOR);
1716        if (next == NULL) {
1717            len = (uint32_t) strlen(p);
1718            next = p + len;
1719        }
1720        else {
1721            len = (uint32_t) (next - p);
1722            *(char *) next = '\0';
1723            next++;
1724        }
1725
1726        curdir = opendir(p);
1727        if (curdir) {
1728            dent = readdir(curdir);
1729            while (dent) {
1730                /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
1731                 * ending with VK_LIBRARY_SUFFIX
1732                 */
1733                if (!strncmp(dent->d_name,
1734                             VK_LAYER_LIBRARY_PREFIX,
1735                             VK_LAYER_LIBRARY_PREFIX_LEN)) {
1736                    uint32_t nlen = (uint32_t) strlen(dent->d_name);
1737                    const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
1738                    if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
1739                            !strncmp(suf,
1740                                     VK_LIBRARY_SUFFIX,
1741                                     VK_LIBRARY_SUFFIX_LEN)) {
1742                        loader_platform_dl_handle handle;
1743                        snprintf(temp_str, sizeof(temp_str),
1744                                 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
1745                        // Used to call: dlopen(temp_str, RTLD_LAZY)
1746                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1747                                   "Attempt to open library: %s", temp_str);
1748                        if ((handle = loader_platform_open_library(temp_str)) == NULL) {
1749                            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
1750                            dent = readdir(curdir);
1751                            continue;
1752                        }
1753                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1754                                   "Opened library: %s", temp_str);
1755
1756                        /* TODO: Need instance pointer here */
1757                        loader_add_layer_library(NULL, temp_str, handle, &loader.scanned_layer_libraries);
1758
1759                        loader_add_global_layer_properties(temp_str, handle, &loader.global_layer_list);
1760
1761                        loader_platform_close_library(handle);
1762                    }
1763                }
1764
1765                dent = readdir(curdir);
1766            } // while (dir_entry)
1767            closedir(curdir);
1768        } // if (curdir))
1769    } // for (libpaths)
1770}
1771
1772static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1773{
1774    // inst is not wrapped
1775    if (inst == VK_NULL_HANDLE) {
1776        return NULL;
1777    }
1778    VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1779    void *addr;
1780
1781    if (!strcmp(pName, "vkGetInstanceProcAddr"))
1782        return (void *) loader_gpa_instance_internal;
1783
1784    if (disp_table == NULL)
1785        return NULL;
1786
1787    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1788    if (addr) {
1789        return addr;
1790    }
1791
1792    if (disp_table->GetInstanceProcAddr == NULL) {
1793        return NULL;
1794    }
1795    return disp_table->GetInstanceProcAddr(inst, pName);
1796}
1797
1798struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
1799{
1800
1801    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1802        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1803            for (uint32_t i = 0; i < icd->gpu_count; i++)
1804                if (icd->gpus[i] == gpu) {
1805                    *gpu_index = i;
1806                    return icd;
1807                }
1808        }
1809    }
1810    return NULL;
1811}
1812
1813static loader_platform_dl_handle loader_add_layer_lib(
1814        const char *chain_type,
1815        struct loader_layer_properties *layer_prop)
1816{
1817    struct loader_lib_info *new_layer_lib_list, *my_lib;
1818
1819    /*
1820     * TODO: We can now track this information in the
1821     * scanned_layer_libraries list.
1822     */
1823    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1824        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
1825            /* Have already loaded this library, just increment ref count */
1826            loader.loaded_layer_lib_list[i].ref_count++;
1827            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1828                       "%s Chain: Increment layer reference count for layer library %s",
1829                       chain_type, layer_prop->lib_info.lib_name);
1830            return loader.loaded_layer_lib_list[i].lib_handle;
1831        }
1832    }
1833
1834    /* Haven't seen this library so load it */
1835    new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1836                      (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1837    if (!new_layer_lib_list) {
1838        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1839        return NULL;
1840    }
1841
1842    my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1843
1844    /* NOTE: We require that the layer property be immutable */
1845    my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
1846    my_lib->ref_count = 0;
1847    my_lib->lib_handle = NULL;
1848
1849    if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1850        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1851                   loader_platform_open_library_error(my_lib->lib_name));
1852        return NULL;
1853    } else {
1854        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1855                   "Chain: %s: Loading layer library %s",
1856                   chain_type, layer_prop->lib_info.lib_name);
1857    }
1858    loader.loaded_layer_lib_count++;
1859    loader.loaded_layer_lib_list = new_layer_lib_list;
1860    my_lib->ref_count++;
1861
1862    return my_lib->lib_handle;
1863}
1864
1865static void loader_remove_layer_lib(
1866        struct loader_instance *inst,
1867        struct loader_layer_properties *layer_prop)
1868{
1869    uint32_t idx;
1870    struct loader_lib_info *new_layer_lib_list, *my_lib;
1871
1872    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1873        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
1874            /* found matching library */
1875            idx = i;
1876            my_lib = &loader.loaded_layer_lib_list[i];
1877            break;
1878        }
1879    }
1880
1881    my_lib->ref_count--;
1882    if (my_lib->ref_count > 0) {
1883        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1884                   "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
1885        return;
1886    }
1887
1888    loader_platform_close_library(my_lib->lib_handle);
1889    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1890               "Unloading layer library %s", layer_prop->lib_info.lib_name);
1891
1892    /* Need to remove unused library from list */
1893    new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1894    if (!new_layer_lib_list) {
1895        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1896        return;
1897    }
1898
1899    if (idx > 0) {
1900        /* Copy records before idx */
1901        memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1902               sizeof(struct loader_lib_info) * idx);
1903    }
1904    if (idx < (loader.loaded_layer_lib_count - 1)) {
1905        /* Copy records after idx */
1906        memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1907                sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1908    }
1909
1910    free(loader.loaded_layer_lib_list);
1911    loader.loaded_layer_lib_count--;
1912    loader.loaded_layer_lib_list = new_layer_lib_list;
1913}
1914
1915static void loader_add_layer_implicit(
1916                const enum layer_type type,
1917                struct loader_layer_list *list,
1918                struct loader_layer_list *search_list)
1919{
1920    uint32_t i;
1921    for (i = 0; i < search_list->count; i++) {
1922        const struct loader_layer_properties *prop = &search_list->list[i];
1923        if (prop->type & type) {
1924            /* Found an layer with the same type, add to layer_list */
1925            loader_add_to_layer_list(list, 1, prop);
1926        }
1927    }
1928
1929}
1930
1931/**
1932 * Get the layer name(s) from the env_name environment variable. If layer
1933 * is found in search_list then add it to layer_list.
1934 */
1935static void loader_add_layer_env(
1936                const char *env_name,
1937                struct loader_layer_list *layer_list,
1938                const struct loader_layer_list *search_list)
1939{
1940    char *layerEnv;
1941    char *next, *name;
1942
1943    layerEnv = getenv(env_name);
1944    if (layerEnv == NULL) {
1945        return;
1946    }
1947    name = loader_stack_alloc(strlen(layerEnv) + 1);
1948    if (name == NULL) {
1949        return;
1950    }
1951    strcpy(name, layerEnv);
1952
1953    while (name && *name ) {
1954        next = loader_get_next_path(name);
1955        loader_find_layer_name_add_list(name, search_list, layer_list);
1956        name = next;
1957    }
1958
1959    return;
1960}
1961
1962void loader_deactivate_instance_layers(struct loader_instance *instance)
1963{
1964    if (!instance->activated_layer_list.count) {
1965        return;
1966    }
1967
1968    /* Create instance chain of enabled layers */
1969    for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1970        struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
1971
1972        loader_remove_layer_lib(instance, layer_prop);
1973    }
1974    loader_destroy_layer_list(&instance->activated_layer_list);
1975}
1976
1977VkResult loader_enable_instance_layers(
1978        struct loader_instance *inst,
1979        const VkInstanceCreateInfo *pCreateInfo)
1980{
1981    VkResult err;
1982
1983    if (inst == NULL)
1984        return VK_ERROR_UNKNOWN;
1985
1986    if (!loader_init_layer_list(&inst->activated_layer_list)) {
1987        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
1988        return VK_ERROR_OUT_OF_HOST_MEMORY;
1989    }
1990
1991    /* Add any implicit layers first */
1992    loader_add_layer_implicit(
1993                                VK_LAYER_TYPE_INSTANCE_IMPLICIT,
1994                                &inst->activated_layer_list,
1995                                &loader.global_layer_list);
1996
1997    /* Add any layers specified via environment variable first */
1998    loader_add_layer_env(
1999                            "VK_INSTANCE_LAYERS",
2000                            &inst->activated_layer_list,
2001                            &loader.global_layer_list);
2002
2003    /* Add layers specified by the application */
2004    err = loader_add_layer_names_to_list(
2005                &inst->activated_layer_list,
2006                pCreateInfo->layerCount,
2007                pCreateInfo->ppEnabledLayerNames,
2008                &loader.global_layer_list);
2009
2010    return err;
2011}
2012
2013uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2014{
2015    uint32_t layer_idx;
2016    VkBaseLayerObject *wrappedInstance;
2017
2018    if (inst == NULL) {
2019        return 0;
2020    }
2021
2022    // NOTE inst is unwrapped at this point in time
2023    VkObject baseObj = (VkObject) inst;
2024    VkObject nextObj = (VkObject) inst;
2025    VkBaseLayerObject *nextInstObj;
2026    PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2027
2028    if (!inst->activated_layer_list.count) {
2029        return 0;
2030    }
2031
2032    wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
2033                                   * inst->activated_layer_list.count);
2034    if (!wrappedInstance) {
2035        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2036        return 0;
2037    }
2038
2039    /* Create instance chain of enabled layers */
2040    layer_idx = inst->activated_layer_list.count - 1;
2041    for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
2042        struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
2043        loader_platform_dl_handle lib_handle;
2044
2045         /*
2046         * Note: An extension's Get*ProcAddr should not return a function pointer for
2047         * any extension entry points until the extension has been enabled.
2048         * To do this requires a different behavior from Get*ProcAddr functions implemented
2049         * in layers.
2050         * The very first call to a layer will be it's Get*ProcAddr function requesting
2051         * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2052         * with the wrapped object given (either Instance or Device) and return the layer's
2053         * Get*ProcAddr function. The layer should also use this opportunity to record the
2054         * baseObject so that it can find the correct local dispatch table on future calls.
2055         * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2056         * will not use a wrapped object and must look up their local dispatch table from
2057         * the given baseObject.
2058         */
2059        nextInstObj = (wrappedInstance + layer_idx);
2060        nextInstObj->pGPA = nextGPA;
2061        nextInstObj->baseObject = baseObj;
2062        nextInstObj->nextObject = nextObj;
2063        nextObj = (VkObject) nextInstObj;
2064
2065        char funcStr[256];
2066        snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2067        lib_handle = loader_add_layer_lib("instance", layer_prop);
2068        if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2069            nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
2070        if (!nextGPA) {
2071            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name);
2072
2073            /* TODO: Should we return nextObj, nextGPA to previous? */
2074            continue;
2075        }
2076
2077        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
2078                   "Insert instance layer %s (%s)",
2079                   layer_prop->info.layerName,
2080                   layer_prop->lib_info.lib_name);
2081
2082        layer_idx--;
2083    }
2084
2085    loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
2086
2087    return inst->activated_layer_list.count;
2088}
2089
2090void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2091{
2092
2093    loader_init_instance_extension_dispatch_table(inst->disp,
2094                                                  inst->disp->GetInstanceProcAddr,
2095                                                  (VkInstance) inst);
2096}
2097
2098static VkResult loader_enable_device_layers(
2099        struct loader_icd *icd,
2100        struct loader_device *dev,
2101        const VkDeviceCreateInfo *pCreateInfo)
2102{
2103    VkResult err;
2104
2105    if (dev == NULL)
2106        return VK_ERROR_UNKNOWN;
2107
2108    if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
2109        loader_init_layer_list(&dev->activated_layer_list);
2110    }
2111
2112    if (dev->activated_layer_list.list == NULL) {
2113        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
2114        return VK_ERROR_OUT_OF_HOST_MEMORY;
2115    }
2116
2117    /* Add any implicit layers first */
2118    loader_add_layer_implicit(
2119                VK_LAYER_TYPE_DEVICE_IMPLICIT,
2120                &dev->activated_layer_list,
2121                &icd->layer_properties_cache);
2122
2123    /* Add any layers specified via environment variable next */
2124    loader_add_layer_env(
2125                "VK_DEVICE_LAYERS",
2126                &dev->activated_layer_list,
2127                &icd->layer_properties_cache);
2128
2129    /* Add layers specified by the application */
2130    err = loader_add_layer_names_to_list(
2131                &dev->activated_layer_list,
2132                pCreateInfo->layerCount,
2133                pCreateInfo->ppEnabledLayerNames,
2134                &icd->layer_properties_cache);
2135
2136    return err;
2137}
2138
2139/*
2140 * This function terminates the device chain fro CreateDevice.
2141 * CreateDevice is a special case and so the loader call's
2142 * the ICD's CreateDevice before creating the chain. Since
2143 * we can't call CreateDevice twice we must terminate the
2144 * device chain with something else.
2145 */
2146static VkResult scratch_vkCreateDevice(
2147    VkPhysicalDevice          gpu,
2148    const VkDeviceCreateInfo *pCreateInfo,
2149    VkDevice                 *pDevice)
2150{
2151    return VK_SUCCESS;
2152}
2153
2154static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2155{
2156    if (!strcmp(name, "vkGetDeviceProcAddr"))
2157        return (void *) loader_GetDeviceChainProcAddr;
2158    if (!strcmp(name, "vkCreateDevice"))
2159        return (void *) scratch_vkCreateDevice;
2160
2161    struct loader_device *found_dev;
2162    struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2163    return icd->GetDeviceProcAddr(device, name);
2164}
2165
2166static uint32_t loader_activate_device_layers(
2167        struct loader_icd *icd,
2168        struct loader_device *dev,
2169        VkDevice device)
2170{
2171    if (!icd)
2172        return 0;
2173
2174    if (!dev) {
2175        return 0;
2176    }
2177
2178    /* activate any layer libraries */
2179    VkObject nextObj = (VkObject) device;
2180    VkObject baseObj = nextObj;
2181    VkBaseLayerObject *nextGpuObj;
2182    PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
2183    VkBaseLayerObject *wrappedGpus;
2184
2185    if (!dev->activated_layer_list.count)
2186        return 0;
2187
2188    wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2189    if (!wrappedGpus) {
2190        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2191        return 0;
2192    }
2193
2194    for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2195
2196        struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
2197        loader_platform_dl_handle lib_handle;
2198
2199        nextGpuObj = (wrappedGpus + i);
2200        nextGpuObj->pGPA = nextGPA;
2201        nextGpuObj->baseObject = baseObj;
2202        nextGpuObj->nextObject = nextObj;
2203        nextObj = (VkObject) nextGpuObj;
2204
2205        char funcStr[256];
2206        snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2207        lib_handle = loader_add_layer_lib("device", layer_prop);
2208        if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2209            nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2210        if (!nextGPA) {
2211            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName);
2212            continue;
2213        }
2214
2215        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
2216                   "Insert device layer library %s (%s)",
2217                   layer_prop->info.layerName,
2218                   layer_prop->lib_info.lib_name);
2219
2220    }
2221
2222    loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2223            (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
2224    free(wrappedGpus);
2225
2226    return dev->activated_layer_list.count;
2227}
2228
2229VkResult loader_validate_layers(
2230        const uint32_t                  layer_count,
2231        const char * const             *ppEnabledLayerNames,
2232        struct loader_layer_list       *list)
2233{
2234    struct loader_layer_properties *prop;
2235
2236    for (uint32_t i = 0; i < layer_count; i++) {
2237        prop = get_layer_property(ppEnabledLayerNames[i],
2238                                  list);
2239        if (!prop) {
2240            return VK_ERROR_INVALID_LAYER;
2241        }
2242    }
2243
2244    return VK_SUCCESS;
2245}
2246
2247VkResult loader_validate_instance_extensions(
2248        const VkInstanceCreateInfo     *pCreateInfo)
2249{
2250    struct loader_extension_property *extension_prop;
2251    struct loader_layer_properties *layer_prop;
2252
2253    for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2254        extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2255                                                &loader.global_extensions);
2256
2257        if (extension_prop) {
2258            continue;
2259        }
2260
2261        extension_prop = NULL;
2262
2263        /* Not in global list, search layer extension lists */
2264        for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2265            layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
2266                                  &loader.global_layer_list);
2267
2268            if (!layer_prop) {
2269                /* Should NOT get here, loader_validate_layers
2270                 * should have already filtered this case out.
2271                 */
2272                continue;
2273            }
2274
2275            extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2276                                          &layer_prop->instance_extension_list);
2277            if (extension_prop) {
2278                /* Found the extension in one of the layers enabled by the app. */
2279                break;
2280            }
2281        }
2282
2283        if (!extension_prop) {
2284            /* Didn't find extension name in any of the global layers, error out */
2285            return VK_ERROR_INVALID_EXTENSION;
2286        }
2287    }
2288    return VK_SUCCESS;
2289}
2290
2291VkResult loader_validate_device_extensions(
2292        struct loader_icd              *icd,
2293        const VkDeviceCreateInfo       *pCreateInfo)
2294{
2295    struct loader_extension_property *extension_prop;
2296    struct loader_layer_properties *layer_prop;
2297
2298    for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2299        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2300        extension_prop = get_extension_property(extension_name,
2301                                                &loader.global_extensions);
2302
2303        if (extension_prop) {
2304            continue;
2305        }
2306
2307        /* Not in global list, search layer extension lists */
2308        for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2309            const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
2310            layer_prop = get_layer_property(layer_name,
2311                                  &icd->layer_properties_cache);
2312
2313            if (!layer_prop) {
2314                /* Should NOT get here, loader_validate_instance_layers
2315                 * should have already filtered this case out.
2316                 */
2317                continue;
2318            }
2319
2320            extension_prop = get_extension_property(extension_name,
2321                                          &layer_prop->device_extension_list);
2322            if (extension_prop) {
2323                /* Found the extension in one of the layers enabled by the app. */
2324                break;
2325            }
2326        }
2327
2328        if (!extension_prop) {
2329            /* Didn't find extension name in any of the device layers, error out */
2330            return VK_ERROR_INVALID_EXTENSION;
2331        }
2332    }
2333    return VK_SUCCESS;
2334}
2335
2336VkResult loader_CreateInstance(
2337        const VkInstanceCreateInfo*     pCreateInfo,
2338        VkInstance*                     pInstance)
2339{
2340    struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
2341    struct loader_scanned_icds *scanned_icds;
2342    struct loader_icd *icd;
2343    struct loader_extension_property *prop;
2344    char **filtered_extension_names = NULL;
2345    VkInstanceCreateInfo icd_create_info;
2346    VkResult res = VK_SUCCESS;
2347
2348    icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2349    icd_create_info.layerCount = 0;
2350    icd_create_info.ppEnabledLayerNames = NULL;
2351    icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2352    icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2353    icd_create_info.pNext = pCreateInfo->pNext;
2354
2355    /*
2356     * NOTE: Need to filter the extensions to only those
2357     * supported by the ICD.
2358     * No ICD will advertise support for layers. An ICD
2359     * library could support a layer, but it would be
2360     * independent of the actual ICD, just in the same library.
2361     */
2362    filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2363    if (!filtered_extension_names) {
2364        return VK_ERROR_OUT_OF_HOST_MEMORY;
2365    }
2366    icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2367
2368    scanned_icds = loader.scanned_icd_list;
2369    while (scanned_icds) {
2370        icd = loader_icd_add(ptr_instance, scanned_icds);
2371        if (icd) {
2372
2373            icd_create_info.extensionCount = 0;
2374            for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2375                prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2376                                              &scanned_icds->global_extension_list);
2377                if (prop) {
2378                    filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2379                    icd_create_info.extensionCount++;
2380                }
2381            }
2382
2383            res = scanned_icds->CreateInstance(&icd_create_info,
2384                                           &(icd->instance));
2385            if (res != VK_SUCCESS)
2386            {
2387                ptr_instance->icds = ptr_instance->icds->next;
2388                loader_icd_destroy(ptr_instance, icd);
2389                icd->instance = VK_NULL_HANDLE;
2390                loader_log(VK_DBG_REPORT_WARN_BIT, 0,
2391                        "ICD ignored: failed to CreateInstance on device");
2392            } else
2393            {
2394                loader_icd_init_entrys(icd, scanned_icds);
2395            }
2396        }
2397        scanned_icds = scanned_icds->next;
2398    }
2399
2400    /*
2401     * If no ICDs were added to instance list and res is unchanged
2402     * from it's initial value, the loader was unable to find
2403     * a suitable ICD.
2404     */
2405    if (ptr_instance->icds == NULL) {
2406        if (res == VK_SUCCESS) {
2407            return VK_ERROR_INCOMPATIBLE_DRIVER;
2408        } else {
2409            return res;
2410        }
2411    }
2412
2413    return VK_SUCCESS;
2414}
2415
2416VkResult loader_DestroyInstance(
2417        VkInstance                                instance)
2418{
2419    struct loader_instance *ptr_instance = loader_instance(instance);
2420    struct loader_icd *icds = ptr_instance->icds;
2421    struct loader_icd *next_icd;
2422    VkResult res;
2423
2424    // Remove this instance from the list of instances:
2425    struct loader_instance *prev = NULL;
2426    struct loader_instance *next = loader.instances;
2427    while (next != NULL) {
2428        if (next == ptr_instance) {
2429            // Remove this instance from the list:
2430            if (prev)
2431                prev->next = next->next;
2432            else
2433                loader.instances = next->next;
2434            break;
2435        }
2436        prev = next;
2437        next = next->next;
2438    }
2439    if (next  == NULL) {
2440        // This must be an invalid instance handle or empty list
2441        return VK_ERROR_INVALID_HANDLE;
2442    }
2443
2444    while (icds) {
2445        if (icds->instance) {
2446            res = icds->DestroyInstance(icds->instance);
2447            if (res != VK_SUCCESS)
2448                loader_log(VK_DBG_REPORT_WARN_BIT, 0,
2449                            "ICD ignored: failed to DestroyInstance on device");
2450        }
2451        next_icd = icds->next;
2452        icds->instance = VK_NULL_HANDLE;
2453        loader_icd_destroy(ptr_instance, icds);
2454
2455        icds = next_icd;
2456    }
2457
2458
2459    return VK_SUCCESS;
2460}
2461
2462VkResult loader_init_physical_device_info(
2463        struct loader_instance *ptr_instance)
2464{
2465    struct loader_icd *icd;
2466    uint32_t n, count = 0;
2467    VkResult res = VK_ERROR_UNKNOWN;
2468
2469    icd = ptr_instance->icds;
2470    while (icd) {
2471        res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2472        if (res != VK_SUCCESS)
2473            return res;
2474        icd->gpu_count = n;
2475        count += n;
2476        icd = icd->next;
2477    }
2478
2479    ptr_instance->total_gpu_count = count;
2480
2481    icd = ptr_instance->icds;
2482    while (icd) {
2483
2484        n = icd->gpu_count;
2485        icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2486        if (!icd->gpus) {
2487            /* TODO: Add cleanup code here */
2488            return VK_ERROR_OUT_OF_HOST_MEMORY;
2489        }
2490        res = icd->EnumeratePhysicalDevices(
2491                                        icd->instance,
2492                                        &n,
2493                                        icd->gpus);
2494        if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
2495
2496            for (unsigned int i = 0; i < n; i++) {
2497
2498                loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
2499
2500                if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2501                    /* TODO: Add cleanup code here */
2502                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
2503                }
2504                if (res == VK_SUCCESS) {
2505
2506                    loader_add_physical_device_extensions(
2507                                icd->GetPhysicalDeviceExtensionProperties,
2508                                icd->gpus[0],
2509                                VK_EXTENSION_ORIGIN_ICD,
2510                                icd->scanned_icds->lib_name,
2511                                &icd->device_extension_cache[i]);
2512
2513                    for (uint32_t l = 0; l < loader.scanned_layer_libraries.count; l++) {
2514                        loader_platform_dl_handle lib_handle;
2515                        char *lib_name = loader.scanned_layer_libraries.list[l].lib_name;
2516
2517                        lib_handle = loader_platform_open_library(lib_name);
2518                        if (lib_handle == NULL) {
2519                            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2520                            continue;
2521                        }
2522                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2523                                   "library: %s", lib_name);
2524
2525                        loader_add_physical_device_layer_properties(
2526                                    icd, lib_name, lib_handle);
2527
2528                        loader_platform_close_library(lib_handle);
2529                    }
2530                }
2531
2532                if (res != VK_SUCCESS) {
2533                    /* clean up any extension lists previously created before this request failed */
2534                    for (uint32_t j = 0; j < i; j++) {
2535                        loader_destroy_ext_list(&icd->device_extension_cache[i]);
2536                    }
2537
2538                    loader_destroy_layer_list(&icd->layer_properties_cache);
2539                    return res;
2540                }
2541            }
2542
2543            count += n;
2544        }
2545
2546        icd = icd->next;
2547    }
2548
2549    return VK_SUCCESS;
2550}
2551
2552VkResult loader_EnumeratePhysicalDevices(
2553        VkInstance                              instance,
2554        uint32_t*                               pPhysicalDeviceCount,
2555        VkPhysicalDevice*                       pPhysicalDevices)
2556{
2557    uint32_t index = 0;
2558    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2559    struct loader_icd *icd = ptr_instance->icds;
2560
2561    if (ptr_instance->total_gpu_count == 0) {
2562        loader_init_physical_device_info(ptr_instance);
2563    }
2564
2565    *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2566    if (!pPhysicalDevices) {
2567        return VK_SUCCESS;
2568    }
2569
2570    while (icd) {
2571        assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
2572        memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
2573        index += icd->gpu_count;
2574        icd = icd->next;
2575    }
2576
2577    return VK_SUCCESS;
2578}
2579
2580VkResult loader_GetPhysicalDeviceProperties(
2581        VkPhysicalDevice                        gpu,
2582        VkPhysicalDeviceProperties*             pProperties)
2583{
2584    uint32_t gpu_index;
2585    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2586    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2587
2588    if (icd->GetPhysicalDeviceProperties)
2589        res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2590
2591    return res;
2592}
2593
2594VkResult loader_GetPhysicalDevicePerformance(
2595        VkPhysicalDevice                        gpu,
2596        VkPhysicalDevicePerformance*            pPerformance)
2597{
2598    uint32_t gpu_index;
2599    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2600    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2601
2602    if (icd->GetPhysicalDevicePerformance)
2603        res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2604
2605    return res;
2606}
2607
2608VkResult loader_GetPhysicalDeviceQueueCount(
2609        VkPhysicalDevice                        gpu,
2610        uint32_t*                               pCount)
2611{
2612    uint32_t gpu_index;
2613    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2614    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2615
2616    if (icd->GetPhysicalDeviceQueueCount)
2617        res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2618
2619    return res;
2620}
2621
2622VkResult loader_GetPhysicalDeviceQueueProperties (
2623        VkPhysicalDevice gpu,
2624        uint32_t count,
2625        VkPhysicalDeviceQueueProperties * pProperties)
2626{
2627    uint32_t gpu_index;
2628    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2629    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2630
2631    if (icd->GetPhysicalDeviceQueueProperties)
2632        res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2633
2634    return res;
2635}
2636
2637VkResult loader_GetPhysicalDeviceMemoryProperties (
2638        VkPhysicalDevice gpu,
2639        VkPhysicalDeviceMemoryProperties* pProperties)
2640{
2641    uint32_t gpu_index;
2642    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2643    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2644
2645    if (icd->GetPhysicalDeviceMemoryProperties)
2646        res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
2647
2648    return res;
2649}
2650
2651VkResult loader_GetPhysicalDeviceFeatures(
2652        VkPhysicalDevice                        physicalDevice,
2653        VkPhysicalDeviceFeatures*               pFeatures)
2654{
2655    uint32_t gpu_index;
2656    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2657    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2658
2659    if (icd->GetPhysicalDeviceFeatures)
2660        res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2661
2662    return res;
2663}
2664
2665VkResult loader_GetPhysicalDeviceFormatInfo(
2666        VkPhysicalDevice                        physicalDevice,
2667        VkFormat                                format,
2668        VkFormatProperties*                     pFormatInfo)
2669{
2670    uint32_t gpu_index;
2671    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2672    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2673
2674    if (icd->GetPhysicalDeviceFormatInfo)
2675        res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2676
2677    return res;
2678}
2679
2680VkResult loader_GetPhysicalDeviceLimits(
2681        VkPhysicalDevice                        physicalDevice,
2682        VkPhysicalDeviceLimits*                 pLimits)
2683{
2684    uint32_t gpu_index;
2685    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2686    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2687
2688    if (icd->GetPhysicalDeviceLimits)
2689        res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2690
2691    return res;
2692}
2693
2694VkResult loader_CreateDevice(
2695        VkPhysicalDevice                        gpu,
2696        const VkDeviceCreateInfo*               pCreateInfo,
2697        VkDevice*                               pDevice)
2698{
2699    uint32_t gpu_index;
2700    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2701    struct loader_device *dev;
2702    VkDeviceCreateInfo device_create_info;
2703    char **filtered_extension_names = NULL;
2704    VkResult res;
2705
2706    if (!icd->CreateDevice) {
2707        return VK_ERROR_INITIALIZATION_FAILED;
2708    }
2709
2710    /*
2711     * TODO: Must filter CreateInfo extension list to only
2712     * those extensions supported by the ICD.
2713     * TODO: Probably should verify that every extension is
2714     * covered by either the ICD or some layer.
2715     */
2716    res = loader_validate_layers(pCreateInfo->layerCount,
2717                           pCreateInfo->ppEnabledLayerNames,
2718                           &icd->layer_properties_cache);
2719    if (res != VK_SUCCESS) {
2720        return res;
2721    }
2722
2723    res = loader_validate_device_extensions(icd, pCreateInfo);
2724    if (res != VK_SUCCESS) {
2725        return res;
2726    }
2727
2728    /*
2729     * NOTE: Need to filter the extensions to only those
2730     * supported by the ICD.
2731     * No ICD will advertise support for layers. An ICD
2732     * library could support a layer, but it would be
2733     * independent of the actual ICD, just in the same library.
2734     */
2735    filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2736    if (!filtered_extension_names) {
2737        return VK_ERROR_OUT_OF_HOST_MEMORY;
2738    }
2739
2740    /* Copy user's data */
2741    memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2742
2743    /* ICD's do not use layers */
2744    device_create_info.layerCount = 0;
2745    device_create_info.ppEnabledLayerNames = NULL;
2746
2747    device_create_info.extensionCount = 0;
2748    device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2749
2750    for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2751        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2752        struct loader_extension_property *prop = get_extension_property(extension_name,
2753                                      &icd->device_extension_cache[gpu_index]);
2754        if (prop) {
2755            filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2756            device_create_info.extensionCount++;
2757        }
2758    }
2759
2760    res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2761    if (res != VK_SUCCESS) {
2762        return res;
2763    }
2764
2765    dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2766    if (dev == NULL) {
2767        return VK_ERROR_OUT_OF_HOST_MEMORY;
2768    }
2769    PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2770    loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2771                                      icd->gpus[gpu_index], icd->gpus[gpu_index]);
2772
2773    dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2774    loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2775
2776    /*
2777     * Put together the complete list of extensions to enable
2778     * This includes extensions requested via environment variables.
2779     */
2780    loader_enable_device_layers(icd, dev, pCreateInfo);
2781
2782    /*
2783     * Load the libraries and build the device chain
2784     * terminating with the selected device.
2785     */
2786    loader_activate_device_layers(icd, dev, *pDevice);
2787
2788    res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2789
2790    dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2791
2792    return res;
2793}
2794
2795static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
2796{
2797    if (instance == VK_NULL_HANDLE)
2798        return NULL;
2799
2800    void *addr;
2801    /* get entrypoint addresses that are global (in the loader)*/
2802    addr = globalGetProcAddr(pName);
2803    if (addr)
2804        return addr;
2805
2806    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2807
2808    /* return any extension global entrypoints */
2809    addr = debug_report_instance_gpa(ptr_instance, pName);
2810    if (addr) {
2811        return addr;
2812    }
2813
2814    /* TODO Remove this once WSI has no loader special code */
2815    addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
2816    if (addr) {
2817        return addr;
2818    }
2819
2820    /* return the instance dispatch table entrypoint for extensions */
2821    const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2822    if (disp_table == NULL)
2823        return NULL;
2824
2825    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2826    if (addr)
2827        return addr;
2828
2829    return NULL;
2830}
2831
2832LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2833{
2834    return loader_GetInstanceProcAddr(instance, pName);
2835}
2836
2837static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
2838{
2839    if (device == VK_NULL_HANDLE) {
2840        return NULL;
2841    }
2842
2843    void *addr;
2844
2845    /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2846       make sure the loader entrypoint is returned */
2847    addr = loader_non_passthrough_gpa(pName);
2848    if (addr) {
2849        return addr;
2850    }
2851
2852    /* return any extension device entrypoints the loader knows about */
2853    /* TODO once WSI has no loader special code remove this */
2854    addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
2855    if (addr) {
2856        return addr;
2857    }
2858
2859    /* return the dispatch table entrypoint for the fastest case */
2860    const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
2861    if (disp_table == NULL)
2862        return NULL;
2863
2864    addr = loader_lookup_device_dispatch_table(disp_table, pName);
2865    if (addr)
2866        return addr;
2867    else  {
2868        if (disp_table->GetDeviceProcAddr == NULL)
2869            return NULL;
2870        return disp_table->GetDeviceProcAddr(device, pName);
2871    }
2872}
2873
2874LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2875{
2876    return loader_GetDeviceProcAddr(device, pName);
2877}
2878
2879LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
2880    const char*                                 pLayerName,
2881    uint32_t*                                   pCount,
2882    VkExtensionProperties*                      pProperties)
2883{
2884    struct loader_extension_list *global_extension_list;
2885
2886    /* Scan/discover all ICD libraries in a single-threaded manner */
2887    loader_platform_thread_once(&once_icd, loader_icd_scan);
2888
2889    /* get layer libraries in a single-threaded manner */
2890    loader_platform_thread_once(&once_layer, loader_layer_scan);
2891
2892    /* merge any duplicate extensions */
2893    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2894
2895    uint32_t copy_size;
2896
2897    if (pCount == NULL) {
2898        return VK_ERROR_INVALID_POINTER;
2899    }
2900
2901    loader_platform_thread_lock_mutex(&loader_lock);
2902
2903    global_extension_list = loader_global_extensions(pLayerName);
2904    if (global_extension_list == NULL) {
2905        loader_platform_thread_unlock_mutex(&loader_lock);
2906        return VK_ERROR_INVALID_LAYER;
2907    }
2908
2909    if (pProperties == NULL) {
2910        *pCount = global_extension_list->count;
2911        loader_platform_thread_unlock_mutex(&loader_lock);
2912        return VK_SUCCESS;
2913    }
2914
2915    copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2916    for (uint32_t i = 0; i < copy_size; i++) {
2917        memcpy(&pProperties[i],
2918               &global_extension_list->list[i].info,
2919               sizeof(VkExtensionProperties));
2920    }
2921    *pCount = copy_size;
2922
2923    loader_platform_thread_unlock_mutex(&loader_lock);
2924
2925    if (copy_size < global_extension_list->count) {
2926        return VK_INCOMPLETE;
2927    }
2928
2929    return VK_SUCCESS;
2930}
2931
2932LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2933    uint32_t*                                   pCount,
2934    VkLayerProperties*                          pProperties)
2935{
2936
2937    /* Scan/discover all ICD libraries in a single-threaded manner */
2938    loader_platform_thread_once(&once_icd, loader_icd_scan);
2939
2940    /* get layer libraries in a single-threaded manner */
2941    loader_platform_thread_once(&once_layer, loader_layer_scan);
2942
2943    /* merge any duplicate extensions */
2944    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2945
2946    uint32_t copy_size;
2947
2948    if (pCount == NULL) {
2949        return VK_ERROR_INVALID_POINTER;
2950    }
2951
2952    /* TODO: do we still need to lock */
2953    loader_platform_thread_lock_mutex(&loader_lock);
2954
2955    struct loader_layer_list *layer_list;
2956    layer_list = loader_global_layers();
2957
2958    if (pProperties == NULL) {
2959        *pCount = layer_list->count;
2960        loader_platform_thread_unlock_mutex(&loader_lock);
2961        return VK_SUCCESS;
2962    }
2963
2964    copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
2965    for (uint32_t i = 0; i < copy_size; i++) {
2966        memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
2967    }
2968    *pCount = copy_size;
2969
2970    loader_platform_thread_unlock_mutex(&loader_lock);
2971
2972    if (copy_size < layer_list->count) {
2973        return VK_INCOMPLETE;
2974    }
2975
2976    return VK_SUCCESS;
2977}
2978
2979VkResult loader_GetPhysicalDeviceExtensionProperties(
2980        VkPhysicalDevice                        gpu,
2981        const char*                             pLayerName,
2982        uint32_t*                               pCount,
2983        VkExtensionProperties*                  pProperties)
2984{
2985    uint32_t gpu_index;
2986    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2987    uint32_t copy_size;
2988
2989    if (pCount == NULL) {
2990        return VK_ERROR_INVALID_POINTER;
2991    }
2992
2993    uint32_t count;
2994    struct loader_extension_list *list;
2995    loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
2996
2997    if (pProperties == NULL) {
2998        *pCount = count;
2999        return VK_SUCCESS;
3000    }
3001
3002    copy_size = *pCount < count ? *pCount : count;
3003    for (uint32_t i = 0; i < copy_size; i++) {
3004        memcpy(&pProperties[i],
3005               &list->list[i].info,
3006               sizeof(VkExtensionProperties));
3007    }
3008    *pCount = copy_size;
3009
3010    if (copy_size < count) {
3011        return VK_INCOMPLETE;
3012    }
3013
3014    return VK_SUCCESS;
3015}
3016
3017VkResult loader_GetPhysicalDeviceLayerProperties(
3018        VkPhysicalDevice                        gpu,
3019        uint32_t*                               pCount,
3020        VkLayerProperties*                      pProperties)
3021{
3022    uint32_t gpu_index;
3023    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
3024    uint32_t copy_size;
3025
3026    if (pCount == NULL) {
3027        return VK_ERROR_INVALID_POINTER;
3028    }
3029
3030    uint32_t count;
3031    struct loader_layer_list *layer_list;
3032    loader_physical_device_layers(icd, &count, &layer_list);
3033
3034    if (pProperties == NULL) {
3035        *pCount = count;
3036        return VK_SUCCESS;
3037    }
3038
3039    copy_size = *pCount < count ? *pCount : count;
3040    for (uint32_t i = 0; i < copy_size; i++) {
3041        memcpy(&pProperties[i],
3042               &layer_list->list[i].info,
3043               sizeof(VkLayerProperties));
3044    }
3045    *pCount = copy_size;
3046
3047    if (copy_size < count) {
3048        return VK_INCOMPLETE;
3049    }
3050
3051    return VK_SUCCESS;
3052}
3053