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