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