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