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