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