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