loader.c revision 301c5f0be9ee48bb48c80ded9faad2ea3efc33f1
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 "table_ops.h"
45#include "loader.h"
46#include "vkIcd.h"
47// The following is #included again to catch certain OS-specific functions
48// being used:
49#include "loader_platform.h"
50
51struct loader_layers {
52    loader_platform_dl_handle lib_handle;
53    char name[256];
54};
55
56struct layer_name_pair {
57    char *layer_name;
58    const char *lib_name;
59};
60
61struct loader_icd {
62    const struct loader_scanned_icds *scanned_icds;
63
64    VkLayerDispatchTable *loader_dispatch;
65    uint32_t layer_count[VK_MAX_PHYSICAL_GPUS];
66    struct loader_layers layer_libs[VK_MAX_PHYSICAL_GPUS][MAX_LAYER_LIBRARIES];
67    VkBaseLayerObject *wrappedGpus[VK_MAX_PHYSICAL_GPUS];
68    uint32_t gpu_count;
69    VkBaseLayerObject *gpus;
70
71    struct loader_icd *next;
72};
73
74
75struct loader_scanned_icds {
76    loader_platform_dl_handle handle;
77    PFN_vkGetProcAddr GetProcAddr;
78    PFN_vkCreateInstance CreateInstance;
79    PFN_vkDestroyInstance DestroyInstance;
80    PFN_vkEnumerateGpus EnumerateGpus;
81    PFN_vkGetExtensionSupport GetExtensionSupport;
82    VkInstance instance;
83    struct loader_scanned_icds *next;
84};
85
86// Note: Since the following is a static structure, all members are initialized
87// to zero.
88static struct {
89    struct loader_instance *instances;
90    bool icds_scanned;
91    struct loader_scanned_icds *scanned_icd_list;
92    bool layer_scanned;
93    char *layer_dirs;
94    unsigned int scanned_layer_count;
95    char *scanned_layer_names[MAX_LAYER_LIBRARIES];
96} loader;
97
98
99#if defined(WIN32)
100char *loader_get_registry_string(const HKEY hive,
101                                 const LPCTSTR sub_key,
102                                 const char *value)
103{
104    DWORD access_flags = KEY_QUERY_VALUE;
105    DWORD value_type;
106    HKEY key;
107    LONG  rtn_value;
108    char *rtn_str = NULL;
109    size_t rtn_len = 0;
110    size_t allocated_len = 0;
111
112    rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
113    if (rtn_value != ERROR_SUCCESS) {
114        // We didn't find the key.  Try the 32-bit hive (where we've seen the
115        // key end up on some people's systems):
116        access_flags |= KEY_WOW64_32KEY;
117        rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
118        if (rtn_value != ERROR_SUCCESS) {
119            // We still couldn't find the key, so give up:
120            return NULL;
121        }
122    }
123
124    rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
125                                (PVOID) rtn_str, &rtn_len);
126    if (rtn_value == ERROR_SUCCESS) {
127        // If we get to here, we found the key, and need to allocate memory
128        // large enough for rtn_str, and query again:
129        allocated_len = rtn_len + 4;
130        rtn_str = malloc(allocated_len);
131        rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
132                                    (PVOID) rtn_str, &rtn_len);
133        if (rtn_value == ERROR_SUCCESS) {
134            // We added 4 extra bytes to rtn_str, so that we can ensure that
135            // the string is NULL-terminated (albeit, in a brute-force manner):
136            rtn_str[allocated_len-1] = '\0';
137        } else {
138            // This should never occur, but in case it does, clean up:
139            free(rtn_str);
140            rtn_str = NULL;
141        }
142    } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
143
144    // Close the registry key that was opened:
145    RegCloseKey(key);
146
147    return rtn_str;
148}
149
150
151// For ICD developers, look in the registry, and look for an environment
152// variable for a path(s) where to find the ICD(s):
153static char *loader_get_registry_and_env(const char *env_var,
154                                         const char *registry_value)
155{
156    char *env_str = getenv(env_var);
157    size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
158    char *registry_str = NULL;
159    DWORD registry_len = 0;
160    char *rtn_str = NULL;
161    size_t rtn_len;
162
163    registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
164                                              "Software\\Vulkan",
165                                              registry_value);
166    registry_len = (registry_str) ? strlen(registry_str) : 0;
167
168    rtn_len = env_len + registry_len + 1;
169    if (rtn_len <= 2) {
170        // We found neither the desired registry value, nor the environment
171        // variable; return NULL:
172        return NULL;
173    } else {
174        // We found something, and so we need to allocate memory for the string
175        // to return:
176        rtn_str = malloc(rtn_len);
177    }
178
179    if (registry_len == 0) {
180        // We didn't find the desired registry value, and so we must have found
181        // only the environment variable:
182        _snprintf(rtn_str, rtn_len, "%s", env_str);
183    } else if (env_str != NULL) {
184        // We found both the desired registry value and the environment
185        // variable, so concatenate them both:
186        _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
187    } else {
188        // We must have only found the desired registry value:
189        _snprintf(rtn_str, rtn_len, "%s", registry_str);
190    }
191
192    if (registry_str) {
193      free(registry_str);
194    }
195
196    return(rtn_str);
197}
198#endif // WIN32
199
200
201static void loader_log(VK_DBG_MSG_TYPE msg_type, int32_t msg_code,
202                       const char *format, ...)
203{
204    char msg[256];
205    va_list ap;
206    int ret;
207
208    va_start(ap, format);
209    ret = vsnprintf(msg, sizeof(msg), format, ap);
210    if ((ret >= (int) sizeof(msg)) || ret < 0) {
211        msg[sizeof(msg) - 1] = '\0';
212    }
213    va_end(ap);
214
215    fputs(msg, stderr);
216    fputc('\n', stderr);
217}
218
219static void
220loader_icd_destroy(struct loader_icd *icd)
221{
222    loader_platform_close_library(icd->scanned_icds->handle);
223    free(icd);
224}
225
226static struct loader_icd *
227loader_icd_create(const struct loader_scanned_icds *scanned)
228{
229    struct loader_icd *icd;
230
231    icd = malloc(sizeof(*icd));
232    if (!icd)
233        return NULL;
234
235    memset(icd, 0, sizeof(*icd));
236
237    icd->scanned_icds = scanned;
238
239    return icd;
240}
241
242static struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst,
243                                     const struct loader_scanned_icds *scanned)
244{
245    struct loader_icd *icd;
246
247    icd = loader_icd_create(scanned);
248    if (!icd)
249        return NULL;
250
251    /* prepend to the list */
252    icd->next = ptr_inst->icds;
253    ptr_inst->icds = icd;
254
255    return icd;
256}
257
258static void loader_scanned_icd_add(const char *filename)
259{
260    loader_platform_dl_handle handle;
261    void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst, *fp_get_extension_support;
262    struct loader_scanned_icds *new_node;
263
264    // Used to call: dlopen(filename, RTLD_LAZY);
265    handle = loader_platform_open_library(filename);
266    if (!handle) {
267        loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_open_library_error(filename));
268        return;
269    }
270
271#define LOOKUP(func_ptr, func) do {                            \
272    func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
273    if (!func_ptr) {                                           \
274        loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_get_proc_address_error("vk" #func)); \
275        return;                                                \
276    }                                                          \
277} while (0)
278
279    LOOKUP(fp_gpa, GetProcAddr);
280    LOOKUP(fp_create_inst, CreateInstance);
281    LOOKUP(fp_destroy_inst, DestroyInstance);
282    LOOKUP(fp_enumerate, EnumerateGpus);
283    LOOKUP(fp_get_extension_support, GetExtensionSupport);
284#undef LOOKUP
285
286    new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds));
287    if (!new_node) {
288        loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory can't add icd");
289        return;
290    }
291
292    new_node->handle = handle;
293    new_node->GetProcAddr = fp_gpa;
294    new_node->CreateInstance = fp_create_inst;
295    new_node->DestroyInstance = fp_destroy_inst;
296    new_node->EnumerateGpus = fp_enumerate;
297    new_node->GetExtensionSupport = fp_get_extension_support;
298    new_node->next = loader.scanned_icd_list;
299    loader.scanned_icd_list = new_node;
300}
301
302
303/**
304 * Try to \c loader_icd_scan VK driver(s).
305 *
306 * This function scans the default system path or path
307 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
308 * order to find loadable VK ICDs with the name of libVK_*.
309 *
310 * \returns
311 * void; but side effect is to set loader_icd_scanned to true
312 */
313static void loader_icd_scan(void)
314{
315    const char *p, *next;
316    char *libPaths = NULL;
317    DIR *sysdir;
318    struct dirent *dent;
319    char icd_library[1024];
320    char path[1024];
321    uint32_t len;
322#if defined(WIN32)
323    bool must_free_libPaths;
324    libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
325                                           DRIVER_PATH_REGISTRY_VALUE);
326    if (libPaths != NULL) {
327        must_free_libPaths = true;
328    } else {
329        must_free_libPaths = false;
330        libPaths = DEFAULT_VK_DRIVERS_PATH;
331    }
332#else  // WIN32
333    if (geteuid() == getuid()) {
334        /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
335        libPaths = getenv(DRIVER_PATH_ENV);
336    }
337    if (libPaths == NULL) {
338        libPaths = DEFAULT_VK_DRIVERS_PATH;
339    }
340#endif // WIN32
341
342    for (p = libPaths; *p; p = next) {
343       next = strchr(p, PATH_SEPERATOR);
344       if (next == NULL) {
345          len = (uint32_t) strlen(p);
346          next = p + len;
347       }
348       else {
349          len = (uint32_t) (next - p);
350          sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
351          p = path;
352          next++;
353       }
354
355       // TODO/TBD: Do we want to do this on Windows, or just let Windows take
356       // care of its own search path (which it apparently has)?
357       sysdir = opendir(p);
358       if (sysdir) {
359          dent = readdir(sysdir);
360          while (dent) {
361             /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
362              * ending with VK_LIBRARY_SUFFIX
363              */
364              if (!strncmp(dent->d_name,
365                          VK_DRIVER_LIBRARY_PREFIX,
366                          VK_DRIVER_LIBRARY_PREFIX_LEN)) {
367                 uint32_t nlen = (uint32_t) strlen(dent->d_name);
368                 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
369                 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
370                     !strncmp(suf,
371                              VK_LIBRARY_SUFFIX,
372                              VK_LIBRARY_SUFFIX_LEN)) {
373                    snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
374                    loader_scanned_icd_add(icd_library);
375                 }
376              }
377
378             dent = readdir(sysdir);
379          }
380          closedir(sysdir);
381       }
382    }
383
384#if defined(WIN32)
385    // Free any allocated memory:
386    if (must_free_libPaths) {
387        free(libPaths);
388    }
389#endif // WIN32
390
391    // Note that we've scanned for ICDs:
392    loader.icds_scanned = true;
393}
394
395
396static void layer_lib_scan(void)
397{
398    const char *p, *next;
399    char *libPaths = NULL;
400    DIR *curdir;
401    struct dirent *dent;
402    size_t len, i;
403    char temp_str[1024];
404
405#if defined(WIN32)
406    bool must_free_libPaths;
407    libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
408                                           LAYERS_PATH_REGISTRY_VALUE);
409    if (libPaths != NULL) {
410        must_free_libPaths = true;
411    } else {
412        must_free_libPaths = false;
413        libPaths = DEFAULT_VK_LAYERS_PATH;
414    }
415#else  // WIN32
416    if (geteuid() == getuid()) {
417        /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
418        libPaths = getenv(LAYERS_PATH_ENV);
419    }
420    if (libPaths == NULL) {
421        libPaths = DEFAULT_VK_LAYERS_PATH;
422    }
423#endif // WIN32
424
425    if (libPaths == NULL) {
426        // Have no paths to search:
427        return;
428    }
429    len = strlen(libPaths);
430    loader.layer_dirs = malloc(len+1);
431    if (loader.layer_dirs == NULL) {
432        free(libPaths);
433        return;
434    }
435    // Alloc passed, so we know there is enough space to hold the string, don't
436    // need strncpy
437    strcpy(loader.layer_dirs, libPaths);
438#if defined(WIN32)
439    // Free any allocated memory:
440    if (must_free_libPaths) {
441        free(libPaths);
442        must_free_libPaths = false;
443    }
444#endif // WIN32
445    libPaths = loader.layer_dirs;
446
447    /* cleanup any previously scanned libraries */
448    for (i = 0; i < loader.scanned_layer_count; i++) {
449        if (loader.scanned_layer_names[i] != NULL)
450            free(loader.scanned_layer_names[i]);
451        loader.scanned_layer_names[i] = NULL;
452    }
453    loader.scanned_layer_count = 0;
454
455    for (p = libPaths; *p; p = next) {
456       next = strchr(p, PATH_SEPERATOR);
457       if (next == NULL) {
458          len = (uint32_t) strlen(p);
459          next = p + len;
460       }
461       else {
462          len = (uint32_t) (next - p);
463          *(char *) next = '\0';
464          next++;
465       }
466
467       curdir = opendir(p);
468       if (curdir) {
469          dent = readdir(curdir);
470          while (dent) {
471             /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
472              * ending with VK_LIBRARY_SUFFIX
473              */
474              if (!strncmp(dent->d_name,
475                          VK_LAYER_LIBRARY_PREFIX,
476                          VK_LAYER_LIBRARY_PREFIX_LEN)) {
477                 uint32_t nlen = (uint32_t) strlen(dent->d_name);
478                 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
479                 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
480                     !strncmp(suf,
481                              VK_LIBRARY_SUFFIX,
482                              VK_LIBRARY_SUFFIX_LEN)) {
483                     loader_platform_dl_handle handle;
484                     snprintf(temp_str, sizeof(temp_str), "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
485                     // Used to call: dlopen(temp_str, RTLD_LAZY)
486                     if ((handle = loader_platform_open_library(temp_str)) == NULL) {
487                         dent = readdir(curdir);
488                         continue;
489                     }
490                     if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
491                         loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
492                         break;
493                     }
494                     if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
495                         loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
496                         break;
497                     }
498                     strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
499                     loader.scanned_layer_count++;
500                     loader_platform_close_library(handle);
501                 }
502             }
503
504             dent = readdir(curdir);
505          }
506          closedir(curdir);
507       }
508    }
509
510    loader.layer_scanned = true;
511}
512
513static void loader_init_dispatch_table(VkLayerDispatchTable *tab, PFN_vkGetProcAddr fpGPA, VkPhysicalGpu gpu)
514{
515    loader_initialize_dispatch_table(tab, fpGPA, gpu);
516
517    if (tab->EnumerateLayers == NULL)
518        tab->EnumerateLayers = vkEnumerateLayers;
519}
520
521extern struct loader_icd * loader_get_icd(const VkBaseLayerObject *gpu, uint32_t *gpu_index)
522{
523    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
524        for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
525            for (uint32_t i = 0; i < icd->gpu_count; i++)
526                if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject ==
527                                                            gpu->baseObject) {
528                    *gpu_index = i;
529                    return icd;
530                }
531        }
532    }
533    return NULL;
534}
535
536static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
537{
538    if (icd->layer_count[gpu_index])
539        return true;
540    else
541        return false;
542}
543
544static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair * pLayerNames, uint32_t count)
545{
546    if (!icd)
547        return;
548
549    struct loader_layers *obj;
550    bool foundLib;
551    for (uint32_t i = 0; i < count; i++) {
552        foundLib = false;
553        for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) {
554            if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) {
555                foundLib = true;
556                break;
557            }
558        }
559        if (!foundLib) {
560            obj = &(icd->layer_libs[gpu_index][i]);
561            strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
562            obj->name[sizeof(obj->name) - 1] = '\0';
563            // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)
564            if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) {
565                loader_log(VK_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name));
566                continue;
567            } else {
568                loader_log(VK_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name);
569            }
570            free(pLayerNames[i].layer_name);
571            icd->layer_count[gpu_index]++;
572        }
573    }
574}
575
576static VkResult find_layer_extension(struct loader_icd *icd, uint32_t gpu_index, const char *pExtName, const char **lib_name)
577{
578    VkResult err;
579    char *search_name;
580    loader_platform_dl_handle handle;
581    PFN_vkGetExtensionSupport fpGetExtensionSupport;
582
583    /*
584     * The loader provides the abstraction that make layers and extensions work via
585     * the currently defined extension mechanism. That is, when app queries for an extension
586     * via vkGetExtensionSupport, the loader will call both the driver as well as any layers
587     * to see who implements that extension. Then, if the app enables the extension during
588     * vkCreateDevice the loader will find and load any layers that implement that extension.
589     */
590
591    // TODO: What if extension is in multiple places?
592
593    // TODO: Who should we ask first? Driver or layers? Do driver for now.
594    err = icd->scanned_icds[gpu_index].GetExtensionSupport((VkPhysicalGpu) (icd->gpus[gpu_index].nextObject), pExtName);
595    if (err == VK_SUCCESS) {
596        if (lib_name) {
597            *lib_name = NULL;
598        }
599        return VK_SUCCESS;
600    }
601
602    for (unsigned int j = 0; j < loader.scanned_layer_count; j++) {
603        search_name = loader.scanned_layer_names[j];
604
605        if ((handle = loader_platform_open_library(search_name)) == NULL)
606            continue;
607
608        fpGetExtensionSupport = loader_platform_get_proc_address(handle, "vkGetExtensionSupport");
609
610        if (fpGetExtensionSupport != NULL) {
611            // Found layer's GetExtensionSupport call
612            err = fpGetExtensionSupport((VkPhysicalGpu) (icd->gpus + gpu_index), pExtName);
613
614            loader_platform_close_library(handle);
615
616            if (err == VK_SUCCESS) {
617                if (lib_name) {
618                    *lib_name = loader.scanned_layer_names[j];
619                }
620                return VK_SUCCESS;
621            }
622        } else {
623            loader_platform_close_library(handle);
624        }
625
626        // No GetExtensionSupport or GetExtensionSupport returned invalid extension
627        // for the layer, so test the layer name as if it is an extension name
628        // use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
629        char *pEnd;
630        size_t siz;
631
632        search_name = basename(search_name);
633        search_name += strlen(VK_LAYER_LIBRARY_PREFIX);
634        pEnd = strrchr(search_name, '.');
635        siz = (int) (pEnd - search_name);
636        if (siz != strlen(pExtName))
637            continue;
638
639        if (strncmp(search_name, pExtName, siz) == 0) {
640            if (lib_name) {
641                *lib_name = loader.scanned_layer_names[j];
642            }
643            return VK_SUCCESS;
644        }
645    }
646    return VK_ERROR_INVALID_EXTENSION;
647}
648
649static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames)
650{
651    char *layerEnv;
652    uint32_t len, count = 0;
653    char *p, *pOrig, *next, *name;
654
655#if defined(WIN32)
656    layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
657                                           LAYER_NAMES_REGISTRY_VALUE);
658#else  // WIN32
659    layerEnv = getenv(LAYER_NAMES_ENV);
660#endif // WIN32
661    if (layerEnv == NULL) {
662        return 0;
663    }
664    p = malloc(strlen(layerEnv) + 1);
665    if (p == NULL) {
666#if defined(WIN32)
667        free(layerEnv);
668#endif // WIN32
669        return 0;
670    }
671    strcpy(p, layerEnv);
672#if defined(WIN32)
673    free(layerEnv);
674#endif // WIN32
675    pOrig = p;
676
677    while (p && *p && count < MAX_LAYER_LIBRARIES) {
678        const char *lib_name = NULL;
679        next = strchr(p, PATH_SEPERATOR);
680        if (next == NULL) {
681            len = (uint32_t) strlen(p);
682            next = p + len;
683        } else {
684            len = (uint32_t) (next - p);
685            *(char *) next = '\0';
686            next++;
687        }
688        name = basename(p);
689        if (find_layer_extension(icd, gpu_index, name, &lib_name) != VK_SUCCESS) {
690            p = next;
691            continue;
692        }
693
694        len = (uint32_t) strlen(name);
695        pLayerNames[count].layer_name = malloc(len + 1);
696        if (!pLayerNames[count].layer_name) {
697            free(pOrig);
698            return count;
699        }
700        strncpy((char *) pLayerNames[count].layer_name, name, len);
701        pLayerNames[count].layer_name[len] = '\0';
702        pLayerNames[count].lib_name = lib_name;
703        count++;
704        p = next;
705
706    }
707
708    free(pOrig);
709    return count;
710}
711
712static uint32_t loader_get_layer_libs(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names, struct layer_name_pair **ppLayerNames)
713{
714    static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES];
715    const char *lib_name = NULL;
716    uint32_t count = 0;
717
718    *ppLayerNames =  &layerNames[0];
719    /* Load any layers specified in the environment first */
720    count = loader_get_layer_env(icd, gpu_index, layerNames);
721
722    for (uint32_t i = 0; i < ext_count; i++) {
723        const char *pExtName = ext_names[i];
724
725        if (find_layer_extension(icd, gpu_index, pExtName, &lib_name) == VK_SUCCESS) {
726            uint32_t len;
727
728            /*
729             * the library name is NULL if the driver supports this
730             * extension and thus no layer to load.
731             */
732            if (lib_name == NULL)
733                continue;
734
735            len = (uint32_t) strlen(pExtName);
736            for (uint32_t j = 0; j < count; j++) {
737                if (len == strlen(layerNames[j].layer_name) &&
738                     strncmp(pExtName, layerNames[j].layer_name, len) == 0) {
739                    // Extension / Layer already on the list
740                    continue;
741                }
742            }
743
744            layerNames[count].layer_name = malloc(len + 1);
745            if (!layerNames[count].layer_name)
746                return count;
747            strncpy((char *) layerNames[count].layer_name, pExtName, len);
748            layerNames[count].layer_name[len] = '\0';
749            layerNames[count].lib_name = lib_name;
750            count++;
751        }
752    }
753
754    return count;
755}
756
757static void loader_deactivate_layer(const struct loader_instance *instance)
758{
759    struct loader_icd *icd;
760    struct loader_layers *libs;
761
762    for (icd = instance->icds; icd; icd = icd->next) {
763        if (icd->gpus)
764            free(icd->gpus);
765        icd->gpus = NULL;
766        if (icd->loader_dispatch)
767            free(icd->loader_dispatch);
768        icd->loader_dispatch = NULL;
769        for (uint32_t j = 0; j < icd->gpu_count; j++) {
770            if (icd->layer_count[j] > 0) {
771                for (uint32_t i = 0; i < icd->layer_count[j]; i++) {
772                    libs = &(icd->layer_libs[j][i]);
773                    if (libs->lib_handle)
774                        loader_platform_close_library(libs->lib_handle);
775                    libs->lib_handle = NULL;
776                }
777                if (icd->wrappedGpus[j])
778                    free(icd->wrappedGpus[j]);
779            }
780            icd->layer_count[j] = 0;
781        }
782        icd->gpu_count = 0;
783    }
784}
785
786extern uint32_t loader_activate_layers(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names)
787{
788    uint32_t count;
789    VkBaseLayerObject *gpu;
790    struct layer_name_pair *pLayerNames;
791    if (!icd)
792        return 0;
793    assert(gpu_index < VK_MAX_PHYSICAL_GPUS);
794
795    gpu = icd->gpus + gpu_index;
796    /* activate any layer libraries */
797    if (!loader_layers_activated(icd, gpu_index)) {
798        VkBaseLayerObject *gpuObj = gpu;
799        VkBaseLayerObject *nextGpuObj, *baseObj = gpuObj->baseObject;
800        PFN_vkGetProcAddr nextGPA = vkGetProcAddr;
801
802        count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames);
803        if (!count)
804            return 0;
805        loader_init_layer_libs(icd, gpu_index, pLayerNames, count);
806
807        icd->wrappedGpus[gpu_index] = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
808        if (! icd->wrappedGpus[gpu_index])
809                loader_log(VK_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer");
810        for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
811            nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
812            nextGpuObj->pGPA = nextGPA;
813            nextGpuObj->baseObject = baseObj;
814            nextGpuObj->nextObject = gpuObj;
815            gpuObj = nextGpuObj;
816
817            char funcStr[256];
818            snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name);
819            if ((nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
820                nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, "vkGetProcAddr");
821            if (!nextGPA) {
822                loader_log(VK_DBG_MSG_ERROR, 0, "Failed to find vkGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name);
823                continue;
824            }
825
826            if (i == 0) {
827                loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj);
828                //Insert the new wrapped objects into the list with loader object at head
829                gpu->nextObject = gpuObj;
830                gpu->pGPA = nextGPA;
831                gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1;
832                gpuObj->nextObject = baseObj;
833                gpuObj->pGPA = icd->scanned_icds->GetProcAddr;
834            }
835
836        }
837    }
838    else {
839        //make sure requested Layers matches currently activated Layers
840        count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames);
841        for (uint32_t i = 0; i < count; i++) {
842            if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) {
843                loader_log(VK_DBG_MSG_ERROR, 0, "Layers activated != Layers requested");
844                break;
845            }
846        }
847        if (count != icd->layer_count[gpu_index]) {
848            loader_log(VK_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested");
849        }
850    }
851    return icd->layer_count[gpu_index];
852}
853
854LOADER_EXPORT VkResult VKAPI vkCreateInstance(
855        const VkInstanceCreateInfo*         pCreateInfo,
856        VkInstance*                           pInstance)
857{
858    static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
859    static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
860    struct loader_instance *ptr_instance = NULL;
861    struct loader_scanned_icds *scanned_icds;
862    struct loader_icd *icd;
863    VkResult res = VK_ERROR_INITIALIZATION_FAILED;
864    uint32_t i;
865
866    /* Scan/discover all ICD libraries in a single-threaded manner */
867    loader_platform_thread_once(&once_icd, loader_icd_scan);
868
869    /* get layer libraries in a single-threaded manner */
870    loader_platform_thread_once(&once_layer, layer_lib_scan);
871
872    ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance));
873    if (ptr_instance == NULL) {
874        return VK_ERROR_OUT_OF_MEMORY;
875    }
876    memset(ptr_instance, 0, sizeof(struct loader_instance));
877    ptr_instance->extension_count = pCreateInfo->extensionCount;
878    ptr_instance->extension_names = (ptr_instance->extension_count > 0) ?
879                malloc(sizeof (char *) * ptr_instance->extension_count) : NULL;
880    for (i = 0; i < ptr_instance->extension_count; i++) {
881        ptr_instance->extension_names[i] = malloc(strlen(pCreateInfo->ppEnabledExtensionNames[i] + 1));
882        if (ptr_instance->extension_names[i] == NULL)
883            return VK_ERROR_OUT_OF_MEMORY;
884        strcpy(ptr_instance->extension_names[i], pCreateInfo->ppEnabledExtensionNames[i]);
885    }
886    ptr_instance->next = loader.instances;
887    loader.instances = ptr_instance;
888
889    scanned_icds = loader.scanned_icd_list;
890    while (scanned_icds) {
891        icd = loader_icd_add(ptr_instance, scanned_icds);
892        if (icd) {
893            res = scanned_icds->CreateInstance(pCreateInfo,
894                                           &(scanned_icds->instance));
895            if (res != VK_SUCCESS)
896            {
897                ptr_instance->icds = ptr_instance->icds->next;
898                loader_icd_destroy(icd);
899                scanned_icds->instance = NULL;
900                loader_log(VK_DBG_MSG_WARNING, 0,
901                        "ICD ignored: failed to CreateInstance on device");
902            }
903        }
904        scanned_icds = scanned_icds->next;
905    }
906
907    if (ptr_instance->icds == NULL) {
908        return VK_ERROR_INCOMPATIBLE_DRIVER;
909    }
910
911    *pInstance = (VkInstance) ptr_instance;
912    return VK_SUCCESS;
913}
914
915LOADER_EXPORT VkResult VKAPI vkDestroyInstance(
916        VkInstance                                instance)
917{
918    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
919    struct loader_scanned_icds *scanned_icds;
920    VkResult res;
921    uint32_t i;
922
923    // Remove this instance from the list of instances:
924    struct loader_instance *prev = NULL;
925    struct loader_instance *next = loader.instances;
926    while (next != NULL) {
927        if (next == ptr_instance) {
928            // Remove this instance from the list:
929            for (i = 0; i < ptr_instance->extension_count; i++) {
930                free(ptr_instance->extension_names[i]);
931            }
932            if (prev)
933                prev->next = next->next;
934            else
935                loader.instances = next->next;
936            break;
937        }
938        prev = next;
939        next = next->next;
940    }
941    if (next  == NULL) {
942        // This must be an invalid instance handle or empty list
943        return VK_ERROR_INVALID_HANDLE;
944    }
945
946    // cleanup any prior layer initializations
947    loader_deactivate_layer(ptr_instance);
948
949    scanned_icds = loader.scanned_icd_list;
950    while (scanned_icds) {
951        if (scanned_icds->instance)
952            res = scanned_icds->DestroyInstance(scanned_icds->instance);
953        if (res != VK_SUCCESS)
954            loader_log(VK_DBG_MSG_WARNING, 0,
955                        "ICD ignored: failed to DestroyInstance on device");
956        scanned_icds->instance = NULL;
957        scanned_icds = scanned_icds->next;
958    }
959
960    free(ptr_instance);
961
962    return VK_SUCCESS;
963}
964
965LOADER_EXPORT VkResult VKAPI vkEnumerateGpus(
966
967        VkInstance                                instance,
968        uint32_t                                    maxGpus,
969        uint32_t*                                   pGpuCount,
970        VkPhysicalGpu*                           pGpus)
971{
972    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
973    struct loader_icd *icd;
974    uint32_t count = 0;
975    VkResult res;
976
977    //in spirit of VK don't error check on the instance parameter
978    icd = ptr_instance->icds;
979    while (icd) {
980        VkPhysicalGpu gpus[VK_MAX_PHYSICAL_GPUS];
981        VkBaseLayerObject * wrapped_gpus;
982        PFN_vkGetProcAddr get_proc_addr = icd->scanned_icds->GetProcAddr;
983        uint32_t n, max = maxGpus - count;
984
985        if (max > VK_MAX_PHYSICAL_GPUS) {
986            max = VK_MAX_PHYSICAL_GPUS;
987        }
988
989        res = icd->scanned_icds->EnumerateGpus(icd->scanned_icds->instance,
990                                               max, &n,
991                                               gpus);
992        if (res == VK_SUCCESS && n) {
993            wrapped_gpus = (VkBaseLayerObject*) malloc(n *
994                                        sizeof(VkBaseLayerObject));
995            icd->gpus = wrapped_gpus;
996            icd->gpu_count = n;
997            icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
998                                        sizeof(VkLayerDispatchTable));
999            for (unsigned int i = 0; i < n; i++) {
1000                (wrapped_gpus + i)->baseObject = gpus[i];
1001                (wrapped_gpus + i)->pGPA = get_proc_addr;
1002                (wrapped_gpus + i)->nextObject = gpus[i];
1003                memcpy(pGpus + count, &wrapped_gpus, sizeof(*pGpus));
1004                loader_init_dispatch_table(icd->loader_dispatch + i,
1005                                           get_proc_addr, gpus[i]);
1006
1007                /* Verify ICD compatibility */
1008                if (!valid_loader_magic_value(gpus[i])) {
1009                    loader_log(VK_DBG_MSG_WARNING, 0,
1010                            "Loader: Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\n");
1011                    assert(0);
1012                }
1013
1014                const VkLayerDispatchTable **disp;
1015                disp = (const VkLayerDispatchTable **) gpus[i];
1016                *disp = icd->loader_dispatch + i;
1017            }
1018
1019            count += n;
1020
1021            if (count >= maxGpus) {
1022                break;
1023            }
1024        }
1025
1026        icd = icd->next;
1027    }
1028
1029    *pGpuCount = count;
1030
1031    return (count > 0) ? VK_SUCCESS : res;
1032}
1033
1034LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char * pName)
1035{
1036    if (gpu == NULL) {
1037        return NULL;
1038    }
1039    VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
1040    VkLayerDispatchTable * disp_table = * (VkLayerDispatchTable **) gpuw->baseObject;
1041    void *addr;
1042
1043    if (disp_table == NULL)
1044        return NULL;
1045
1046    addr = loader_lookup_dispatch_table(disp_table, pName);
1047    if (addr)
1048        return addr;
1049    else  {
1050        if (disp_table->GetProcAddr == NULL)
1051            return NULL;
1052        return disp_table->GetProcAddr(gpuw->nextObject, pName);
1053    }
1054}
1055
1056LOADER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char *pExtName)
1057{
1058    uint32_t gpu_index;
1059    struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index);
1060
1061    if (!icd)
1062        return VK_ERROR_UNAVAILABLE;
1063
1064    return find_layer_extension(icd, gpu_index, pExtName, NULL);
1065}
1066
1067LOADER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
1068{
1069    uint32_t gpu_index;
1070    size_t count = 0;
1071    char *lib_name;
1072    struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index);
1073    loader_platform_dl_handle handle;
1074    PFN_vkEnumerateLayers fpEnumerateLayers;
1075    char layer_buf[16][256];
1076    char * layers[16];
1077
1078    if (pOutLayerCount == NULL || pOutLayers == NULL)
1079        return VK_ERROR_INVALID_POINTER;
1080
1081    if (!icd)
1082        return VK_ERROR_UNAVAILABLE;
1083
1084    for (int i = 0; i < 16; i++)
1085         layers[i] = &layer_buf[i][0];
1086
1087    for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
1088        lib_name = loader.scanned_layer_names[j];
1089        // Used to call: dlopen(*lib_name, RTLD_LAZY)
1090        if ((handle = loader_platform_open_library(lib_name)) == NULL)
1091            continue;
1092        if ((fpEnumerateLayers = loader_platform_get_proc_address(handle, "vkEnumerateLayers")) == NULL) {
1093            //use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
1094            char *pEnd, *cpyStr;
1095            size_t siz;
1096            loader_platform_close_library(handle);
1097            lib_name = basename(lib_name);
1098            pEnd = strrchr(lib_name, '.');
1099            siz = (int) (pEnd - lib_name - strlen(VK_LAYER_LIBRARY_PREFIX) + 1);
1100            if (pEnd == NULL || siz <= 0)
1101                continue;
1102            cpyStr = malloc(siz);
1103            if (cpyStr == NULL) {
1104                free(cpyStr);
1105                continue;
1106            }
1107            strncpy(cpyStr, lib_name + strlen(VK_LAYER_LIBRARY_PREFIX), siz);
1108            cpyStr[siz - 1] = '\0';
1109            if (siz > maxStringSize)
1110                siz = (int) maxStringSize;
1111            strncpy((char *) (pOutLayers[count]), cpyStr, siz);
1112            pOutLayers[count][siz - 1] = '\0';
1113            count++;
1114            free(cpyStr);
1115        } else {
1116            size_t cnt;
1117            uint32_t n;
1118            VkResult res;
1119            n = (uint32_t) ((maxStringSize < 256) ? maxStringSize : 256);
1120            res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (char *) icd->gpus + gpu_index);
1121            loader_platform_close_library(handle);
1122            if (res != VK_SUCCESS)
1123                continue;
1124            if (cnt + count > maxLayerCount)
1125                cnt = maxLayerCount - count;
1126            for (uint32_t i = (uint32_t) count; i < cnt + count; i++) {
1127                strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n);
1128                if (n > 0)
1129                    pOutLayers[i - count][n - 1] = '\0';
1130            }
1131            count += cnt;
1132        }
1133    }
1134
1135    *pOutLayerCount = count;
1136
1137    return VK_SUCCESS;
1138}
1139
1140LOADER_EXPORT VkResult VKAPI vkDbgRegisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData)
1141{
1142    const struct loader_icd *icd;
1143    struct loader_instance *inst;
1144    VkResult res;
1145    uint32_t gpu_idx;
1146
1147    if (instance == VK_NULL_HANDLE)
1148        return VK_ERROR_INVALID_HANDLE;
1149
1150    assert(loader.icds_scanned);
1151
1152    for (inst = loader.instances; inst; inst = inst->next) {
1153        if (inst == instance)
1154            break;
1155    }
1156
1157    if (inst == VK_NULL_HANDLE)
1158        return VK_ERROR_INVALID_HANDLE;
1159
1160    for (icd = inst->icds; icd; icd = icd->next) {
1161        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1162            res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(icd->scanned_icds->instance,
1163                                                   pfnMsgCallback, pUserData);
1164            if (res != VK_SUCCESS) {
1165                gpu_idx = i;
1166                break;
1167            }
1168        }
1169        if (res != VK_SUCCESS)
1170            break;
1171    }
1172
1173
1174    /* roll back on errors */
1175    if (icd) {
1176        for (const struct loader_icd *tmp = inst->icds; tmp != icd;
1177                                                      tmp = tmp->next) {
1178            for (uint32_t i = 0; i < icd->gpu_count; i++)
1179                (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(tmp->scanned_icds->instance, pfnMsgCallback);
1180        }
1181        /* and gpus on current icd */
1182        for (uint32_t i = 0; i < gpu_idx; i++)
1183            (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback);
1184
1185        return res;
1186    }
1187
1188    return VK_SUCCESS;
1189}
1190
1191LOADER_EXPORT VkResult VKAPI vkDbgUnregisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback)
1192{
1193    VkResult res = VK_SUCCESS;
1194    struct loader_instance *inst;
1195    if (instance == VK_NULL_HANDLE)
1196        return VK_ERROR_INVALID_HANDLE;
1197
1198    assert(loader.icds_scanned);
1199
1200    for (inst = loader.instances; inst; inst = inst->next) {
1201        if (inst == instance)
1202            break;
1203    }
1204
1205    if (inst == VK_NULL_HANDLE)
1206        return VK_ERROR_INVALID_HANDLE;
1207
1208    for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) {
1209        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1210            VkResult r;
1211            r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback);
1212            if (r != VK_SUCCESS) {
1213                res = r;
1214            }
1215        }
1216    }
1217    return res;
1218}
1219
1220LOADER_EXPORT VkResult VKAPI vkDbgSetGlobalOption(VkInstance instance, VK_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData)
1221{
1222    VkResult res = VK_SUCCESS;
1223    struct loader_instance *inst;
1224    if (instance == VK_NULL_HANDLE)
1225        return VK_ERROR_INVALID_HANDLE;
1226
1227    assert(loader.icds_scanned);
1228
1229    for (inst = loader.instances; inst; inst = inst->next) {
1230        if (inst == instance)
1231            break;
1232    }
1233
1234    if (inst == VK_NULL_HANDLE)
1235        return VK_ERROR_INVALID_HANDLE;
1236    for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) {
1237        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1238            VkResult r;
1239            r = (icd->loader_dispatch + i)->DbgSetGlobalOption(icd->scanned_icds->instance, dbgOption,
1240                                                           dataSize, pData);
1241            /* unfortunately we cannot roll back */
1242            if (r != VK_SUCCESS) {
1243               res = r;
1244            }
1245        }
1246    }
1247
1248    return res;
1249}
1250