loader.c revision 535bd00968e86ef2c32495566b7b61400c2aad7d
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_extension_property *ext_prop);
60
61static void loader_remove_layer_lib(
62        struct loader_instance *inst,
63        struct loader_extension_property *ext_prop);
64
65struct loader_struct loader = {0};
66
67static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
68
69enum loader_debug {
70    LOADER_INFO_BIT       = VK_BIT(0),
71    LOADER_WARN_BIT       = VK_BIT(1),
72    LOADER_PERF_BIT       = VK_BIT(2),
73    LOADER_ERROR_BIT      = VK_BIT(3),
74    LOADER_DEBUG_BIT      = VK_BIT(4),
75};
76
77uint32_t g_loader_debug = 0;
78uint32_t g_loader_log_msgs = 0;
79
80//thread safety lock for accessing global data structures such as "loader"
81// all entrypoints on the instance chain need to be locked except GPA
82// additionally CreateDevice and DestroyDevice needs to be locked
83loader_platform_thread_mutex loader_lock;
84
85const VkLayerInstanceDispatchTable instance_disp = {
86    .GetInstanceProcAddr = loader_GetInstanceProcAddr,
87    .CreateInstance = loader_CreateInstance,
88    .DestroyInstance = loader_DestroyInstance,
89    .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
90    .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
91    .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo,
92    .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
93    .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
94    .GetPhysicalDevicePerformance = loader_GetPhysicalDevicePerformance,
95    .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
96    .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
97    .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
98    .GetPhysicalDeviceExtensionCount = loader_GetPhysicalDeviceExtensionCount,
99    .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
100    .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
101    .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
102};
103
104LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
105LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
107
108static void loader_log(VkFlags msg_type, int32_t msg_code,
109    const char *format, ...)
110{
111    char msg[256];
112    va_list ap;
113    int ret;
114
115    if (!(msg_type & g_loader_log_msgs)) {
116        return;
117    }
118
119    va_start(ap, format);
120    ret = vsnprintf(msg, sizeof(msg), format, ap);
121    if ((ret >= (int) sizeof(msg)) || ret < 0) {
122        msg[sizeof(msg)-1] = '\0';
123    }
124    va_end(ap);
125
126#if defined(WIN32)
127    OutputDebugString(msg);
128#endif
129    fputs(msg, stderr);
130    fputc('\n', stderr);
131}
132
133#if defined(WIN32)
134/**
135* Find the list of registry files (names within a key) in key "location".
136*
137* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
138* for a list or name/values which are added to a returned list (function return value).
139* The DWORD values within the key must be 0 or they are skipped.
140* Function return is a string with a ';'  seperated list of filenames.
141* Function return is NULL if no valid name/value pairs  are found in the key,
142* or the key is not found.
143*
144* \returns
145* A string list of filenames as pointer.
146* When done using the returned string list, pointer should be freed.
147*/
148static char *loader_get_registry_files(const char *location)
149{
150    LONG rtn_value;
151    HKEY hive, key;
152    DWORD access_flags = KEY_QUERY_VALUE;
153    char name[2048];
154    char *out = NULL;
155
156    hive = DEFAULT_VK_REGISTRY_HIVE;
157    rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
158    if (rtn_value != ERROR_SUCCESS) {
159        // We didn't find the key.  Try the 32-bit hive (where we've seen the
160        // key end up on some people's systems):
161        access_flags |= KEY_WOW64_32KEY;
162        rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
163        if (rtn_value != ERROR_SUCCESS) {
164            // We still couldn't find the key, so give up:
165            return NULL;
166        }
167    }
168
169    DWORD idx = 0;
170    DWORD name_size = sizeof(name);
171    DWORD value;
172    DWORD total_size = 4096;
173    DWORD value_size = sizeof(value);
174    while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
175        if (value_size == sizeof(value) && value == 0) {
176            if (out == NULL) {
177                out = malloc(total_size);
178                out[0] = '\0';
179            }
180            else if (strlen(out) + name_size + 1 > total_size) {
181                out = realloc(out, total_size * 2);
182                total_size *= 2;
183            }
184            if (out == NULL) {
185                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
186                return NULL;
187            }
188            if (strlen(out) == 0)
189                snprintf(out, name_size + 1, "%s", name);
190            else
191                snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
192        }
193    }
194    return out;
195}
196
197char *loader_get_registry_string(const HKEY hive,
198                                 const LPCTSTR sub_key,
199                                 const char *value)
200{
201    DWORD access_flags = KEY_QUERY_VALUE;
202    DWORD value_type;
203    HKEY key;
204    LONG rtn_value;
205    char *rtn_str = NULL;
206    DWORD rtn_len = 0;
207    size_t allocated_len = 0;
208
209    rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
210    if (rtn_value != ERROR_SUCCESS) {
211        // We didn't find the key.  Try the 32-bit hive (where we've seen the
212        // key end up on some people's systems):
213        access_flags |= KEY_WOW64_32KEY;
214        rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
215        if (rtn_value != ERROR_SUCCESS) {
216            // We still couldn't find the key, so give up:
217            return NULL;
218        }
219    }
220
221    rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
222                                (PVOID) rtn_str, (LPDWORD) &rtn_len);
223    if (rtn_value == ERROR_SUCCESS) {
224        // If we get to here, we found the key, and need to allocate memory
225        // large enough for rtn_str, and query again:
226        allocated_len = rtn_len + 4;
227        rtn_str = malloc(allocated_len);
228        rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
229                                    (PVOID) rtn_str, (LPDWORD) &rtn_len);
230        if (rtn_value == ERROR_SUCCESS) {
231            // We added 4 extra bytes to rtn_str, so that we can ensure that
232            // the string is NULL-terminated (albeit, in a brute-force manner):
233            rtn_str[allocated_len-1] = '\0';
234        } else {
235            // This should never occur, but in case it does, clean up:
236            free(rtn_str);
237            rtn_str = NULL;
238        }
239    } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
240
241    // Close the registry key that was opened:
242    RegCloseKey(key);
243
244    return rtn_str;
245}
246
247
248// For ICD developers, look in the registry, and look for an environment
249// variable for a path(s) where to find the ICD(s):
250static char *loader_get_registry_and_env(const char *env_var,
251                                         const char *registry_value)
252{
253    char *env_str = getenv(env_var);
254    size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
255    char *registry_str = NULL;
256    size_t registry_len = 0;
257    char *rtn_str = NULL;
258    size_t rtn_len;
259
260    registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
261                                              "Software\\Vulkan",
262                                              registry_value);
263    registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
264
265    rtn_len = env_len + registry_len + 1;
266    if (rtn_len <= 2) {
267        // We found neither the desired registry value, nor the environment
268        // variable; return NULL:
269        return NULL;
270    } else {
271        // We found something, and so we need to allocate memory for the string
272        // to return:
273        rtn_str = malloc(rtn_len);
274    }
275
276    if (registry_len == 0) {
277        // We didn't find the desired registry value, and so we must have found
278        // only the environment variable:
279        _snprintf(rtn_str, rtn_len, "%s", env_str);
280    } else if (env_str != NULL) {
281        // We found both the desired registry value and the environment
282        // variable, so concatenate them both:
283        _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
284    } else {
285        // We must have only found the desired registry value:
286        _snprintf(rtn_str, rtn_len, "%s", registry_str);
287    }
288
289    if (registry_str) {
290      free(registry_str);
291    }
292
293    return(rtn_str);
294}
295#endif // WIN32
296
297bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
298{
299    return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
300}
301
302/*
303 * Search the given ext_array for an extension
304 * matching the given vk_ext_prop
305 */
306bool has_vk_extension_property_array(
307        const VkExtensionProperties *vk_ext_prop,
308        const uint32_t count,
309        const VkExtensionProperties *ext_array)
310{
311    for (uint32_t i = 0; i < count; i++) {
312        if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
313            return true;
314    }
315    return false;
316}
317
318/*
319 * Search the given ext_list for an extension
320 * matching the given vk_ext_prop
321 */
322bool has_vk_extension_property(
323        const VkExtensionProperties *vk_ext_prop,
324        const struct loader_extension_list *ext_list)
325{
326    for (uint32_t i = 0; i < ext_list->count; i++) {
327        if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
328            return true;
329    }
330    return false;
331}
332
333/*
334 * Search the given ext_list for an extension
335 * matching the given vk_ext_prop
336 */
337static struct loader_extension_property *get_extension_property_from_vkext(
338        const VkExtensionProperties *vk_ext_prop,
339        const struct loader_extension_list *ext_list)
340{
341    for (uint32_t i = 0; i < ext_list->count; i++) {
342        const VkExtensionProperties *item = &ext_list->list[i].info;
343        if (compare_vk_extension_properties(item, vk_ext_prop))
344            return &ext_list->list[i];
345    }
346    return NULL;
347}
348
349static void loader_get_global_extensions(
350        const PFN_vkGetGlobalExtensionCount fp_get_count,
351        const PFN_vkGetGlobalExtensionProperties fp_get_props,
352        const PFN_vkGPA get_proc_addr,
353        const char *lib_name,
354        const loader_platform_dl_handle lib_handle,
355        const enum extension_origin origin,
356        struct loader_extension_list *ext_list)
357{
358    uint32_t i, count;
359    struct loader_extension_property ext_props;
360    VkResult res;
361    PFN_vkGPA ext_get_proc_addr;
362    PFN_vkGetInstanceProcAddr get_instance_proc_addr;
363
364    res = fp_get_count(&count);
365    if (res != VK_SUCCESS) {
366        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
367        return;
368    }
369
370    if (get_proc_addr == NULL)
371        get_instance_proc_addr = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
372
373    for (i = 0; i < count; i++) {
374        memset(&ext_props, 0, sizeof(ext_props));
375        res = fp_get_props(i, &ext_props.info);
376        if (res == VK_SUCCESS) {
377            //TODO eventually get this from the layer config file
378            if (get_proc_addr == NULL) {
379                char funcStr[MAX_EXTENSION_NAME_SIZE+1];
380                snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetInstanceProcAddr", ext_props.info.name);
381
382                if ((ext_get_proc_addr = (PFN_vkGPA) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
383                    ext_get_proc_addr = get_instance_proc_addr;
384            }
385            ext_props.origin = origin;
386            ext_props.lib_name = lib_name;
387            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
388                       "Global Extension: %s: %s", ext_props.info.name, ext_props.info.description);
389            ext_props.get_proc_addr = (get_proc_addr == NULL) ? ext_get_proc_addr : get_proc_addr;
390            loader_add_to_ext_list(ext_list, 1, &ext_props);
391        }
392    }
393
394    return;
395}
396
397static void loader_get_physical_device_layer_extensions(
398        struct loader_instance *ptr_instance,
399        VkPhysicalDevice physical_device,
400        const struct loader_layer_properties *layer_props,
401        struct loader_extension_list *ext_list)
402{
403    uint32_t i, count;
404    VkResult res;
405    loader_platform_dl_handle lib_handle;
406    PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props;
407    PFN_vkGetPhysicalDeviceExtensionCount get_phys_dev_ext_count;
408    struct loader_extension_property ext_props;
409    PFN_vkGPA ext_get_proc_addr;
410    PFN_vkGetDeviceProcAddr get_device_proc_addr;
411
412    if (layer_props->device_extension_list.count == 0) {
413        return;
414    }
415
416    ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
417    ext_props.lib_name = layer_props->lib_info.lib_name;
418    char funcStr[MAX_EXTENSION_NAME_SIZE+1];  // add one character for 0 termination
419
420    lib_handle = loader_add_layer_lib("device", &ext_props);
421
422    get_phys_dev_ext_props = (PFN_vkGetPhysicalDeviceExtensionProperties) loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
423    get_phys_dev_ext_count = (PFN_vkGetPhysicalDeviceExtensionCount) loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionCount");
424    get_device_proc_addr = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
425    if (get_phys_dev_ext_count) {
426        res = get_phys_dev_ext_count(physical_device, &count);
427        if (res == VK_SUCCESS) {
428            for (i = 0; i < count; i++) {
429                memset(&ext_props, 0, sizeof(ext_props));
430                res = get_phys_dev_ext_props(physical_device, i, &ext_props.info);
431                if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
432                    ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
433                    //TODO eventually get this from the layer config file
434                    snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetDeviceProcAddr", ext_props.info.name);
435
436                    if ((ext_get_proc_addr = (PFN_vkGPA) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
437                        ext_get_proc_addr = get_device_proc_addr;
438                    ext_props.get_proc_addr = ext_get_proc_addr;
439                    ext_props.lib_name = layer_props->lib_info.lib_name;
440                    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
441                               "PhysicalDevice Extension: %s: %s", ext_props.info.name, ext_props.info.description);
442                    loader_add_to_ext_list(ext_list, 1, &ext_props);
443                }
444            }
445        } else {
446            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
447        }
448    }
449
450    loader_remove_layer_lib(ptr_instance, &ext_props);
451    return;
452}
453
454static bool loader_init_ext_list(struct loader_extension_list *ext_info)
455{
456    ext_info->capacity = 32 * sizeof(struct loader_extension_property);
457    ext_info->list = malloc(ext_info->capacity);
458    if (ext_info->list == NULL) {
459        return false;
460    }
461    memset(ext_info->list, 0, ext_info->capacity);
462    ext_info->count = 0;
463    return true;
464}
465
466void loader_destroy_ext_list(struct loader_extension_list *ext_info)
467{
468    free(ext_info->list);
469    ext_info->count = 0;
470    ext_info->capacity = 0;
471}
472
473/**
474 * Search the given search_list for an any layer extensions in the props list.
475 * Add these to the output ext_list.  Don't add duplicates to the output ext_list.
476 * Search is limited to extensions having the origin of layer libraries.
477 * Appending to output list handles  layer aliases
478 */
479static void loader_add_layer_ext_to_ext_list(
480        struct loader_extension_list *out_ext_list,
481        uint32_t prop_list_count,
482        const VkExtensionProperties *props,
483        const struct loader_extension_list *search_list)
484{
485    struct loader_extension_property *ext_prop;
486
487    for (uint32_t i = 0; i < prop_list_count; i++) {
488        const VkExtensionProperties *search_target = &props[i];
489        // look for duplicates
490        if (has_vk_extension_property(search_target, out_ext_list)) {
491            continue;
492        }
493
494        ext_prop = get_extension_property_from_vkext(search_target, search_list);
495        if (!ext_prop) {
496            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", search_target->name);
497            continue;
498        }
499
500        if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER)
501            continue;
502        if (ext_prop->alias)
503            ext_prop = ext_prop->alias;
504        loader_add_to_ext_list(out_ext_list, 1, ext_prop);
505    }
506}
507
508/*
509 * Append non-duplicate extension properties defined in prop_list
510 * to the given ext_info list
511 */
512void loader_add_to_ext_list(
513        struct loader_extension_list *ext_list,
514        uint32_t prop_list_count,
515        const struct loader_extension_property *props)
516{
517    uint32_t i;
518    struct loader_extension_property *cur_ext;
519
520    if (ext_list->list == NULL || ext_list->capacity == 0) {
521        loader_init_ext_list(ext_list);
522    }
523
524    if (ext_list->list == NULL)
525        return;
526
527    for (i = 0; i < prop_list_count; i++) {
528        cur_ext = (struct loader_extension_property *) &props[i];
529
530        // look for duplicates
531        if (has_vk_extension_property(&cur_ext->info, ext_list)) {
532            continue;
533        }
534
535        // add to list at end
536        // check for enough capacity
537        if (ext_list->count * sizeof(struct loader_extension_property)
538                        >= ext_list->capacity) {
539            // double capacity
540            ext_list->capacity *= 2;
541            ext_list->list = realloc(ext_list->list, ext_list->capacity);
542        }
543
544        /*
545         * Check if any extensions already on the list come from the same
546         * library and use the same Get*ProcAddr. If so, link this
547         * extension to the previous as an alias. That way when we activate
548         * extensions we only activiate the associated layer once no
549         * matter how many extensions are used.
550         */
551        for (uint32_t j = 0; j < ext_list->count; j++) {
552            struct loader_extension_property *active_property = &ext_list->list[j];
553            if (cur_ext->lib_name &&
554                cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
555                active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
556                strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
557                (cur_ext->get_proc_addr == active_property->get_proc_addr) &&
558                    active_property->alias == NULL) {
559                cur_ext->alias = active_property;
560                break;
561            }
562        }
563
564        memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
565        ext_list->count++;
566    }
567}
568
569/*
570 * Search the search_list for any extension with
571 * a name that matches the given ext_name.
572 * Add all matching extensions to the found_list
573 * Do not add if found VkExtensionProperties is already
574 * on the found_list.  Add the aliased layer if needed.
575 */
576static void loader_find_layer_name_add_list(
577        const char *name,
578        const struct loader_extension_list *search_list,
579        struct loader_extension_list *found_list)
580{
581    for (uint32_t i = 0; i < search_list->count; i++) {
582        struct loader_extension_property *ext_prop = &search_list->list[i];
583        if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER &&
584            0 == strcmp(ext_prop->info.name, name)) {
585            if (ext_prop->alias)
586                ext_prop = ext_prop->alias;
587            /* Found an extension with the same name, add to found_list */
588            loader_add_to_ext_list(found_list, 1, ext_prop);
589        }
590    }
591}
592
593bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
594{
595    uint32_t i;
596
597    for (i = 0; i < loader.global_extensions.count; i++) {
598        if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
599            return true;
600    }
601    return false;
602}
603
604/*
605 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
606 * the extension must provide two entry points for the loader to use:
607 * - "trampoline" entry point - this is the address returned by GetProcAddr
608 * and will always do what's necessary to support a global call.
609 * - "terminator" function - this function will be put at the end of the
610 * instance chain and will contain the necessary logica to call / process
611 * the extension for the appropriate ICDs that are available.
612 * There is no generic mechanism for including these functions, the references
613 * must be placed into the appropriate loader entry points.
614 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
615 * loader_coalesce_extensions(void) - add extension records to the list of global
616 * extension available to the app.
617 * instance_disp - add function pointer for terminator function to this array.
618 * The extension itself should be in a separate file that will be
619 * linked directly with the loader.
620 */
621void loader_coalesce_extensions(void)
622{
623    uint32_t i;
624    struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
625
626    // traverse scanned icd list adding non-duplicate extensions to the list
627    while (icd_list != NULL) {
628        loader_add_to_ext_list(&loader.global_extensions,
629                               icd_list->global_extension_list.count,
630                               icd_list->global_extension_list.list);
631        icd_list = icd_list->next;
632    };
633
634    //Traverse layers list adding non-duplicate extensions to the list
635    for (i = 0; i < loader.scanned_layers.count; i++) {
636        loader_add_to_ext_list(&loader.global_extensions,
637                               loader.scanned_layers.list[i].instance_extension_list.count,
638                               loader.scanned_layers.list[i].instance_extension_list.list);
639    }
640
641    // Traverse loader's extensions, adding non-duplicate extensions to the list
642    debug_report_add_instance_extensions(&loader.global_extensions);
643}
644
645static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
646                                                    struct loader_device **found_dev)
647{
648    *found_dev = NULL;
649    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
650        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
651            for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
652                if (dev->device == device) {
653                    *found_dev = dev;
654                    return icd;
655                }
656        }
657    }
658    return NULL;
659}
660
661static void loader_destroy_logical_device(struct loader_device *dev)
662{
663    free(dev->app_extension_props);
664    if (dev->activated_layer_list.count)
665        loader_destroy_ext_list(&dev->activated_layer_list);
666    free(dev);
667}
668
669static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
670{
671    struct loader_device *new_dev;
672
673    new_dev = malloc(sizeof(struct loader_device));
674    if (!new_dev) {
675        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
676        return NULL;
677    }
678
679    memset(new_dev, 0, sizeof(struct loader_device));
680
681    new_dev->next = *device_list;
682    new_dev->device = dev;
683    *device_list = new_dev;
684    return new_dev;
685}
686
687void loader_remove_logical_device(VkDevice device)
688{
689    struct loader_device *found_dev, *dev, *prev_dev;
690    struct loader_icd *icd;
691    icd = loader_get_icd_and_device(device, &found_dev);
692
693    if (!icd || !found_dev)
694        return;
695
696    prev_dev = NULL;
697    dev = icd->logical_device_list;
698    while (dev && dev != found_dev) {
699        prev_dev = dev;
700        dev = dev->next;
701    }
702
703    if (prev_dev)
704        prev_dev->next = found_dev->next;
705    else
706        icd->logical_device_list = found_dev->next;
707    loader_destroy_logical_device(found_dev);
708}
709
710
711static void loader_icd_destroy(
712        struct loader_instance *ptr_inst,
713        struct loader_icd *icd)
714{
715    ptr_inst->total_icd_count--;
716    free(icd->gpus);
717    for (struct loader_device *dev = icd->logical_device_list; dev; ) {
718        struct loader_device *next_dev = dev->next;
719        loader_destroy_logical_device(dev);
720        dev = next_dev;
721    }
722
723    free(icd);
724}
725
726static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
727{
728    struct loader_icd *icd;
729
730    icd = malloc(sizeof(*icd));
731    if (!icd)
732        return NULL;
733
734    memset(icd, 0, sizeof(*icd));
735
736    icd->scanned_icds = scanned;
737
738    return icd;
739}
740
741static struct loader_icd *loader_icd_add(
742        struct loader_instance *ptr_inst,
743        const struct loader_scanned_icds *scanned)
744{
745    struct loader_icd *icd;
746
747    icd = loader_icd_create(scanned);
748    if (!icd)
749        return NULL;
750
751    /* prepend to the list */
752    icd->next = ptr_inst->icds;
753    ptr_inst->icds = icd;
754    ptr_inst->total_icd_count++;
755
756    return icd;
757}
758
759static void loader_scanned_icd_add(const char *filename)
760{
761    loader_platform_dl_handle handle;
762    void *fp_create_inst;
763    void *fp_get_global_ext_props;
764    void *fp_get_global_ext_count;
765    void *fp_get_device_ext_props;
766    void *fp_get_device_ext_count;
767    PFN_vkGPA fp_get_proc_addr;
768    struct loader_scanned_icds *new_node;
769
770    // Used to call: dlopen(filename, RTLD_LAZY);
771    handle = loader_platform_open_library(filename);
772    if (!handle) {
773        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
774        return;
775    }
776
777#define LOOKUP(func_ptr, func) do {                            \
778    func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
779    if (!func_ptr) {                                           \
780        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
781        return;                                                \
782    }                                                          \
783} while (0)
784
785    LOOKUP(fp_create_inst, CreateInstance);
786    LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
787    LOOKUP(fp_get_global_ext_count, GetGlobalExtensionCount);
788    LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
789    LOOKUP(fp_get_device_ext_count, GetPhysicalDeviceExtensionCount);
790    LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
791#undef LOOKUP
792
793    new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
794                                                     + strlen(filename) + 1);
795    if (!new_node) {
796        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
797        return;
798    }
799
800    new_node->handle = handle;
801    new_node->CreateInstance = fp_create_inst;
802    new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
803    new_node->GetGlobalExtensionCount = fp_get_global_ext_count;
804    loader_init_ext_list(&new_node->global_extension_list);
805    loader_init_ext_list(&new_node->device_extension_list);
806    new_node->next = loader.scanned_icd_list;
807
808    new_node->lib_name = (char *) (new_node + 1);
809    if (!new_node->lib_name) {
810        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
811        return;
812    }
813    strcpy(new_node->lib_name, filename);
814
815    loader.scanned_icd_list = new_node;
816
817    loader_get_global_extensions(
818                (PFN_vkGetGlobalExtensionCount) fp_get_global_ext_count,
819                (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
820                fp_get_proc_addr,
821                new_node->lib_name,
822                handle,
823                VK_EXTENSION_ORIGIN_ICD,
824                &new_node->global_extension_list);
825}
826
827static void loader_icd_init_entrys(struct loader_icd *icd,
828                                   struct loader_scanned_icds *scanned_icds)
829{
830    /* initialize entrypoint function pointers */
831
832    #define LOOKUP(func) do {                                 \
833    icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
834    if (!icd->func) {                                           \
835        loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
836        return;                                                \
837    }                                                          \
838    } while (0)
839
840    /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
841    LOOKUP(GetDeviceProcAddr);
842    LOOKUP(DestroyInstance);
843    LOOKUP(EnumeratePhysicalDevices);
844    LOOKUP(GetPhysicalDeviceFeatures);
845    LOOKUP(GetPhysicalDeviceFormatInfo);
846    LOOKUP(GetPhysicalDeviceLimits);
847    LOOKUP(CreateDevice);
848    LOOKUP(GetPhysicalDeviceProperties);
849    LOOKUP(GetPhysicalDeviceMemoryProperties);
850    LOOKUP(GetPhysicalDevicePerformance);
851    LOOKUP(GetPhysicalDeviceQueueCount);
852    LOOKUP(GetPhysicalDeviceQueueProperties);
853    LOOKUP(GetPhysicalDeviceExtensionProperties);
854    LOOKUP(GetPhysicalDeviceExtensionCount);
855    LOOKUP(DbgCreateMsgCallback);
856    LOOKUP(DbgDestroyMsgCallback);
857#undef LOOKUP
858
859    return;
860}
861
862static void loader_debug_init(void)
863{
864    const char *env;
865
866    if (g_loader_debug > 0)
867        return;
868
869    g_loader_debug = 0;
870
871    /* parse comma-separated debug options */
872    env = getenv("LOADER_DEBUG");
873    while (env) {
874        const char *p = strchr(env, ',');
875        size_t len;
876
877        if (p)
878            len = p - env;
879        else
880            len = strlen(env);
881
882        if (len > 0) {
883            if (strncmp(env, "warn", len) == 0) {
884                g_loader_debug |= LOADER_WARN_BIT;
885                g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
886            } else if (strncmp(env, "info", len) == 0) {
887                g_loader_debug |= LOADER_INFO_BIT;
888                g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
889            } else if (strncmp(env, "perf", len) == 0) {
890                g_loader_debug |= LOADER_PERF_BIT;
891                g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
892            } else if (strncmp(env, "error", len) == 0) {
893                g_loader_debug |= LOADER_ERROR_BIT;
894                g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
895            } else if (strncmp(env, "debug", len) == 0) {
896                g_loader_debug |= LOADER_DEBUG_BIT;
897                g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
898            }
899        }
900
901        if (!p)
902            break;
903
904        env = p + 1;
905    }
906}
907
908struct loader_manifest_files {
909    uint32_t count;
910    char **filename_list;
911};
912
913/**
914 * Get next file or dirname given a string list or registry key path
915 *
916 * \returns
917 * A pointer to first char in the next path.
918 * The next path (or NULL) in the list is returned in next_path.
919 * Note: input string is modified in some cases. PASS IN A COPY!
920 */
921static char *loader_get_next_path(char *path)
922{
923    uint32_t len;
924    char *next;
925
926    if (path == NULL)
927        return NULL;
928    next = strchr(path, PATH_SEPERATOR);
929    if (next == NULL) {
930        len = (uint32_t) strlen(path);
931        next = path + len;
932    }
933    else {
934        *next = '\0';
935        next++;
936    }
937
938    return next;
939}
940
941/**
942 * Given a filename (file)  and a list of paths (dir), try to find an existing
943 * file in the paths.  If filename already is a path then no
944 * searching in the given paths.
945 *
946 * \returns
947 * A string in out_fullpath of either the full path or file.
948 * Side effect is that dir string maybe modified.
949 */
950static void loader_get_fullpath(const char *file,
951                                char *dir,
952                                size_t out_size,
953                                char *out_fullpath)
954{
955    char *next_dir;
956    if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
957        //find file exists with prepending given path
958        while (*dir) {
959            next_dir = loader_get_next_path(dir);
960            snprintf(out_fullpath, out_size, "%s%c%s",
961                     dir, DIRECTORY_SYMBOL, file);
962            if (loader_platform_file_exists(out_fullpath)) {
963                return;
964            }
965            dir = next_dir;
966        }
967    }
968    snprintf(out_fullpath, out_size, "%s", file);
969}
970
971/**
972 * Read a JSON file into a buffer.
973 *
974 * \returns
975 * A pointer to a cJSON object representing the JSON parse tree.
976 * This returned buffer should be freed by caller.
977 */
978static cJSON *loader_get_json(const char *filename)
979{
980    FILE *file;
981    char *json_buf;
982    cJSON *json;
983    uint64_t len;
984    file = fopen(filename,"rb");
985    fseek(file, 0, SEEK_END);
986    len = ftell(file);
987    fseek(file, 0, SEEK_SET);
988    json_buf = (char*) alloca(len+1);
989    if (json_buf == NULL) {
990        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
991        fclose(file);
992        return NULL;
993    }
994    if (fread(json_buf, sizeof(char), len, file) != len) {
995        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
996        fclose(file);
997        return NULL;
998    }
999    fclose(file);
1000    json_buf[len] = '\0';
1001
1002    //parse text from file
1003    json = cJSON_Parse(json_buf);
1004    if (json == NULL)
1005        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1006    return json;
1007}
1008
1009/**
1010 * Find the Vulkan library manifest files.
1011 *
1012 * This function scans the location or env_override directories/files
1013 * for a list of JSON manifest files.  If env_override is non-NULL
1014 * and has a valid value. Then the location is ignored.  Otherwise
1015 * location is used to look for manifest files. The location
1016 * is interpreted as  Registry path on Windows and a directory path(s)
1017 * on Linux.
1018 *
1019 * \returns
1020 * A string list of manifest files to be opened in out_files param.
1021 * List has a pointer to string for each manifest filename.
1022 * When done using the list in out_files, pointers should be freed.
1023 * Location or override  string lists can be either files or directories as follows:
1024 *            | location | override
1025 * --------------------------------
1026 * Win ICD    | files    | files
1027 * Win Layer  | files    | dirs
1028 * Linux ICD  | dirs     | files
1029 * Linux Layer| dirs     | dirs
1030 */
1031static void loader_get_manifest_files(const char *env_override,
1032                                      bool is_layer,
1033                                      const char *location,
1034                                      struct loader_manifest_files *out_files)
1035{
1036    char *override = NULL;
1037    char *loc;
1038    char *file, *next_file, *name;
1039    size_t alloced_count = 64;
1040    char full_path[2048];
1041    DIR *sysdir = NULL;
1042    bool list_is_dirs = false;
1043    struct dirent *dent;
1044
1045    out_files->count = 0;
1046    out_files->filename_list = NULL;
1047
1048    if (env_override != NULL && (override = getenv(env_override))) {
1049#if defined(__linux__)
1050        if (geteuid() != getuid()) {
1051            /* Don't allow setuid apps to use the env var: */
1052            override = NULL;
1053        }
1054#endif
1055    }
1056
1057    if (location == NULL) {
1058        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1059            "Can't get manifest files with NULL location, env_override=%s",
1060            env_override);
1061        return;
1062    }
1063
1064#if defined(__linux__)
1065    list_is_dirs = (override == NULL || is_layer) ? true : false;
1066#else //WIN32
1067    list_is_dirs = (is_layer && override != NULL) ? true : false;
1068#endif
1069    // Make a copy of the input we are using so it is not modified
1070    // Also handle getting the location(s) from registry on Windows
1071    if (override == NULL) {
1072#if defined (_WIN32)
1073        loc = loader_get_registry_files(location);
1074        if (loc == NULL) {
1075            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1076            return;
1077        }
1078#else
1079        loc = alloca(strlen(location) + 1);
1080        if (loc == NULL) {
1081            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1082            return;
1083        }
1084        strcpy(loc, location);
1085#endif
1086    }
1087    else {
1088        loc = alloca(strlen(override) + 1);
1089        if (loc == NULL) {
1090            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1091            return;
1092        }
1093        strcpy(loc, override);
1094    }
1095
1096    file = loc;
1097    while (*file) {
1098        next_file = loader_get_next_path(file);
1099        if (list_is_dirs) {
1100            sysdir = opendir(file);
1101            name = NULL;
1102            if (sysdir) {
1103                dent = readdir(sysdir);
1104                if (dent == NULL)
1105                    break;
1106                name = &(dent->d_name[0]);
1107                loader_get_fullpath(name, file, sizeof(full_path), full_path);
1108                name = full_path;
1109            }
1110        }
1111        else {
1112#if defined(__linux__)
1113            // only Linux has relative paths
1114            char *dir;
1115            // make a copy of location so it isn't modified
1116            dir = alloca(strlen(location) + 1);
1117            if (dir == NULL) {
1118                loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1119                return;
1120            }
1121            strcpy(dir, location);
1122
1123            loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1124
1125            name = full_path;
1126#else  // WIN32
1127            name = file;
1128#endif
1129        }
1130        while (name) {
1131                /* Look for files ending with ".json" suffix */
1132                uint32_t nlen = (uint32_t) strlen(name);
1133                const char *suf = name + nlen - 5;
1134                if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1135                    if (out_files->count == 0) {
1136                        out_files->filename_list = malloc(alloced_count * sizeof(char *));
1137                    }
1138                    else if (out_files->count == alloced_count) {
1139                        out_files->filename_list = realloc(out_files->filename_list,
1140                                        alloced_count * sizeof(char *) * 2);
1141                        alloced_count *= 2;
1142                    }
1143                    if (out_files->filename_list == NULL) {
1144                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1145                        return;
1146                    }
1147                    out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1148                    if (out_files->filename_list[out_files->count] == NULL) {
1149                        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1150                        return;
1151                    }
1152                    strcpy(out_files->filename_list[out_files->count], name);
1153                    out_files->count++;
1154                } else if (!list_is_dirs) {
1155                    loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
1156                }
1157                if (list_is_dirs) {
1158                    dent = readdir(sysdir);
1159                    if (dent == NULL)
1160                        break;
1161                    name = &(dent->d_name[0]);
1162                    loader_get_fullpath(name, file, sizeof(full_path), full_path);
1163                    name = full_path;
1164                }
1165                else {
1166                    break;
1167                }
1168        }
1169        if (sysdir)
1170            closedir(sysdir);
1171        file = next_file;
1172    }
1173    return;
1174}
1175
1176/**
1177 * Try to find the Vulkan ICD driver(s).
1178 *
1179 * This function scans the default system loader path(s) or path
1180 * specified by the \c VK_ICD_FILENAMES environment variable in
1181 * order to find loadable VK ICDs manifest files. From these
1182 * manifest files it finds the ICD libraries.
1183 *
1184 * \returns
1185 * void
1186 */
1187void loader_icd_scan(void)
1188{
1189    char *file_str;
1190    struct loader_manifest_files manifest_files;
1191
1192
1193    // convenient place to initialize a mutex
1194    loader_platform_thread_create_mutex(&loader_lock);
1195
1196    // convenient place to initialize logging
1197    loader_debug_init();
1198
1199    // Get a list of manifest files for ICDs
1200    loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1201                              &manifest_files);
1202    for (uint32_t i = 0; i < manifest_files.count; i++) {
1203        file_str = manifest_files.filename_list[i];
1204        if (file_str == NULL)
1205            continue;
1206
1207        cJSON *json, *icd_json;
1208        json = loader_get_json(file_str);
1209        icd_json = cJSON_GetObjectItem(json, "ICD");
1210        if (icd_json != NULL) {
1211            icd_json = cJSON_GetObjectItem(icd_json, "library_path");
1212            if (icd_json != NULL) {
1213                char *icd_filename = cJSON_PrintUnformatted(icd_json);
1214                char *icd_file = icd_filename;
1215                if (icd_filename != NULL) {
1216                    char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1217                    char *dir = def_dir;
1218                    // strip off extra quotes
1219                    if (icd_filename[strlen(icd_filename)  - 1] == '"')
1220                        icd_filename[strlen(icd_filename) - 1] = '\0';
1221                    if (icd_filename[0] == '"')
1222                        icd_filename++;
1223#if defined(__linux__)
1224                    char full_path[2048];
1225                    loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1226                    loader_scanned_icd_add(full_path);
1227#else // WIN32
1228                    loader_scanned_icd_add(icd_filename);
1229#endif
1230                    free(icd_file);
1231                }
1232            }
1233            else
1234                loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1235        }
1236        else
1237            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1238
1239        free(file_str);
1240        cJSON_Delete(json);
1241    }
1242    free(manifest_files.filename_list);
1243
1244}
1245
1246
1247void loader_layer_scan(void)
1248{
1249    const char *p, *next;
1250    char *libPaths = NULL;
1251    DIR *curdir;
1252    struct dirent *dent;
1253    size_t len, i;
1254    char temp_str[1024];
1255    uint32_t count;
1256    PFN_vkGetGlobalExtensionProperties fp_get_props;
1257    PFN_vkGetGlobalExtensionCount fp_get_count;
1258
1259#if defined(WIN32)
1260    bool must_free_libPaths;
1261    libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
1262                                           LAYERS_PATH_REGISTRY_VALUE);
1263    if (libPaths != NULL) {
1264        must_free_libPaths = true;
1265    } else {
1266        must_free_libPaths = false;
1267        libPaths = DEFAULT_VK_LAYERS_PATH;
1268    }
1269#else  // WIN32
1270    if (geteuid() == getuid()) {
1271        /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
1272        libPaths = getenv(LAYERS_PATH_ENV);
1273    }
1274    if (libPaths == NULL) {
1275        libPaths = DEFAULT_VK_LAYERS_PATH;
1276    }
1277#endif // WIN32
1278
1279    if (libPaths == NULL) {
1280        // Have no paths to search:
1281        return;
1282    }
1283    len = strlen(libPaths);
1284    loader.layer_dirs = malloc(len+1);
1285    if (loader.layer_dirs == NULL) {
1286        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
1287
1288        free(libPaths);
1289        return;
1290    }
1291    // Alloc passed, so we know there is enough space to hold the string
1292    strcpy(loader.layer_dirs, libPaths);
1293#if defined(WIN32)
1294    // Free any allocated memory:
1295    if (must_free_libPaths) {
1296        free(libPaths);
1297        must_free_libPaths = false;
1298    }
1299#endif // WIN32
1300    libPaths = loader.layer_dirs;
1301
1302    if (loader.scanned_layers.capacity == 0) {
1303        loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1304        if (loader.scanned_layers.list == NULL) {
1305            //TODO ERR log
1306            return;
1307        }
1308        memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1309        loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1310    }
1311    else {
1312        /* cleanup any previously scanned libraries */
1313        //TODO make sure everything is cleaned up properly
1314        for (i = 0; i < loader.scanned_layers.count; i++) {
1315            if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1316                free(loader.scanned_layers.list[i].lib_info.lib_name);
1317            free(loader.scanned_layers.list[i].name);
1318            loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1319            loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1320            loader.scanned_layers.list[i].lib_info.lib_name = NULL;
1321        }
1322        loader.scanned_layers.count = 0;
1323    }
1324    count = 0;
1325
1326    for (p = libPaths; *p; p = next) {
1327        next = strchr(p, PATH_SEPERATOR);
1328        if (next == NULL) {
1329            len = (uint32_t) strlen(p);
1330            next = p + len;
1331        }
1332        else {
1333            len = (uint32_t) (next - p);
1334            *(char *) next = '\0';
1335            next++;
1336        }
1337
1338        curdir = opendir(p);
1339        if (curdir) {
1340            dent = readdir(curdir);
1341            while (dent) {
1342                /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
1343                 * ending with VK_LIBRARY_SUFFIX
1344                 */
1345                if (!strncmp(dent->d_name,
1346                             VK_LAYER_LIBRARY_PREFIX,
1347                             VK_LAYER_LIBRARY_PREFIX_LEN)) {
1348                    uint32_t nlen = (uint32_t) strlen(dent->d_name);
1349                    const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
1350                    if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
1351                            !strncmp(suf,
1352                                     VK_LIBRARY_SUFFIX,
1353                                     VK_LIBRARY_SUFFIX_LEN)) {
1354                        loader_platform_dl_handle handle;
1355                        snprintf(temp_str, sizeof(temp_str),
1356                                 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
1357                        // Used to call: dlopen(temp_str, RTLD_LAZY)
1358                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1359                                   "Attempt to open library: %s", temp_str);
1360                        if ((handle = loader_platform_open_library(temp_str)) == NULL) {
1361                            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
1362                            dent = readdir(curdir);
1363                            continue;
1364                        }
1365                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1366                                   "Opened library: %s", temp_str);
1367
1368                        if (count * sizeof(struct loader_layer_properties) >= loader.scanned_layers.capacity) {
1369                            loader.scanned_layers.list = realloc(loader.scanned_layers.list,
1370                                        loader.scanned_layers.capacity * 2);
1371                            if (loader.scanned_layers.list == NULL) {
1372                                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1373                                       "realloc failed for scanned layers");
1374                                break;
1375                            }
1376                            loader.scanned_layers.capacity *= 2;
1377                        }
1378
1379                        fp_get_count = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionCount");
1380                        fp_get_props = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionProperties");
1381                        if (!fp_get_props || !fp_get_count) {
1382                            loader_log(VK_DBG_REPORT_WARN_BIT, 0,
1383                                       "Couldn't dlsym vkGetGlobalExtensionCount and/or vkGetGlobalExtensionProperties from library %s",
1384                                       temp_str);
1385                            dent = readdir(curdir);
1386                            loader_platform_close_library(handle);
1387                            continue;
1388                        }
1389
1390                        loader.scanned_layers.list[count].lib_info.lib_name =
1391                                malloc(strlen(temp_str) + 1);
1392                        if (loader.scanned_layers.list[count].lib_info.lib_name == NULL) {
1393                            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
1394                            break;
1395                        }
1396
1397                        strcpy(loader.scanned_layers.list[count].lib_info.lib_name, temp_str);
1398
1399                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s", temp_str);
1400                        loader_get_global_extensions(
1401                                    fp_get_count,
1402                                    fp_get_props,
1403                                    NULL,
1404                                    loader.scanned_layers.list[count].lib_info.lib_name,
1405                                    handle,
1406                                    VK_EXTENSION_ORIGIN_LAYER,
1407                                    &loader.scanned_layers.list[count].instance_extension_list);
1408
1409
1410                        count++;
1411                        loader_platform_close_library(handle);
1412                    }
1413                }
1414
1415                dent = readdir(curdir);
1416            } // while (dir_entry)
1417            closedir(curdir);
1418        } // if (curdir))
1419    } // for (libpaths)
1420
1421    loader.scanned_layers.count = count;
1422}
1423
1424static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1425{
1426    // inst is not wrapped
1427    if (inst == VK_NULL_HANDLE) {
1428        return NULL;
1429    }
1430    VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1431    void *addr;
1432
1433    if (!strcmp(pName, "vkGetInstanceProcAddr"))
1434        return (void *) loader_gpa_instance_internal;
1435
1436    if (disp_table == NULL)
1437        return NULL;
1438
1439    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1440    if (addr) {
1441        return addr;
1442    }
1443
1444    if (disp_table->GetInstanceProcAddr == NULL) {
1445        return NULL;
1446    }
1447    return disp_table->GetInstanceProcAddr(inst, pName);
1448}
1449
1450struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
1451{
1452
1453    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1454        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1455            for (uint32_t i = 0; i < icd->gpu_count; i++)
1456                if (icd->gpus[i] == gpu) {
1457                    *gpu_index = i;
1458                    return icd;
1459                }
1460        }
1461    }
1462    return NULL;
1463}
1464
1465static loader_platform_dl_handle loader_add_layer_lib(
1466        const char *chain_type,
1467        struct loader_extension_property *ext_prop)
1468{
1469    struct loader_lib_info *new_layer_lib_list, *my_lib;
1470
1471    /* Only loader layer libraries here */
1472    if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1473        return NULL;
1474    }
1475
1476    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1477        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1478            /* Have already loaded this library, just increment ref count */
1479            loader.loaded_layer_lib_list[i].ref_count++;
1480            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1481                       "%s Chain: Increment layer reference count for layer library %s",
1482                       chain_type, ext_prop->lib_name);
1483            return loader.loaded_layer_lib_list[i].lib_handle;
1484        }
1485    }
1486
1487    /* Haven't seen this library so load it */
1488    new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1489                      (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1490    if (!new_layer_lib_list) {
1491        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1492        return NULL;
1493    }
1494
1495    my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1496
1497    /* NOTE: We require that the extension property be immutable */
1498    my_lib->lib_name = (char *) ext_prop->lib_name;
1499    my_lib->ref_count = 0;
1500    my_lib->lib_handle = NULL;
1501
1502    if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1503        loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1504                   loader_platform_open_library_error(my_lib->lib_name));
1505        return NULL;
1506    } else {
1507        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1508                   "Chain: %s: Loading layer library %s",
1509                   chain_type, ext_prop->lib_name);
1510    }
1511    loader.loaded_layer_lib_count++;
1512    loader.loaded_layer_lib_list = new_layer_lib_list;
1513    my_lib->ref_count++;
1514
1515    return my_lib->lib_handle;
1516}
1517
1518static void loader_remove_layer_lib(
1519        struct loader_instance *inst,
1520        struct loader_extension_property *ext_prop)
1521{
1522    uint32_t idx;
1523    struct loader_lib_info *new_layer_lib_list, *my_lib;
1524
1525    /* Only loader layer libraries here */
1526    if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1527        return;
1528    }
1529
1530    for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1531        if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1532            /* found matching library */
1533            idx = i;
1534            my_lib = &loader.loaded_layer_lib_list[i];
1535            break;
1536        }
1537    }
1538
1539    my_lib->ref_count--;
1540    if (my_lib->ref_count > 0) {
1541        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1542                   "Decrement reference count for layer library %s", ext_prop->lib_name);
1543        return;
1544    }
1545
1546    loader_platform_close_library(my_lib->lib_handle);
1547    loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
1548               "Unloading layer library %s", ext_prop->lib_name);
1549
1550    /* Need to remove unused library from list */
1551    new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1552    if (!new_layer_lib_list) {
1553        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1554        return;
1555    }
1556
1557    if (idx > 0) {
1558        /* Copy records before idx */
1559        memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1560               sizeof(struct loader_lib_info) * idx);
1561    }
1562    if (idx < (loader.loaded_layer_lib_count - 1)) {
1563        /* Copy records after idx */
1564        memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1565                sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1566    }
1567
1568    free(loader.loaded_layer_lib_list);
1569    loader.loaded_layer_lib_count--;
1570    loader.loaded_layer_lib_list = new_layer_lib_list;
1571}
1572
1573/**
1574 * Initialize ext_prop from layer_prop.
1575 */
1576static void loader_init_ext_prop_from_layer_prop(
1577                struct loader_extension_property *ext_prop,
1578                const struct loader_layer_properties *layer_prop)
1579{
1580    memset(ext_prop, 0, sizeof(*ext_prop));
1581    ext_prop->info.sType = VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES;
1582    strncpy(ext_prop->info.name, layer_prop->name, sizeof(ext_prop->info.name));
1583    ext_prop->info.name[sizeof(ext_prop->info.name) - 1] = '\0';
1584
1585    //TODO from list of string versions to an int, for now just use build version
1586    ext_prop->info.version = VK_API_VERSION;
1587
1588    strncpy(ext_prop->info.description, layer_prop->description, sizeof(ext_prop->info.description));
1589    ext_prop->info.description[sizeof(ext_prop->info.name) - 1] = '\0';
1590    ext_prop->lib_name = layer_prop->lib_info.lib_name;
1591    ext_prop->origin = VK_EXTENSION_ORIGIN_LAYER;
1592    ext_prop->alias = NULL;
1593    ext_prop->get_proc_addr = layer_prop->functions.get_instance_proc_addr;
1594}
1595
1596/**
1597 * Go through the search_list and find any layers which match type. If layer
1598 * type match is found in then add it to ext_list.
1599 */
1600static void loader_add_layer_implicit(
1601                const enum layer_type type,
1602                struct loader_extension_list *ext_list,
1603                const uint32_t count,
1604                const struct loader_layer_properties *search_list)
1605{
1606    uint32_t i;
1607    for (i = 0; i < count; i++) {
1608        const struct loader_layer_properties *prop = &search_list[i];
1609        struct loader_extension_property ext_prop;
1610        if (prop->type & type) {
1611            loader_init_ext_prop_from_layer_prop(&ext_prop, prop);
1612            /* Found an extension with the same type, add to ext_list */
1613            loader_add_to_ext_list(ext_list, 1, &ext_prop);
1614        }
1615    }
1616
1617}
1618
1619/**
1620 * Get the layer name(s) from the env_name environment variable. If layer
1621 * is found in search_list then add it to ext_list.
1622 */
1623static void loader_add_layer_env(
1624                const char *env_name,
1625                struct loader_extension_list *ext_list,
1626                const struct loader_extension_list *search_list)
1627{
1628    char *layerEnv;
1629    char *next, *name;
1630
1631    layerEnv = getenv(env_name);
1632    if (layerEnv == NULL) {
1633        return;
1634    }
1635    name = alloca(strlen(layerEnv) + 1);
1636    if (name == NULL) {
1637        return;
1638    }
1639    strcpy(name, layerEnv);
1640
1641    while (name && *name ) {
1642        next = loader_get_next_path(name);
1643        loader_find_layer_name_add_list(name, search_list, ext_list);
1644        name = next;
1645    }
1646
1647    return;
1648}
1649
1650void loader_deactivate_instance_layers(struct loader_instance *instance)
1651{
1652    if (!instance->activated_layer_list.count) {
1653        return;
1654    }
1655
1656    /* Create instance chain of enabled layers */
1657    for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1658        struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i];
1659
1660        loader_remove_layer_lib(instance, ext_prop);
1661    }
1662    loader_destroy_ext_list(&instance->activated_layer_list);
1663    instance->activated_layer_list.count = 0;
1664}
1665
1666void loader_enable_instance_layers(struct loader_instance *inst)
1667{
1668    if (inst == NULL)
1669        return;
1670
1671    if (inst->activated_layer_list.list == NULL || inst->activated_layer_list.capacity == 0) {
1672        loader_init_ext_list(&inst->activated_layer_list);
1673    }
1674
1675    if (inst->activated_layer_list.list == NULL) {
1676        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
1677        return;
1678    }
1679
1680    /* Add any implicit layers first */
1681    loader_add_layer_implicit(
1682                                VK_LAYER_TYPE_INSTANCE_IMPLICIT,
1683                                &inst->activated_layer_list,
1684                                loader.scanned_layers.count,
1685                                loader.scanned_layers.list);
1686
1687    /* Add any layers specified via environment variable first */
1688    loader_add_layer_env(
1689                            "VK_INSTANCE_LAYERS",
1690                            &inst->activated_layer_list,
1691                            &loader.global_extensions);
1692
1693    /* Add layers specified by the application */
1694    loader_add_layer_ext_to_ext_list(
1695                                &inst->activated_layer_list,
1696                                inst->app_extension_count,
1697                                inst->app_extension_props,
1698                                &loader.global_extensions);
1699}
1700
1701uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1702{
1703    uint32_t layer_idx;
1704    VkBaseLayerObject *wrappedInstance;
1705
1706    if (inst == NULL) {
1707        return 0;
1708    }
1709
1710    // NOTE inst is unwrapped at this point in time
1711    VkObject baseObj = (VkObject) inst;
1712    VkObject nextObj = (VkObject) inst;
1713    VkBaseLayerObject *nextInstObj;
1714    PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1715
1716    if (!inst->activated_layer_list.count) {
1717        return 0;
1718    }
1719
1720    wrappedInstance = malloc(sizeof(VkBaseLayerObject)
1721                                   * inst->activated_layer_list.count);
1722    if (!wrappedInstance) {
1723        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1724        return 0;
1725    }
1726
1727    /* Create instance chain of enabled layers */
1728    layer_idx = inst->activated_layer_list.count - 1;
1729    for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1730        struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
1731        loader_platform_dl_handle lib_handle;
1732
1733         /*
1734         * Note: An extension's Get*ProcAddr should not return a function pointer for
1735         * any extension entry points until the extension has been enabled.
1736         * To do this requires a different behavior from Get*ProcAddr functions implemented
1737         * in layers.
1738         * The very first call to a layer will be it's Get*ProcAddr function requesting
1739         * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1740         * with the wrapped object given (either Instance or Device) and return the layer's
1741         * Get*ProcAddr function. The layer should also use this opportunity to record the
1742         * baseObject so that it can find the correct local dispatch table on future calls.
1743         * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1744         * will not use a wrapped object and must look up their local dispatch table from
1745         * the given baseObject.
1746         */
1747        assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
1748
1749        nextInstObj = (wrappedInstance + layer_idx);
1750        nextInstObj->pGPA = nextGPA;
1751        nextInstObj->baseObject = baseObj;
1752        nextInstObj->nextObject = nextObj;
1753        nextObj = (VkObject) nextInstObj;
1754
1755        char funcStr[256];
1756        snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
1757        lib_handle = loader_add_layer_lib("instance", ext_prop);
1758        if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1759            nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
1760        if (!nextGPA) {
1761            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", ext_prop->lib_name);
1762
1763            /* TODO: Should we return nextObj, nextGPA to previous? */
1764            continue;
1765        }
1766
1767        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1768                   "Insert instance layer library %s for extension: %s",
1769                   ext_prop->lib_name, ext_prop->info.name);
1770
1771        layer_idx--;
1772    }
1773
1774    loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
1775
1776    free(wrappedInstance);
1777    return inst->activated_layer_list.count;
1778}
1779
1780void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1781{
1782
1783    loader_init_instance_extension_dispatch_table(inst->disp,
1784                                                  inst->disp->GetInstanceProcAddr,
1785                                                  (VkInstance) inst);
1786}
1787
1788static void loader_enable_device_layers(
1789            struct loader_device *dev,
1790            struct loader_extension_list *ext_list)
1791{
1792    if (dev == NULL)
1793        return;
1794
1795    if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
1796        loader_init_ext_list(&dev->activated_layer_list);
1797    }
1798
1799    if (dev->activated_layer_list.list == NULL) {
1800        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
1801        return;
1802    }
1803
1804    /* Add any implicit layers first */
1805    loader_add_layer_implicit(
1806                                VK_LAYER_TYPE_DEVICE_IMPLICIT,
1807                                &dev->activated_layer_list,
1808                                loader.scanned_layers.count,
1809                                loader.scanned_layers.list);
1810
1811    /* Add any layers specified via environment variable next */
1812    loader_add_layer_env(
1813                        "VK_DEVICE_LAYERS",
1814                        &dev->activated_layer_list,
1815                        &loader.global_extensions);
1816
1817    /* Add layers specified by the application */
1818    loader_add_layer_ext_to_ext_list(
1819                                &dev->activated_layer_list,
1820                                dev->app_extension_count,
1821                                dev->app_extension_props,
1822                                ext_list);
1823}
1824
1825static VkResult scratch_vkCreateDevice(
1826    VkPhysicalDevice          gpu,
1827    const VkDeviceCreateInfo *pCreateInfo,
1828    VkDevice                 *pDevice)
1829{
1830    return VK_SUCCESS;
1831}
1832
1833static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
1834{
1835    /* CreateDevice workaround: Make the terminator be a scratch function
1836     * that does nothing since we have already called the ICD's create device.
1837     * We can then call down the device chain and have all the layers get set up.
1838     */
1839    if (!strcmp(name, "vkGetDeviceProcAddr"))
1840        return (void *) loader_GetDeviceChainProcAddr;
1841    if (!strcmp(name, "vkCreateDevice"))
1842        return (void *) scratch_vkCreateDevice;
1843
1844    struct loader_device *found_dev;
1845    struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
1846    return icd->GetDeviceProcAddr(device, name);
1847}
1848
1849static uint32_t loader_activate_device_layers(
1850        VkPhysicalDevice gpu,
1851        VkDevice device,
1852        struct loader_device *dev,
1853        struct loader_icd *icd,
1854        uint32_t ext_count,
1855        const VkExtensionProperties *ext_props)
1856{
1857    if (!icd)
1858        return 0;
1859
1860    if (!dev) {
1861        return 0;
1862    }
1863
1864    /* activate any layer libraries */
1865    VkObject nextObj = (VkObject) device;
1866    VkObject baseObj = nextObj;
1867    VkBaseLayerObject *nextGpuObj;
1868    PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
1869    VkBaseLayerObject *wrappedGpus;
1870
1871
1872    if (!dev->activated_layer_list.count)
1873        return 0;
1874
1875    wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
1876    if (!wrappedGpus) {
1877        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
1878        return 0;
1879    }
1880
1881    for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
1882
1883        struct loader_extension_property *ext_prop = &dev->activated_layer_list.list[i];
1884        loader_platform_dl_handle lib_handle;
1885
1886        assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
1887
1888        nextGpuObj = (wrappedGpus + i);
1889        nextGpuObj->pGPA = nextGPA;
1890        nextGpuObj->baseObject = baseObj;
1891        nextGpuObj->nextObject = nextObj;
1892        nextObj = (VkObject) nextGpuObj;
1893
1894        char funcStr[256];
1895        snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
1896        lib_handle = loader_add_layer_lib("device", ext_prop);
1897        if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1898            nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
1899        if (!nextGPA) {
1900            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", ext_prop->info.name);
1901            continue;
1902        }
1903
1904        loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1905                "Insert device layer library %s for extension: %s",
1906                ext_prop->lib_name, ext_prop->info.name);
1907
1908    }
1909
1910    loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
1911            (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
1912    free(wrappedGpus);
1913
1914    return dev->activated_layer_list.count;
1915}
1916
1917VkResult loader_CreateInstance(
1918        const VkInstanceCreateInfo*     pCreateInfo,
1919        VkInstance*                     pInstance)
1920{
1921    struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
1922    struct loader_scanned_icds *scanned_icds;
1923    struct loader_icd *icd;
1924    VkResult res;
1925
1926    scanned_icds = loader.scanned_icd_list;
1927    while (scanned_icds) {
1928        icd = loader_icd_add(ptr_instance, scanned_icds);
1929        if (icd) {
1930            res = scanned_icds->CreateInstance(pCreateInfo,
1931                                           &(icd->instance));
1932            if (res != VK_SUCCESS)
1933            {
1934                ptr_instance->icds = ptr_instance->icds->next;
1935                loader_icd_destroy(ptr_instance, icd);
1936                icd->instance = VK_NULL_HANDLE;
1937                loader_log(VK_DBG_REPORT_WARN_BIT, 0,
1938                        "ICD ignored: failed to CreateInstance on device");
1939            } else
1940            {
1941                loader_icd_init_entrys(icd, scanned_icds);
1942            }
1943        }
1944        scanned_icds = scanned_icds->next;
1945    }
1946
1947    if (ptr_instance->icds == NULL) {
1948        return VK_ERROR_INCOMPATIBLE_DRIVER;
1949    }
1950
1951    return res;
1952}
1953
1954VkResult loader_DestroyInstance(
1955        VkInstance                                instance)
1956{
1957    struct loader_instance *ptr_instance = loader_instance(instance);
1958    struct loader_icd *icds = ptr_instance->icds;
1959    struct loader_icd *next_icd;
1960    VkResult res;
1961
1962    // Remove this instance from the list of instances:
1963    struct loader_instance *prev = NULL;
1964    struct loader_instance *next = loader.instances;
1965    while (next != NULL) {
1966        if (next == ptr_instance) {
1967            // Remove this instance from the list:
1968            free(ptr_instance->app_extension_props);
1969            if (prev)
1970                prev->next = next->next;
1971            else
1972                loader.instances = next->next;
1973            break;
1974        }
1975        prev = next;
1976        next = next->next;
1977    }
1978    if (next  == NULL) {
1979        // This must be an invalid instance handle or empty list
1980        return VK_ERROR_INVALID_HANDLE;
1981    }
1982
1983    while (icds) {
1984        if (icds->instance) {
1985            res = icds->DestroyInstance(icds->instance);
1986            if (res != VK_SUCCESS)
1987                loader_log(VK_DBG_REPORT_WARN_BIT, 0,
1988                            "ICD ignored: failed to DestroyInstance on device");
1989        }
1990        next_icd = icds->next;
1991        icds->instance = VK_NULL_HANDLE;
1992        loader_icd_destroy(ptr_instance, icds);
1993
1994        icds = next_icd;
1995    }
1996
1997
1998    return VK_SUCCESS;
1999}
2000
2001VkResult loader_init_physical_device_info(
2002        struct loader_instance *ptr_instance)
2003{
2004    struct loader_icd *icd;
2005    uint32_t n, count = 0;
2006    VkResult res = VK_ERROR_UNKNOWN;
2007
2008    icd = ptr_instance->icds;
2009    while (icd) {
2010        res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2011        if (res != VK_SUCCESS)
2012            return res;
2013        icd->gpu_count = n;
2014        count += n;
2015        icd = icd->next;
2016    }
2017
2018    ptr_instance->total_gpu_count = count;
2019
2020    icd = ptr_instance->icds;
2021    while (icd) {
2022
2023        n = icd->gpu_count;
2024        icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2025        if (!icd->gpus) {
2026            /* TODO: Add cleanup code here */
2027            return VK_ERROR_OUT_OF_HOST_MEMORY;
2028        }
2029        res = icd->EnumeratePhysicalDevices(
2030                                        icd->instance,
2031                                        &n,
2032                                        icd->gpus);
2033        if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
2034
2035            for (unsigned int i = 0; i < n; i++) {
2036
2037                loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
2038
2039                if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2040                    /* TODO: Add cleanup code here */
2041                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
2042                }
2043                if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionProperties && icd->GetPhysicalDeviceExtensionCount) {
2044                    uint32_t extension_count;
2045
2046                    res = icd->GetPhysicalDeviceExtensionCount(icd->gpus[i], &extension_count);
2047                    if (res == VK_SUCCESS) {
2048                        struct loader_extension_property ext_props;
2049
2050                        /* Gather all the ICD extensions */
2051                        for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
2052                            res = icd->GetPhysicalDeviceExtensionProperties(icd->gpus[i],
2053                                                                      extension_id, &ext_props.info);
2054                            if (res == VK_SUCCESS) {
2055                                ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
2056                                ext_props.lib_name = icd->scanned_icds->lib_name;
2057                                ext_props.get_proc_addr = icd->GetDeviceProcAddr;
2058                                loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
2059                            }
2060                        }
2061
2062                        // Traverse layers list adding non-duplicate extensions to the list
2063                        for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
2064                            loader_get_physical_device_layer_extensions(
2065                                                ptr_instance,
2066                                                icd->gpus[i],
2067                                                &loader.scanned_layers.list[i],
2068                                                &icd->device_extension_cache[i]);
2069                        }
2070                    }
2071                }
2072
2073                if (res != VK_SUCCESS) {
2074                    /* clean up any extension lists previously created before this request failed */
2075                    for (uint32_t j = 0; j < i; j++) {
2076                        loader_destroy_ext_list(&icd->device_extension_cache[i]);
2077                    }
2078                    return res;
2079                }
2080            }
2081
2082            count += n;
2083        }
2084
2085        icd = icd->next;
2086    }
2087
2088    return VK_SUCCESS;
2089}
2090
2091VkResult loader_EnumeratePhysicalDevices(
2092        VkInstance                              instance,
2093        uint32_t*                               pPhysicalDeviceCount,
2094        VkPhysicalDevice*                       pPhysicalDevices)
2095{
2096    uint32_t index = 0;
2097    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2098    struct loader_icd *icd = ptr_instance->icds;
2099
2100    if (ptr_instance->total_gpu_count == 0) {
2101        loader_init_physical_device_info(ptr_instance);
2102    }
2103
2104    *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2105    if (!pPhysicalDevices) {
2106        return VK_SUCCESS;
2107    }
2108
2109    while (icd) {
2110        assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
2111        memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
2112        index += icd->gpu_count;
2113        icd = icd->next;
2114    }
2115
2116    return VK_SUCCESS;
2117}
2118
2119VkResult loader_GetPhysicalDeviceProperties(
2120        VkPhysicalDevice                        gpu,
2121        VkPhysicalDeviceProperties*             pProperties)
2122{
2123    uint32_t gpu_index;
2124    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2125    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2126
2127    if (icd->GetPhysicalDeviceProperties)
2128        res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2129
2130    return res;
2131}
2132
2133VkResult loader_GetPhysicalDevicePerformance(
2134        VkPhysicalDevice                        gpu,
2135        VkPhysicalDevicePerformance*            pPerformance)
2136{
2137    uint32_t gpu_index;
2138    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2139    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2140
2141    if (icd->GetPhysicalDevicePerformance)
2142        res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2143
2144    return res;
2145}
2146
2147VkResult loader_GetPhysicalDeviceQueueCount(
2148        VkPhysicalDevice                        gpu,
2149        uint32_t*                               pCount)
2150{
2151    uint32_t gpu_index;
2152    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2153    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2154
2155    if (icd->GetPhysicalDeviceQueueCount)
2156        res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2157
2158    return res;
2159}
2160
2161VkResult loader_GetPhysicalDeviceQueueProperties (
2162        VkPhysicalDevice gpu,
2163        uint32_t count,
2164        VkPhysicalDeviceQueueProperties * pProperties)
2165{
2166    uint32_t gpu_index;
2167    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2168    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2169
2170    if (icd->GetPhysicalDeviceQueueProperties)
2171        res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2172
2173    return res;
2174}
2175
2176VkResult loader_GetPhysicalDeviceMemoryProperties (
2177        VkPhysicalDevice gpu,
2178        VkPhysicalDeviceMemoryProperties* pProperties)
2179{
2180    uint32_t gpu_index;
2181    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2182    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2183
2184    if (icd->GetPhysicalDeviceMemoryProperties)
2185        res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
2186
2187    return res;
2188}
2189
2190VkResult loader_GetPhysicalDeviceFeatures(
2191        VkPhysicalDevice                        physicalDevice,
2192        VkPhysicalDeviceFeatures*               pFeatures)
2193{
2194    uint32_t gpu_index;
2195    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2196    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2197
2198    if (icd->GetPhysicalDeviceFeatures)
2199        res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2200
2201    return res;
2202}
2203
2204VkResult loader_GetPhysicalDeviceFormatInfo(
2205        VkPhysicalDevice                        physicalDevice,
2206        VkFormat                                format,
2207        VkFormatProperties*                     pFormatInfo)
2208{
2209    uint32_t gpu_index;
2210    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2211    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2212
2213    if (icd->GetPhysicalDeviceFormatInfo)
2214        res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2215
2216    return res;
2217}
2218
2219VkResult loader_GetPhysicalDeviceLimits(
2220        VkPhysicalDevice                        physicalDevice,
2221        VkPhysicalDeviceLimits*                 pLimits)
2222{
2223    uint32_t gpu_index;
2224    struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2225    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2226
2227    if (icd->GetPhysicalDeviceLimits)
2228        res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2229
2230    return res;
2231}
2232
2233VkResult loader_CreateDevice(
2234        VkPhysicalDevice                        gpu,
2235        const VkDeviceCreateInfo*               pCreateInfo,
2236        VkDevice*                               pDevice)
2237{
2238    uint32_t gpu_index;
2239    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2240    struct loader_device *dev;
2241    VkResult res;
2242
2243    if (!icd->CreateDevice) {
2244        return VK_ERROR_INITIALIZATION_FAILED;
2245    }
2246
2247    res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2248    if (res != VK_SUCCESS) {
2249        return res;
2250    }
2251
2252    dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2253    if (dev == NULL) {
2254        return VK_ERROR_OUT_OF_HOST_MEMORY;
2255    }
2256    PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2257    loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2258                                      icd->gpus[gpu_index], icd->gpus[gpu_index]);
2259
2260    dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2261    loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2262
2263    dev->app_extension_count = pCreateInfo->extensionCount;
2264    dev->app_extension_props = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
2265    if (dev->app_extension_props == NULL && (dev->app_extension_count > 0)) {
2266        return VK_ERROR_OUT_OF_HOST_MEMORY;
2267    }
2268
2269    /* Make local copy of extension list */
2270    if (dev->app_extension_count > 0 && dev->app_extension_props != NULL) {
2271        memcpy(dev->app_extension_props, pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
2272    }
2273
2274    /*
2275     * Put together the complete list of extensions to enable
2276     * This includes extensions requested via environment variables.
2277     */
2278    loader_enable_device_layers(dev, &icd->device_extension_cache[gpu_index]);
2279
2280    /*
2281     * Load the libraries needed by the extensions on the
2282     * enabled extension list. This will build the device chain
2283     * terminating with the selected device.
2284     */
2285    loader_activate_device_layers(gpu, *pDevice, dev, icd,
2286                                  dev->app_extension_count,
2287                                  dev->app_extension_props);
2288
2289    res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2290
2291    dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2292
2293    return res;
2294}
2295
2296static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
2297{
2298    if (instance == VK_NULL_HANDLE)
2299        return NULL;
2300
2301    void *addr;
2302    /* get entrypoint addresses that are global (in the loader)*/
2303    addr = globalGetProcAddr(pName);
2304    if (addr)
2305        return addr;
2306
2307    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2308
2309    /* return any extension global entrypoints */
2310    addr = debug_report_instance_gpa(ptr_instance, pName);
2311    if (addr) {
2312        return addr;
2313    }
2314
2315    /* TODO Remove this once WSI has no loader special code */
2316    addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
2317    if (addr) {
2318        return addr;
2319    }
2320
2321    /* return the instance dispatch table entrypoint for extensions */
2322    const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2323    if (disp_table == NULL)
2324        return NULL;
2325
2326    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2327    if (addr)
2328        return addr;
2329
2330    return NULL;
2331}
2332
2333LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2334{
2335    return loader_GetInstanceProcAddr(instance, pName);
2336}
2337
2338static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
2339{
2340    if (device == VK_NULL_HANDLE) {
2341        return NULL;
2342    }
2343
2344    void *addr;
2345
2346    /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2347       make sure the loader entrypoint is returned */
2348    addr = loader_non_passthrough_gpa(pName);
2349    if (addr) {
2350        return addr;
2351    }
2352
2353    /* return any extension device entrypoints the loader knows about */
2354    /* TODO once WSI has no loader special code remove this */
2355    addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
2356    if (addr) {
2357        return addr;
2358    }
2359
2360    /* return the dispatch table entrypoint for the fastest case */
2361    const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
2362    if (disp_table == NULL)
2363        return NULL;
2364
2365    addr = loader_lookup_device_dispatch_table(disp_table, pName);
2366    if (addr)
2367        return addr;
2368    else  {
2369        if (disp_table->GetDeviceProcAddr == NULL)
2370            return NULL;
2371        return disp_table->GetDeviceProcAddr(device, pName);
2372    }
2373}
2374
2375LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2376{
2377    return loader_GetDeviceProcAddr(device, pName);
2378}
2379
2380LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionCount(
2381                                               uint32_t* pCount)
2382{
2383    /* Scan/discover all ICD libraries in a single-threaded manner */
2384    loader_platform_thread_once(&once_icd, loader_icd_scan);
2385
2386    /* get layer libraries in a single-threaded manner */
2387    loader_platform_thread_once(&once_layer, loader_layer_scan);
2388
2389    /* merge any duplicate extensions */
2390    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2391
2392    loader_platform_thread_lock_mutex(&loader_lock);
2393    *pCount = loader.global_extensions.count;
2394    loader_platform_thread_unlock_mutex(&loader_lock);
2395    return VK_SUCCESS;
2396}
2397
2398LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
2399                                              uint32_t extensionIndex,
2400                                              VkExtensionProperties* pProperties)
2401{
2402
2403    /* Scan/discover all ICD libraries in a single-threaded manner */
2404    loader_platform_thread_once(&once_icd, loader_icd_scan);
2405
2406    /* get layer libraries in a single-threaded manner */
2407    loader_platform_thread_once(&once_layer, loader_layer_scan);
2408
2409    /* merge any duplicate extensions */
2410    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2411
2412    if (extensionIndex >= loader.global_extensions.count)
2413        return VK_ERROR_INVALID_VALUE;
2414
2415    loader_platform_thread_lock_mutex(&loader_lock);
2416    memcpy(pProperties,
2417               &loader.global_extensions.list[extensionIndex],
2418               sizeof(VkExtensionProperties));
2419
2420    loader_platform_thread_unlock_mutex(&loader_lock);
2421    return VK_SUCCESS;
2422}
2423
2424VkResult loader_GetPhysicalDeviceExtensionCount(
2425        VkPhysicalDevice                        gpu,
2426        uint32_t*                               pCount)
2427{
2428    uint32_t gpu_index;
2429    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2430    *pCount = icd->device_extension_cache[gpu_index].count;
2431
2432    return VK_SUCCESS;
2433}
2434
2435VkResult loader_GetPhysicalDeviceExtensionProperties(
2436        VkPhysicalDevice                        gpu,
2437        uint32_t                                extensionIndex,
2438        VkExtensionProperties*                  pProperties)
2439{
2440    uint32_t gpu_index;
2441    struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2442
2443    if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
2444        return VK_ERROR_INVALID_VALUE;
2445
2446    memcpy( pProperties,
2447           &icd->device_extension_cache[gpu_index].list[extensionIndex],
2448           sizeof(VkExtensionProperties));
2449
2450    return VK_SUCCESS;
2451}
2452