loader.c revision fce93d9098c3f00c94919a78b8529ccdc0fbf1a6
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 "loader_platform.h"
44#include "loader.h"
45#include "gpa_helper.h"
46#include "table_ops.h"
47#include "vkIcd.h"
48// The following is #included again to catch certain OS-specific functions
49// being used:
50#include "loader_platform.h"
51
52struct layer_name_pair {
53    char *layer_name;
54    const char *lib_name;
55};
56
57struct extension_property {
58    char extName[VK_MAX_EXTENSION_NAME];
59    uint32_t version;
60    bool hosted;            // does the extension reside in one driver/layer
61};
62
63struct loader_icd {
64    const struct loader_scanned_icds *scanned_icds;
65
66    VkLayerDispatchTable *loader_dispatch;
67    uint32_t layer_count[MAX_GPUS_FOR_LAYER];
68    struct loader_layers layer_libs[MAX_GPUS_FOR_LAYER][MAX_LAYER_LIBRARIES];
69    VkBaseLayerObject *wrappedGpus[MAX_GPUS_FOR_LAYER];
70    uint32_t gpu_count;
71    VkBaseLayerObject *gpus;
72
73    struct loader_icd *next;
74};
75
76
77struct loader_scanned_icds {
78    loader_platform_dl_handle handle;
79
80    PFN_vkGetProcAddr GetProcAddr;
81    PFN_vkCreateInstance CreateInstance;
82    PFN_vkDestroyInstance DestroyInstance;
83    PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
84    PFN_vkGetGlobalExtensionInfo GetGlobalExtensionInfo;
85    VkInstance instance;
86    struct loader_scanned_icds *next;
87    uint32_t extension_count;
88    struct extension_property *extensions;
89};
90
91struct loader_struct loader = {0};
92
93VkLayerInstanceDispatchTable instance_disp = {
94    .GetInstanceProcAddr = vkGetInstanceProcAddr,
95    .GetProcAddr = vkGetProcAddr,
96    .CreateInstance = loader_CreateInstance,
97    .DestroyInstance = loader_DestroyInstance,
98    .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
99    .GetPhysicalDeviceInfo = vkGetPhysicalDeviceInfo,
100    .CreateDevice = vkCreateDevice,
101    .GetGlobalExtensionInfo = loader_GetGlobalExtensionInfo,
102    .GetPhysicalDeviceExtensionInfo = vkGetPhysicalDeviceExtensionInfo,
103    .EnumerateLayers = vkEnumerateLayers,
104    .GetMultiDeviceCompatibility = vkGetMultiDeviceCompatibility,
105    .DbgRegisterMsgCallback = loader_DbgRegisterMsgCallback,
106    .DbgUnregisterMsgCallback = loader_DbgUnregisterMsgCallback,
107    .DbgSetGlobalOption = loader_DbgSetGlobalOption,
108};
109
110LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
111LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
112LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
113
114#if defined(WIN32)
115char *loader_get_registry_string(const HKEY hive,
116                                 const LPCTSTR sub_key,
117                                 const char *value)
118{
119    DWORD access_flags = KEY_QUERY_VALUE;
120    DWORD value_type;
121    HKEY key;
122    VkResult  rtn_value;
123    char *rtn_str = NULL;
124    DWORD rtn_len = 0;
125    size_t allocated_len = 0;
126
127    rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
128    if (rtn_value != ERROR_SUCCESS) {
129        // We didn't find the key.  Try the 32-bit hive (where we've seen the
130        // key end up on some people's systems):
131        access_flags |= KEY_WOW64_32KEY;
132        rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
133        if (rtn_value != ERROR_SUCCESS) {
134            // We still couldn't find the key, so give up:
135            return NULL;
136        }
137    }
138
139    rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
140                                (PVOID) rtn_str, (LPDWORD) &rtn_len);
141    if (rtn_value == ERROR_SUCCESS) {
142        // If we get to here, we found the key, and need to allocate memory
143        // large enough for rtn_str, and query again:
144        allocated_len = rtn_len + 4;
145        rtn_str = malloc(allocated_len);
146        rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
147                                    (PVOID) rtn_str, (LPDWORD) &rtn_len);
148        if (rtn_value == ERROR_SUCCESS) {
149            // We added 4 extra bytes to rtn_str, so that we can ensure that
150            // the string is NULL-terminated (albeit, in a brute-force manner):
151            rtn_str[allocated_len-1] = '\0';
152        } else {
153            // This should never occur, but in case it does, clean up:
154            free(rtn_str);
155            rtn_str = NULL;
156        }
157    } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
158
159    // Close the registry key that was opened:
160    RegCloseKey(key);
161
162    return rtn_str;
163}
164
165
166// For ICD developers, look in the registry, and look for an environment
167// variable for a path(s) where to find the ICD(s):
168static char *loader_get_registry_and_env(const char *env_var,
169                                         const char *registry_value)
170{
171    char *env_str = getenv(env_var);
172    size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
173    char *registry_str = NULL;
174    size_t registry_len = 0;
175    char *rtn_str = NULL;
176    size_t rtn_len;
177
178    registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
179                                              "Software\\Vulkan",
180                                              registry_value);
181    registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
182
183    rtn_len = env_len + registry_len + 1;
184    if (rtn_len <= 2) {
185        // We found neither the desired registry value, nor the environment
186        // variable; return NULL:
187        return NULL;
188    } else {
189        // We found something, and so we need to allocate memory for the string
190        // to return:
191        rtn_str = malloc(rtn_len);
192    }
193
194    if (registry_len == 0) {
195        // We didn't find the desired registry value, and so we must have found
196        // only the environment variable:
197        _snprintf(rtn_str, rtn_len, "%s", env_str);
198    } else if (env_str != NULL) {
199        // We found both the desired registry value and the environment
200        // variable, so concatenate them both:
201        _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
202    } else {
203        // We must have only found the desired registry value:
204        _snprintf(rtn_str, rtn_len, "%s", registry_str);
205    }
206
207    if (registry_str) {
208      free(registry_str);
209    }
210
211    return(rtn_str);
212}
213#endif // WIN32
214
215
216static void loader_log(VK_DBG_MSG_TYPE msg_type, int32_t msg_code,
217                       const char *format, ...)
218{
219    char msg[256];
220    va_list ap;
221    int ret;
222
223    va_start(ap, format);
224    ret = vsnprintf(msg, sizeof(msg), format, ap);
225    if ((ret >= (int) sizeof(msg)) || ret < 0) {
226        msg[sizeof(msg) - 1] = '\0';
227    }
228    va_end(ap);
229
230#if defined(WIN32)
231	OutputDebugString(msg);
232#endif
233    fputs(msg, stderr);
234    fputc('\n', stderr);
235
236}
237
238static bool has_extension(struct extension_property *exts, uint32_t count,
239                          const char *name, bool must_be_hosted)
240{
241    uint32_t i;
242    for (i = 0; i < count; i++) {
243        if (!strcmp(name, exts[i].extName) && (!must_be_hosted || exts[i].hosted))
244            return true;
245    }
246    return false;
247}
248
249static void get_global_extensions(PFN_vkGetGlobalExtensionInfo fp_get,
250                                  uint32_t *count_out,
251                                  struct extension_property **props_out)
252{
253    uint32_t i, count, cur;
254    size_t siz = sizeof(count);
255    struct extension_property *ext_props;
256    VkExtensionProperties vk_prop;
257    VkResult res;
258
259    *count_out = 0;
260    *props_out = NULL;
261    res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
262    if (res != VK_SUCCESS) {
263        loader_log(VK_DBG_MSG_WARNING, 0, "Error getting global extension count from ICD");
264        return;
265    }
266    ext_props = (struct extension_property *) malloc(sizeof(struct extension_property) * count);
267    if (ext_props == NULL) {
268        loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory didn't get global extensions from ICD");
269        return;
270    }
271    siz = sizeof(VkExtensionProperties);
272    cur = 0;
273    for (i = 0; i < count; i++) {
274        res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &vk_prop);
275        if (res == VK_SUCCESS) {
276            (ext_props + cur)->hosted = false;
277            (ext_props + cur)->version = vk_prop.version;
278            strncpy((ext_props + cur)->extName, vk_prop.extName, VK_MAX_EXTENSION_NAME);
279            (ext_props + cur)->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
280            cur++;
281        }
282        *count_out = cur;
283        *props_out = ext_props;
284    }
285    return;
286}
287
288static void loader_init_ext_list()
289{
290    loader.scanned_ext_list_capacity = 256 * sizeof(struct extension_property *);
291    loader.scanned_ext_list = malloc(loader.scanned_ext_list_capacity);
292    memset(loader.scanned_ext_list, 0, loader.scanned_ext_list_capacity);
293    loader.scanned_ext_list_count = 0;
294}
295
296#if 0 // currently no place to call this
297static void loader_destroy_ext_list()
298{
299    free(loader.scanned_ext_list);
300    loader.scanned_ext_list_capacity = 0;
301    loader.scanned_ext_list_count = 0;
302}
303#endif
304
305static void loader_add_to_ext_list(uint32_t count,
306                                   struct extension_property *prop_list,
307                                   bool is_layer_ext)
308{
309    uint32_t i, j;
310    bool duplicate;
311    struct extension_property *cur_ext;
312
313    if (loader.scanned_ext_list == NULL || loader.scanned_ext_list_capacity == 0)
314        loader_init_ext_list();
315
316    if (loader.scanned_ext_list == NULL)
317        return;
318
319    struct extension_property *ext_list, **ext_list_addr;
320
321    for (i = 0; i < count; i++) {
322        cur_ext = prop_list + i;
323
324        // look for duplicates or not
325        duplicate = false;
326        for (j = 0; j < loader.scanned_ext_list_count; j++) {
327            ext_list = loader.scanned_ext_list[j];
328            if (!strcmp(cur_ext->extName, ext_list->extName)) {
329                duplicate = true;
330                ext_list->hosted = false;
331                break;
332            }
333        }
334
335        // add to list at end
336        if (!duplicate) {
337            // check for enough capacity
338            if (loader.scanned_ext_list_count * sizeof(struct extension_property *)
339                            >= loader.scanned_ext_list_capacity) {
340                // double capacity
341                loader.scanned_ext_list_capacity *= 2;
342                loader.scanned_ext_list = realloc(loader.scanned_ext_list,
343                        loader.scanned_ext_list_capacity);
344            }
345            ext_list_addr = &(loader.scanned_ext_list[loader.scanned_ext_list_count++]);
346            *ext_list_addr = cur_ext;
347            cur_ext->hosted = true;
348        }
349
350    }
351}
352
353bool loader_is_extension_scanned(const char *name)
354{
355    uint32_t i;
356
357    for (i = 0; i < loader.scanned_ext_list_count; i++) {
358        if (!strcmp(name, loader.scanned_ext_list[i]->extName))
359            return true;
360    }
361    return false;
362}
363
364void loader_coalesce_extensions(void)
365{
366    uint32_t i;
367    struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
368
369    // traverse scanned icd list adding non-duplicate extensions to the list
370    while (icd_list != NULL) {
371        loader_add_to_ext_list(icd_list->extension_count, icd_list->extensions, false);
372        icd_list = icd_list->next;
373    };
374
375    //Traverse layers list adding non-duplicate extensions to the list
376    for (i = 0; i < loader.scanned_layer_count; i++) {
377        loader_add_to_ext_list(loader.scanned_layers[i].extension_count,
378                loader.scanned_layers[i].extensions, true);
379    }
380}
381
382static void loader_icd_destroy(struct loader_icd *icd)
383{
384    loader_platform_close_library(icd->scanned_icds->handle);
385    free(icd);
386}
387
388static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
389{
390    struct loader_icd *icd;
391
392    icd = malloc(sizeof(*icd));
393    if (!icd)
394        return NULL;
395
396    memset(icd, 0, sizeof(*icd));
397
398    icd->scanned_icds = scanned;
399
400    return icd;
401}
402
403static struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst,
404                                     const struct loader_scanned_icds *scanned)
405{
406    struct loader_icd *icd;
407
408    icd = loader_icd_create(scanned);
409    if (!icd)
410        return NULL;
411
412    /* prepend to the list */
413    icd->next = ptr_inst->icds;
414    ptr_inst->icds = icd;
415
416    return icd;
417}
418
419static void loader_scanned_icd_add(const char *filename)
420{
421    loader_platform_dl_handle handle;
422    void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst;
423    void *fp_get_global_ext_info;
424    struct loader_scanned_icds *new_node;
425
426    // Used to call: dlopen(filename, RTLD_LAZY);
427    handle = loader_platform_open_library(filename);
428    if (!handle) {
429        loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_open_library_error(filename));
430        return;
431    }
432
433#define LOOKUP(func_ptr, func) do {                            \
434    func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
435    if (!func_ptr) {                                           \
436        loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_get_proc_address_error("vk" #func)); \
437        return;                                                \
438    }                                                          \
439} while (0)
440
441    LOOKUP(fp_gpa, GetProcAddr);
442    LOOKUP(fp_create_inst, CreateInstance);
443    LOOKUP(fp_destroy_inst, DestroyInstance);
444    LOOKUP(fp_enumerate, EnumeratePhysicalDevices);
445    LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
446#undef LOOKUP
447
448    new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds));
449    if (!new_node) {
450        loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory can't add icd");
451        return;
452    }
453
454    new_node->handle = handle;
455    new_node->GetProcAddr = fp_gpa;
456    new_node->CreateInstance = fp_create_inst;
457    new_node->DestroyInstance = fp_destroy_inst;
458    new_node->EnumeratePhysicalDevices = fp_enumerate;
459    new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
460    new_node->extension_count = 0;
461    new_node->extensions = NULL;
462    new_node->next = loader.scanned_icd_list;
463
464    loader.scanned_icd_list = new_node;
465
466    if (fp_get_global_ext_info) {
467        get_global_extensions((PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
468                       &new_node->extension_count,
469                       &new_node->extensions);
470    } else {
471        loader_log(VK_DBG_MSG_WARNING, 0, "Couldn't get global extensions from ICD");
472    }
473}
474
475/**
476 * Try to \c loader_icd_scan VK driver(s).
477 *
478 * This function scans the default system path or path
479 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
480 * order to find loadable VK ICDs with the name of libVK_*.
481 *
482 * \returns
483 * void; but side effect is to set loader_icd_scanned to true
484 */
485void loader_icd_scan(void)
486{
487    const char *p, *next;
488    char *libPaths = NULL;
489    DIR *sysdir;
490    struct dirent *dent;
491    char icd_library[1024];
492    char path[1024];
493    uint32_t len;
494#if defined(WIN32)
495    bool must_free_libPaths;
496    libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
497                                           DRIVER_PATH_REGISTRY_VALUE);
498    if (libPaths != NULL) {
499        must_free_libPaths = true;
500    } else {
501        must_free_libPaths = false;
502        libPaths = DEFAULT_VK_DRIVERS_PATH;
503    }
504#else  // WIN32
505    if (geteuid() == getuid()) {
506        /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
507        libPaths = getenv(DRIVER_PATH_ENV);
508    }
509    if (libPaths == NULL) {
510        libPaths = DEFAULT_VK_DRIVERS_PATH;
511    }
512#endif // WIN32
513
514    for (p = libPaths; *p; p = next) {
515       next = strchr(p, PATH_SEPERATOR);
516       if (next == NULL) {
517          len = (uint32_t) strlen(p);
518          next = p + len;
519       }
520       else {
521          len = (uint32_t) (next - p);
522          sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
523          p = path;
524          next++;
525       }
526
527       // TODO/TBD: Do we want to do this on Windows, or just let Windows take
528       // care of its own search path (which it apparently has)?
529       sysdir = opendir(p);
530       if (sysdir) {
531          dent = readdir(sysdir);
532          while (dent) {
533             /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
534              * ending with VK_LIBRARY_SUFFIX
535              */
536              if (!strncmp(dent->d_name,
537                          VK_DRIVER_LIBRARY_PREFIX,
538                          VK_DRIVER_LIBRARY_PREFIX_LEN)) {
539                 uint32_t nlen = (uint32_t) strlen(dent->d_name);
540                 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
541                 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
542                     !strncmp(suf,
543                              VK_LIBRARY_SUFFIX,
544                              VK_LIBRARY_SUFFIX_LEN)) {
545                    snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
546                    loader_scanned_icd_add(icd_library);
547                 }
548              }
549
550             dent = readdir(sysdir);
551          }
552          closedir(sysdir);
553       }
554    }
555
556#if defined(WIN32)
557    // Free any allocated memory:
558    if (must_free_libPaths) {
559        free(libPaths);
560    }
561#endif // WIN32
562
563    // Note that we've scanned for ICDs:
564    loader.icds_scanned = true;
565}
566
567
568void layer_lib_scan(void)
569{
570    const char *p, *next;
571    char *libPaths = NULL;
572    DIR *curdir;
573    struct dirent *dent;
574    size_t len, i;
575    char temp_str[1024];
576    uint32_t count;
577    PFN_vkGetGlobalExtensionInfo fp_get_ext;
578
579#if defined(WIN32)
580    bool must_free_libPaths;
581    libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
582                                           LAYERS_PATH_REGISTRY_VALUE);
583    if (libPaths != NULL) {
584        must_free_libPaths = true;
585    } else {
586        must_free_libPaths = false;
587        libPaths = DEFAULT_VK_LAYERS_PATH;
588    }
589#else  // WIN32
590    if (geteuid() == getuid()) {
591        /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
592        libPaths = getenv(LAYERS_PATH_ENV);
593    }
594    if (libPaths == NULL) {
595        libPaths = DEFAULT_VK_LAYERS_PATH;
596    }
597#endif // WIN32
598
599    if (libPaths == NULL) {
600        // Have no paths to search:
601        return;
602    }
603    len = strlen(libPaths);
604    loader.layer_dirs = malloc(len+1);
605    if (loader.layer_dirs == NULL) {
606        free(libPaths);
607        return;
608    }
609    // Alloc passed, so we know there is enough space to hold the string, don't
610    // need strncpy
611    strcpy(loader.layer_dirs, libPaths);
612#if defined(WIN32)
613    // Free any allocated memory:
614    if (must_free_libPaths) {
615        free(libPaths);
616        must_free_libPaths = false;
617    }
618#endif // WIN32
619    libPaths = loader.layer_dirs;
620
621    /* cleanup any previously scanned libraries */
622    for (i = 0; i < loader.scanned_layer_count; i++) {
623        if (loader.scanned_layers[i].name != NULL)
624            free(loader.scanned_layers[i].name);
625        if (loader.scanned_layers[i].extensions != NULL)
626            free(loader.scanned_layers[i].extensions);
627        loader.scanned_layers[i].name = NULL;
628        loader.scanned_layers[i].extensions = NULL;
629    }
630    loader.scanned_layer_count = 0;
631    count = 0;
632
633    for (p = libPaths; *p; p = next) {
634        next = strchr(p, PATH_SEPERATOR);
635        if (next == NULL) {
636           len = (uint32_t) strlen(p);
637           next = p + len;
638        }
639        else {
640           len = (uint32_t) (next - p);
641           *(char *) next = '\0';
642           next++;
643        }
644
645       curdir = opendir(p);
646       if (curdir) {
647          dent = readdir(curdir);
648          while (dent) {
649             /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
650              * ending with VK_LIBRARY_SUFFIX
651              */
652              if (!strncmp(dent->d_name,
653                          VK_LAYER_LIBRARY_PREFIX,
654                          VK_LAYER_LIBRARY_PREFIX_LEN)) {
655                 uint32_t nlen = (uint32_t) strlen(dent->d_name);
656                 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
657                 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
658                     !strncmp(suf,
659                              VK_LIBRARY_SUFFIX,
660                              VK_LIBRARY_SUFFIX_LEN)) {
661                     loader_platform_dl_handle handle;
662                     snprintf(temp_str, sizeof(temp_str),
663                              "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
664                     // Used to call: dlopen(temp_str, RTLD_LAZY)
665                     if ((handle = loader_platform_open_library(temp_str)) == NULL) {
666                         dent = readdir(curdir);
667                         continue;
668                     }
669                     if (count == MAX_LAYER_LIBRARIES) {
670                         loader_log(VK_DBG_MSG_ERROR, 0,
671                                    "%s ignored: max layer libraries exceed",
672                                    temp_str);
673                         break;
674                     }
675                     fp_get_ext = loader_platform_get_proc_address(handle,
676                                               "vkGetGlobalExtensionInfo");
677
678                     if (!fp_get_ext) {
679                        loader_log(VK_DBG_MSG_WARNING, 0,
680                              "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
681                               temp_str);
682                        dent = readdir(curdir);
683                        loader_platform_close_library(handle);
684                        continue;
685                     }
686
687                     loader.scanned_layers[count].name =
688                                                   malloc(strlen(temp_str) + 1);
689                     if (loader.scanned_layers[count].name == NULL) {
690                         loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
691                         break;
692                     }
693
694                     get_global_extensions(fp_get_ext,
695                             &loader.scanned_layers[count].extension_count,
696                             &loader.scanned_layers[count].extensions);
697
698
699                    strcpy(loader.scanned_layers[count].name, temp_str);
700                    count++;
701                    loader_platform_close_library(handle);
702                 }
703             }
704
705             dent = readdir(curdir);
706          } // while (dir_entry)
707          if (count == MAX_LAYER_LIBRARIES)
708             break;
709          closedir(curdir);
710       } // if (curdir))
711    } // for (libpaths)
712
713    loader.scanned_layer_count = count;
714    loader.layer_scanned = true;
715}
716
717static void* VKAPI loader_gpa_device_internal(VkPhysicalDevice physDev, const char * pName)
718{
719    if (physDev == VK_NULL_HANDLE) {
720        return NULL;
721    }
722    VkBaseLayerObject* physDevWrap = (VkBaseLayerObject *) physDev;
723    VkLayerDispatchTable* disp_table = * (VkLayerDispatchTable **) physDevWrap->baseObject;
724    void *addr;
725
726    if (disp_table == NULL)
727        return NULL;
728
729    addr = loader_lookup_device_dispatch_table(disp_table, pName);
730    if (addr)
731        return addr;
732    else  {
733        if (disp_table->GetProcAddr == NULL)
734            return NULL;
735        if (physDevWrap->baseObject == physDevWrap->nextObject)
736            return physDevWrap->pGPA(physDevWrap->baseObject, pName);
737        return disp_table->GetProcAddr(physDevWrap->nextObject, pName);
738    }
739}
740
741static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
742{
743    // inst is not wrapped
744    if (inst == VK_NULL_HANDLE) {
745        return NULL;
746    }
747    VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
748    void *addr;
749
750    if (disp_table == NULL)
751        return NULL;
752
753    addr = loader_lookup_instance_dispatch_table(disp_table, pName);
754    if (addr)
755        return addr;
756    else  {
757        if (disp_table->GetInstanceProcAddr == NULL)
758            return NULL;
759        return disp_table->GetInstanceProcAddr(inst, pName);
760    }
761}
762
763struct loader_icd * loader_get_icd(const VkBaseLayerObject *gpu, uint32_t *gpu_index)
764{
765    /*
766     * NOTE: at this time icd->gpus is pointing to wrapped GPUs, but no where else
767     * are wrapped gpus used. Should go away. The incoming gpu is NOT wrapped so
768     * need to test it against the wrapped GPU's base object.
769     */
770    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
771        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
772            for (uint32_t i = 0; i < icd->gpu_count; i++)
773                if ((icd->gpus + i) == gpu || (void*)(icd->gpus +i)->baseObject == gpu) {
774                    *gpu_index = i;
775                    return icd;
776                }
777        }
778    }
779    return NULL;
780}
781
782static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
783{
784    if (icd->layer_count[gpu_index])
785        return true;
786    else
787        return false;
788}
789
790static void loader_init_device_layer_libs(struct loader_icd *icd, uint32_t gpu_index,
791                                   struct layer_name_pair * pLayerNames,
792                                   uint32_t count)
793{
794    if (!icd)
795        return;
796
797    struct loader_layers *obj;
798    bool foundLib;
799    for (uint32_t i = 0; i < count; i++) {
800        foundLib = false;
801        for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) {
802            if (icd->layer_libs[gpu_index][j].lib_handle &&
803                !strcmp(icd->layer_libs[gpu_index][j].name,
804                (char *) pLayerNames[i].layer_name) &&
805                strcmp("Validation", (char *) pLayerNames[i].layer_name)) {
806                foundLib = true;
807                break;
808            }
809        }
810        if (!foundLib) {
811            obj = &(icd->layer_libs[gpu_index][i]);
812            strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
813            obj->name[sizeof(obj->name) - 1] = '\0';
814            // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)
815            if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) {
816                loader_log(VK_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name));
817                continue;
818            } else {
819                loader_log(VK_DBG_MSG_UNKNOWN, 0, "Inserting device layer %s from library %s",
820                           pLayerNames[i].layer_name, pLayerNames[i].lib_name);
821            }
822            free(pLayerNames[i].layer_name);
823            icd->layer_count[gpu_index]++;
824        }
825    }
826}
827
828static void loader_init_instance_layer_libs(struct loader_instance *inst,
829                                   struct layer_name_pair * pLayerNames,
830                                   uint32_t count)
831{
832    if (!inst)
833        return;
834
835    struct loader_layers *obj;
836    bool foundLib;
837    for (uint32_t i = 0; i < count; i++) {
838        foundLib = false;
839        for (uint32_t j = 0; j < inst->layer_count; j++) {
840            if (inst->layer_libs[j].lib_handle &&
841                    !strcmp(inst->layer_libs[j].name,
842                    (char *) pLayerNames[i].layer_name) &&
843                    strcmp("Validation", (char *) pLayerNames[i].layer_name)) {
844                foundLib = true;
845                break;
846            }
847        }
848        if (!foundLib) {
849            obj = &(inst->layer_libs[i]);
850            strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
851            obj->name[sizeof(obj->name) - 1] = '\0';
852            // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)
853            if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) {
854                loader_log(VK_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name));
855                continue;
856            } else {
857                loader_log(VK_DBG_MSG_UNKNOWN, 0, "Inserting instance layer %s from library %s",
858                           pLayerNames[i].layer_name, pLayerNames[i].lib_name);
859            }
860            free(pLayerNames[i].layer_name);
861            inst->layer_count++;
862        }
863    }
864}
865
866static bool find_layer_extension(const char *pExtName, uint32_t *out_count,
867                                 char *lib_name[MAX_LAYER_LIBRARIES])
868{
869    char *search_name;
870    uint32_t j, found_count = 0;
871    bool must_be_hosted;
872    bool found = false;
873
874    /*
875     * The loader provides the abstraction that make layers and extensions work via
876     * the currently defined extension mechanism. That is, when app queries for an extension
877     * via vkGetGlobalExtensionInfo, the loader will call both the driver as well as any layers
878     * to see who implements that extension. Then, if the app enables the extension during
879     * vkCreateInstance the loader will find and load any layers that implement that extension.
880     */
881
882    // TODO: what about GetPhysicalDeviceExtension for device specific layers/extensions
883
884    for (j = 0; j < loader.scanned_layer_count; j++) {
885
886        if (!strcmp("Validation", pExtName))
887            must_be_hosted = false;
888        else
889            must_be_hosted = true;
890        if (has_extension(loader.scanned_layers[j].extensions,
891                          loader.scanned_layers[j].extension_count, pExtName,
892                          must_be_hosted)) {
893
894            found = true;
895            lib_name[found_count] = loader.scanned_layers[j].name;
896            found_count++;
897        } else {
898            // Extension not found in list for the layer, so test the layer name
899            // as if it is an extension name. Use default layer name based on
900            // library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
901            char *pEnd;
902            size_t siz;
903
904            search_name = loader.scanned_layers[j].name;
905            search_name = basename(search_name);
906            search_name += strlen(VK_LAYER_LIBRARY_PREFIX);
907            pEnd = strrchr(search_name, '.');
908            siz = (int) (pEnd - search_name);
909            if (siz != strlen(pExtName))
910                continue;
911
912            if (strncmp(search_name, pExtName, siz) == 0) {
913                found = true;
914                lib_name[found_count] = loader.scanned_layers[j].name;
915                found_count++;
916            }
917        }
918    }
919
920    *out_count = found_count;
921    return found;
922}
923
924static uint32_t loader_get_layer_env(struct layer_name_pair *pLayerNames)
925{
926    char *layerEnv;
927    uint32_t i, len, found_count, count = 0;
928    char *p, *pOrig, *next, *name;
929
930#if defined(WIN32)
931    layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
932                                           LAYER_NAMES_REGISTRY_VALUE);
933#else  // WIN32
934    layerEnv = getenv(LAYER_NAMES_ENV);
935#endif // WIN32
936    if (layerEnv == NULL) {
937        return 0;
938    }
939    p = malloc(strlen(layerEnv) + 1);
940    if (p == NULL) {
941#if defined(WIN32)
942        free(layerEnv);
943#endif // WIN32
944        return 0;
945    }
946    strcpy(p, layerEnv);
947#if defined(WIN32)
948    free(layerEnv);
949#endif // WIN32
950    pOrig = p;
951
952    while (p && *p && count < MAX_LAYER_LIBRARIES) {
953        char *lib_name[MAX_LAYER_LIBRARIES];
954        //memset(&lib_name[0], 0, sizeof(const char *) * MAX_LAYER_LIBRARIES);
955        next = strchr(p, PATH_SEPERATOR);
956        if (next == NULL) {
957            len = (uint32_t) strlen(p);
958            next = p + len;
959        } else {
960            len = (uint32_t) (next - p);
961            *(char *) next = '\0';
962            next++;
963        }
964        name = basename(p);
965        if (!find_layer_extension(name, &found_count, lib_name)) {
966            p = next;
967            continue;
968        }
969
970        for (i = 0; i < found_count; i++) {
971            len = (uint32_t) strlen(name);
972            pLayerNames[count].layer_name = malloc(len + 1);
973            if (!pLayerNames[count].layer_name) {
974                free(pOrig);
975                return count;
976            }
977            strncpy((char *) pLayerNames[count].layer_name, name, len);
978            pLayerNames[count].layer_name[len] = '\0';
979            pLayerNames[count].lib_name = lib_name[i];
980            count++;
981        }
982        p = next;
983
984    }
985
986    free(pOrig);
987    return count;
988}
989
990static uint32_t loader_get_layer_libs(uint32_t ext_count, const char *const* ext_names, struct layer_name_pair **ppLayerNames)
991{
992    static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES];
993    char *lib_name[MAX_LAYER_LIBRARIES];
994    uint32_t found_count, count = 0;
995    bool skip;
996
997    *ppLayerNames =  &layerNames[0];
998    /* Load any layers specified in the environment first */
999    count = loader_get_layer_env(layerNames);
1000
1001    for (uint32_t i = 0; i < ext_count; i++) {
1002        const char *pExtName = ext_names[i];
1003
1004        skip = false;
1005        for (uint32_t j = 0; j < count; j++) {
1006            if (!strcmp(pExtName, layerNames[j].layer_name) ) {
1007                // Extension / Layer already on the list skip it
1008                skip = true;
1009                break;
1010            }
1011        }
1012
1013        if (!skip && find_layer_extension(pExtName, &found_count, lib_name)) {
1014
1015            for (uint32_t j = 0; j < found_count; j++) {
1016                uint32_t len;
1017                len = (uint32_t) strlen(pExtName);
1018
1019
1020                layerNames[count].layer_name = malloc(len + 1);
1021                if (!layerNames[count].layer_name)
1022                    return count;
1023                strncpy((char *) layerNames[count].layer_name, pExtName, len);
1024                layerNames[count].layer_name[len] = '\0';
1025                layerNames[count].lib_name = lib_name[j];
1026                count++;
1027            }
1028        }
1029    }
1030
1031    return count;
1032}
1033
1034//TODO static void loader_deactivate_device_layer(device)
1035
1036static void loader_deactivate_instance_layer(const struct loader_instance *instance)
1037{
1038    struct loader_icd *icd;
1039    struct loader_layers *libs;
1040
1041    for (icd = instance->icds; icd; icd = icd->next) {
1042        if (icd->gpus)
1043            free(icd->gpus);
1044        icd->gpus = NULL;
1045        if (icd->loader_dispatch)
1046            free(icd->loader_dispatch);
1047        icd->loader_dispatch = NULL;
1048        for (uint32_t j = 0; j < icd->gpu_count; j++) {
1049            if (icd->layer_count[j] > 0) {
1050                for (uint32_t i = 0; i < icd->layer_count[j]; i++) {
1051                    libs = &(icd->layer_libs[j][i]);
1052                    if (libs->lib_handle)
1053                        loader_platform_close_library(libs->lib_handle);
1054                    libs->lib_handle = NULL;
1055                }
1056                if (icd->wrappedGpus[j])
1057                    free(icd->wrappedGpus[j]);
1058            }
1059            icd->layer_count[j] = 0;
1060        }
1061        icd->gpu_count = 0;
1062    }
1063
1064    free(instance->wrappedInstance);
1065}
1066
1067uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1068{
1069    uint32_t count;
1070    struct layer_name_pair *pLayerNames;
1071    if (inst == NULL)
1072        return 0;
1073
1074    // NOTE inst is unwrapped at this point in time
1075    VkObject baseObj = (VkObject) inst;
1076    VkObject nextObj = (VkObject) inst;
1077    VkBaseLayerObject *nextInstObj;
1078    PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1079
1080    count = loader_get_layer_libs(inst->extension_count, (const char *const*) inst->extension_names, &pLayerNames);
1081    if (!count)
1082        return 0;
1083    loader_init_instance_layer_libs(inst, pLayerNames, count);
1084
1085    inst->wrappedInstance = malloc(sizeof(VkBaseLayerObject) * count);
1086    if (! inst->wrappedInstance) {
1087        loader_log(VK_DBG_MSG_ERROR, 0, "Failed to malloc Instance objects for layer");
1088        return 0;
1089    }
1090    for (int32_t i = count - 1; i >= 0; i--) {
1091        nextInstObj = (inst->wrappedInstance + i);
1092        nextInstObj->pGPA = nextGPA;
1093        nextInstObj->baseObject = baseObj;
1094        nextInstObj->nextObject = nextObj;
1095        nextObj = (VkObject) nextInstObj;
1096
1097        char funcStr[256];
1098        snprintf(funcStr, 256, "%sGetInstanceProcAddr",inst->layer_libs[i].name);
1099        if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(inst->layer_libs[i].lib_handle, funcStr)) == NULL)
1100            nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(inst->layer_libs[i].lib_handle, "vkGetInstanceProcAddr");
1101        if (!nextGPA) {
1102            loader_log(VK_DBG_MSG_ERROR, 0, "Failed to find vkGetInstanceProcAddr in layer %s", inst->layer_libs[i].name);
1103            continue;
1104        }
1105
1106        if (i == 0) {
1107            loader_init_instance_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj);
1108            //Insert the new wrapped objects into the list with loader object at head
1109            nextInstObj = inst->wrappedInstance + inst->layer_count - 1;
1110            nextInstObj->nextObject = baseObj;
1111            nextInstObj->pGPA = loader_gpa_instance_internal;
1112        }
1113
1114    }
1115
1116    return inst->layer_count;
1117}
1118
1119extern uint32_t loader_activate_device_layers(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names)
1120{
1121    uint32_t count;
1122    VkBaseLayerObject *gpu;
1123    struct layer_name_pair *pLayerNames;
1124    if (!icd)
1125        return 0;
1126    assert(gpu_index < MAX_GPUS_FOR_LAYER);
1127
1128    gpu = icd->gpus + gpu_index;
1129    /* activate any layer libraries */
1130    if (!loader_layers_activated(icd, gpu_index)) {
1131        // Note gpu object is wrapped once already
1132        VkBaseLayerObject *gpuObj = gpu;
1133        VkBaseLayerObject *nextGpuObj, *baseObj = (VkBaseLayerObject *) gpuObj->baseObject;
1134        PFN_vkGetProcAddr nextGPA = loader_gpa_device_internal;
1135
1136        count = loader_get_layer_libs(ext_count, ext_names, &pLayerNames);
1137        if (!count)
1138            return 0;
1139        loader_init_device_layer_libs(icd, gpu_index, pLayerNames, count);
1140
1141        icd->wrappedGpus[gpu_index] = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
1142        if (! icd->wrappedGpus[gpu_index]) {
1143                loader_log(VK_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer");
1144                return 0;
1145        }
1146        for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
1147            nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
1148            nextGpuObj->pGPA = nextGPA;
1149            nextGpuObj->baseObject = (VkObject) baseObj;
1150            nextGpuObj->nextObject = (VkObject) gpuObj;
1151            gpuObj = nextGpuObj;
1152
1153            char funcStr[256];
1154            snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name);
1155            if ((nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
1156                nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, "vkGetProcAddr");
1157            if (!nextGPA) {
1158                loader_log(VK_DBG_MSG_ERROR, 0, "Failed to find vkGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name);
1159                continue;
1160            }
1161
1162            if (i == 0) {
1163                loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, (VkPhysicalDevice) gpuObj);
1164                //Insert the new wrapped objects into the list with loader object at head
1165                gpu->nextObject = (VkObject) gpuObj;
1166                gpu->pGPA = nextGPA;
1167                gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1;
1168                gpuObj->nextObject = (VkObject) baseObj;
1169                gpuObj->pGPA = icd->scanned_icds->GetProcAddr;
1170            }
1171
1172        }
1173    }
1174    else {
1175        //make sure requested Layers matches currently activated Layers
1176        count = loader_get_layer_libs(ext_count, ext_names, &pLayerNames);
1177        for (uint32_t i = 0; i < count; i++) {
1178            if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) {
1179                loader_log(VK_DBG_MSG_ERROR, 0, "Layers activated != Layers requested");
1180                break;
1181            }
1182        }
1183        if (count != icd->layer_count[gpu_index]) {
1184            loader_log(VK_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested");
1185        }
1186    }
1187    return icd->layer_count[gpu_index];
1188}
1189
1190VkResult loader_CreateInstance(
1191        const VkInstanceCreateInfo*         pCreateInfo,
1192        VkInstance*                           pInstance)
1193{
1194    struct loader_instance *ptr_instance = (struct loader_instance *) pInstance;
1195    struct loader_scanned_icds *scanned_icds;
1196    struct loader_icd *icd;
1197    VkResult res;
1198
1199    scanned_icds = loader.scanned_icd_list;
1200    while (scanned_icds) {
1201        icd = loader_icd_add(ptr_instance, scanned_icds);
1202        if (icd) {
1203            res = scanned_icds->CreateInstance(pCreateInfo,
1204                                           &(scanned_icds->instance));
1205            if (res != VK_SUCCESS)
1206            {
1207                ptr_instance->icds = ptr_instance->icds->next;
1208                loader_icd_destroy(icd);
1209                scanned_icds->instance = VK_NULL_HANDLE;
1210                loader_log(VK_DBG_MSG_WARNING, 0,
1211                        "ICD ignored: failed to CreateInstance on device");
1212            }
1213        }
1214        scanned_icds = scanned_icds->next;
1215    }
1216
1217    if (ptr_instance->icds == NULL) {
1218        return VK_ERROR_INCOMPATIBLE_DRIVER;
1219    }
1220
1221    return VK_SUCCESS;
1222}
1223
1224VkResult loader_DestroyInstance(
1225        VkInstance                                instance)
1226{
1227    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1228    struct loader_scanned_icds *scanned_icds;
1229    VkResult res;
1230    uint32_t i;
1231
1232    // Remove this instance from the list of instances:
1233    struct loader_instance *prev = NULL;
1234    struct loader_instance *next = loader.instances;
1235    while (next != NULL) {
1236        if (next == ptr_instance) {
1237            // Remove this instance from the list:
1238            for (i = 0; i < ptr_instance->extension_count; i++) {
1239                free(ptr_instance->extension_names[i]);
1240            }
1241            if (prev)
1242                prev->next = next->next;
1243            else
1244                loader.instances = next->next;
1245            break;
1246        }
1247        prev = next;
1248        next = next->next;
1249    }
1250    if (next  == NULL) {
1251        // This must be an invalid instance handle or empty list
1252        return VK_ERROR_INVALID_HANDLE;
1253    }
1254
1255    loader_deactivate_instance_layer(ptr_instance);
1256
1257    scanned_icds = loader.scanned_icd_list;
1258    while (scanned_icds) {
1259        if (scanned_icds->instance) {
1260            res = scanned_icds->DestroyInstance(scanned_icds->instance);
1261            if (res != VK_SUCCESS)
1262                loader_log(VK_DBG_MSG_WARNING, 0,
1263                            "ICD ignored: failed to DestroyInstance on device");
1264        }
1265        scanned_icds->instance = VK_NULL_HANDLE;
1266        scanned_icds = scanned_icds->next;
1267    }
1268
1269    free(ptr_instance);
1270
1271    return VK_SUCCESS;
1272}
1273
1274VkResult loader_EnumeratePhysicalDevices(
1275        VkInstance                              instance,
1276        uint32_t*                               pPhysicalDeviceCount,
1277        VkPhysicalDevice*                       pPhysicalDevices)
1278{
1279    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1280    struct loader_icd *icd;
1281    uint32_t n, count = 0;
1282    VkResult res = VK_ERROR_UNKNOWN;
1283
1284    //in spirit of VK don't error check on the instance parameter
1285    icd = ptr_instance->icds;
1286    if (pPhysicalDevices == NULL) {
1287        while (icd) {
1288            res = icd->scanned_icds->EnumeratePhysicalDevices(
1289                                                icd->scanned_icds->instance,
1290                                                &n, NULL);
1291            if (res != VK_SUCCESS)
1292                return res;
1293            icd->gpu_count = n;
1294            count += n;
1295            icd = icd->next;
1296        }
1297
1298        ptr_instance->total_gpu_count = count;
1299
1300    } else
1301    {
1302        VkPhysicalDevice* gpus;
1303        if (*pPhysicalDeviceCount < ptr_instance->total_gpu_count)
1304            return VK_ERROR_INVALID_VALUE;
1305        gpus = malloc( sizeof(VkPhysicalDevice) *  *pPhysicalDeviceCount);
1306        if (!gpus)
1307            return VK_ERROR_OUT_OF_HOST_MEMORY;
1308        while (icd) {
1309            VkBaseLayerObject * wrapped_gpus;
1310            PFN_vkGetProcAddr get_proc_addr = icd->scanned_icds->GetProcAddr;
1311
1312            n = *pPhysicalDeviceCount;
1313            res = icd->scanned_icds->EnumeratePhysicalDevices(
1314                                            icd->scanned_icds->instance,
1315                                            &n,
1316                                            gpus);
1317            if (res == VK_SUCCESS && n) {
1318                wrapped_gpus = (VkBaseLayerObject*) malloc(n *
1319                                            sizeof(VkBaseLayerObject));
1320                icd->gpus = wrapped_gpus;
1321                icd->gpu_count = n;
1322                icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
1323                                        sizeof(VkLayerDispatchTable));
1324                for (unsigned int i = 0; i < n; i++) {
1325                    (wrapped_gpus + i)->baseObject = gpus[i];
1326                    (wrapped_gpus + i)->pGPA = get_proc_addr;
1327                    (wrapped_gpus + i)->nextObject = gpus[i];
1328                    memcpy(pPhysicalDevices + count, gpus, sizeof(*pPhysicalDevices));
1329                    loader_init_device_dispatch_table(icd->loader_dispatch + i,
1330                                               get_proc_addr, gpus[i]);
1331
1332                    /* Verify ICD compatibility */
1333                    if (!valid_loader_magic_value(gpus[i])) {
1334                        loader_log(VK_DBG_MSG_WARNING, 0,
1335                            "Loader: Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\n");
1336                        assert(0);
1337                    }
1338
1339                    const VkLayerDispatchTable **disp;
1340                    disp = (const VkLayerDispatchTable **) gpus[i];
1341                    *disp = icd->loader_dispatch + i;
1342                    loader_activate_device_layers(icd, i, ptr_instance->extension_count,
1343                        (const char *const*) ptr_instance->extension_names);
1344                }
1345
1346                count += n;
1347
1348                if (count >= *pPhysicalDeviceCount) {
1349                    break;
1350                }
1351            }
1352
1353            icd = icd->next;
1354        }
1355    }
1356
1357    *pPhysicalDeviceCount = count;
1358
1359    return (count > 0) ? VK_SUCCESS : res;
1360}
1361
1362LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
1363{
1364    if (instance != VK_NULL_HANDLE) {
1365
1366        /* return entrypoint addresses that are global (in the loader)*/
1367        return globalGetProcAddr(pName);
1368    }
1369
1370    return NULL;
1371}
1372
1373LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalDevice gpu, const char * pName)
1374{
1375    if (gpu == VK_NULL_HANDLE) {
1376
1377        /* return entrypoint addresses that are global (in the loader)*/
1378        return globalGetProcAddr(pName);
1379    }
1380
1381    void *addr;
1382
1383    /* for entrypoints that loader must handle (ie non-dispatchable or create object)
1384       make sure the loader entrypoint is returned */
1385    addr = loader_non_passthrough_gpa(pName);
1386    if (addr) {
1387        return addr;
1388    }
1389
1390    /* return the dispatch table entrypoint for the fastest case */
1391    const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) gpu;
1392    if (disp_table == NULL)
1393        return NULL;
1394
1395    addr = loader_lookup_device_dispatch_table(disp_table, pName);
1396    if (addr)
1397        return addr;
1398    else  {
1399        if (disp_table->GetProcAddr == NULL)
1400            return NULL;
1401        return disp_table->GetProcAddr(gpu, pName);
1402    }
1403}
1404
1405//TODO make sure createInstance enables extensions that are valid (loader does)
1406//TODO make sure CreateDevice enables extensions that are valid (left for layers/drivers to do)
1407
1408//TODO how is layer extension going to be enabled?
1409//Need to call createInstance on the layer or something
1410
1411VkResult loader_GetGlobalExtensionInfo(
1412                                               VkExtensionInfoType infoType,
1413                                               uint32_t extensionIndex,
1414                                               size_t*  pDataSize,
1415                                               void*    pData)
1416{
1417    VkExtensionProperties *ext_props;
1418    uint32_t *count;
1419    /* Scan/discover all ICD libraries in a single-threaded manner */
1420    loader_platform_thread_once(&once_icd, loader_icd_scan);
1421
1422    /* get layer libraries in a single-threaded manner */
1423    loader_platform_thread_once(&once_layer, layer_lib_scan);
1424
1425    /* merge any duplicate extensions */
1426    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
1427
1428
1429    if (pDataSize == NULL)
1430        return VK_ERROR_INVALID_POINTER;
1431
1432    switch (infoType) {
1433        case VK_EXTENSION_INFO_TYPE_COUNT:
1434            *pDataSize = sizeof(uint32_t);
1435            if (pData == NULL)
1436                return VK_SUCCESS;
1437            count = (uint32_t *) pData;
1438            *count = loader.scanned_ext_list_count;
1439            break;
1440        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1441            *pDataSize = sizeof(VkExtensionProperties);
1442            if (pData == NULL)
1443                return VK_SUCCESS;
1444            if (extensionIndex >= loader.scanned_ext_list_count)
1445                return VK_ERROR_INVALID_VALUE;
1446            ext_props = (VkExtensionProperties *) pData;
1447            ext_props->version = loader.scanned_ext_list[extensionIndex]->version;
1448            strncpy(ext_props->extName, loader.scanned_ext_list[extensionIndex]->extName
1449                                            , VK_MAX_EXTENSION_NAME);
1450            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
1451            break;
1452        default:
1453            loader_log(VK_DBG_MSG_WARNING, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
1454            return VK_ERROR_INVALID_VALUE;
1455    };
1456
1457    return VK_SUCCESS;
1458}
1459
1460LOADER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalDevice gpu, size_t maxStringSize, size_t* pLayerCount, char* const* pOutLayers, void* pReserved)
1461{
1462    size_t maxLayerCount;
1463    uint32_t gpu_index;
1464    size_t count = 0;
1465    char *lib_name;
1466    struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index);
1467    loader_platform_dl_handle handle;
1468    PFN_vkEnumerateLayers fpEnumerateLayers;
1469    char layer_buf[16][256];
1470    char * layers[16];
1471
1472    if (pLayerCount == NULL || pOutLayers == NULL)
1473        return VK_ERROR_INVALID_POINTER;
1474
1475    maxLayerCount = *pLayerCount;
1476
1477    if (!icd)
1478        return VK_ERROR_UNAVAILABLE;
1479
1480    for (int i = 0; i < 16; i++)
1481         layers[i] = &layer_buf[i][0];
1482
1483    for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
1484        lib_name = loader.scanned_layers[j].name;
1485        // Used to call: dlopen(*lib_name, RTLD_LAZY)
1486        if ((handle = loader_platform_open_library(lib_name)) == NULL)
1487            continue;
1488        if ((fpEnumerateLayers = loader_platform_get_proc_address(handle, "vkEnumerateLayers")) == NULL) {
1489            //use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
1490            char *pEnd, *cpyStr;
1491            size_t siz;
1492            loader_platform_close_library(handle);
1493            lib_name = basename(lib_name);
1494            pEnd = strrchr(lib_name, '.');
1495            siz = (int) (pEnd - lib_name - strlen(VK_LAYER_LIBRARY_PREFIX) + 1);
1496            if (pEnd == NULL || siz <= 0)
1497                continue;
1498            cpyStr = malloc(siz);
1499            if (cpyStr == NULL) {
1500                free(cpyStr);
1501                continue;
1502            }
1503            strncpy(cpyStr, lib_name + strlen(VK_LAYER_LIBRARY_PREFIX), siz);
1504            cpyStr[siz - 1] = '\0';
1505            if (siz > maxStringSize)
1506                siz = (int) maxStringSize;
1507            strncpy((char *) (pOutLayers[count]), cpyStr, siz);
1508            pOutLayers[count][siz - 1] = '\0';
1509            count++;
1510            free(cpyStr);
1511        } else {
1512            size_t cnt = 16; /* only allow 16 layers, for now */
1513            uint32_t n;
1514            VkResult res;
1515            n = (uint32_t) ((maxStringSize < 256) ? maxStringSize : 256);
1516            res = fpEnumerateLayers((VkPhysicalDevice) NULL, n, &cnt, layers, (char *) icd->gpus + gpu_index);
1517            loader_platform_close_library(handle);
1518            if (res != VK_SUCCESS)
1519                continue;
1520            if (cnt + count > maxLayerCount)
1521                cnt = maxLayerCount - count;
1522            for (uint32_t i = (uint32_t) count; i < cnt + count; i++) {
1523                strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n);
1524                if (n > 0)
1525                    pOutLayers[i - count][n - 1] = '\0';
1526            }
1527            count += cnt;
1528        }
1529    }
1530
1531    *pLayerCount = count;
1532
1533    return VK_SUCCESS;
1534}
1535
1536VkResult loader_DbgRegisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData)
1537{
1538    const struct loader_icd *icd;
1539    struct loader_instance *inst;
1540    VkResult res;
1541    uint32_t gpu_idx;
1542
1543    if (instance == VK_NULL_HANDLE)
1544        return VK_ERROR_INVALID_HANDLE;
1545
1546    assert(loader.icds_scanned);
1547
1548    for (inst = loader.instances; inst; inst = inst->next) {
1549        if ((VkInstance) inst == instance)
1550            break;
1551    }
1552
1553    if (inst == VK_NULL_HANDLE)
1554        return VK_ERROR_INVALID_HANDLE;
1555
1556    for (icd = inst->icds; icd; icd = icd->next) {
1557        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1558            res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(icd->scanned_icds->instance,
1559                                                   pfnMsgCallback, pUserData);
1560            if (res != VK_SUCCESS) {
1561                gpu_idx = i;
1562                break;
1563            }
1564        }
1565        if (res != VK_SUCCESS)
1566            break;
1567    }
1568
1569
1570    /* roll back on errors */
1571    if (icd) {
1572        for (const struct loader_icd *tmp = inst->icds; tmp != icd;
1573                                                      tmp = tmp->next) {
1574            for (uint32_t i = 0; i < icd->gpu_count; i++)
1575                (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(tmp->scanned_icds->instance, pfnMsgCallback);
1576        }
1577        /* and gpus on current icd */
1578        for (uint32_t i = 0; i < gpu_idx; i++)
1579            (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback);
1580
1581        return res;
1582    }
1583
1584    return VK_SUCCESS;
1585}
1586
1587VkResult loader_DbgUnregisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback)
1588{
1589    VkResult res = VK_SUCCESS;
1590    struct loader_instance *inst;
1591    if (instance == VK_NULL_HANDLE)
1592        return VK_ERROR_INVALID_HANDLE;
1593
1594    assert(loader.icds_scanned);
1595
1596    for (inst = loader.instances; inst; inst = inst->next) {
1597        if ((VkInstance) inst == instance)
1598            break;
1599    }
1600
1601    if (inst == VK_NULL_HANDLE)
1602        return VK_ERROR_INVALID_HANDLE;
1603
1604    for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) {
1605        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1606            VkResult r;
1607            r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback);
1608            if (r != VK_SUCCESS) {
1609                res = r;
1610            }
1611        }
1612    }
1613    return res;
1614}
1615
1616VkResult loader_DbgSetGlobalOption(VkInstance instance, VK_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData)
1617{
1618    VkResult res = VK_SUCCESS;
1619    struct loader_instance *inst;
1620    if (instance == VK_NULL_HANDLE)
1621        return VK_ERROR_INVALID_HANDLE;
1622
1623    assert(loader.icds_scanned);
1624
1625    for (inst = loader.instances; inst; inst = inst->next) {
1626        if ((VkInstance) inst == instance)
1627            break;
1628    }
1629
1630    if (inst == VK_NULL_HANDLE)
1631        return VK_ERROR_INVALID_HANDLE;
1632    for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) {
1633        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1634            VkResult r;
1635            r = (icd->loader_dispatch + i)->DbgSetGlobalOption(icd->scanned_icds->instance, dbgOption,
1636                                                           dataSize, pData);
1637            /* unfortunately we cannot roll back */
1638            if (r != VK_SUCCESS) {
1639               res = r;
1640            }
1641        }
1642    }
1643
1644    return res;
1645}
1646