loader.c revision e2d07a5a3810d83d0ea7ecb396d61477893b74a4
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 */
29#define _GNU_SOURCE
30#include <stdio.h>
31#include <stdlib.h>
32#include <stdarg.h>
33#include <stdbool.h>
34#include <string.h>
35
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <dlfcn.h>
40#include <pthread.h>
41#include <assert.h>
42#include "table_ops.h"
43#include "loader.h"
44
45struct loader_layers {
46    void *lib_handle;
47    char name[256];
48};
49
50struct layer_name_pair {
51    char *layer_name;
52    const char *lib_name;
53};
54
55struct loader_icd {
56    void *handle;
57
58    XGL_LAYER_DISPATCH_TABLE *loader_dispatch;
59    uint32_t layer_count[XGL_MAX_PHYSICAL_GPUS];
60    struct loader_layers layer_libs[XGL_MAX_PHYSICAL_GPUS][MAX_LAYER_LIBRARIES];
61    XGL_BASE_LAYER_OBJECT *wrappedGpus[XGL_MAX_PHYSICAL_GPUS];
62    uint32_t gpu_count;
63    XGL_BASE_LAYER_OBJECT *gpus;
64
65    xglGetProcAddrType GetProcAddr;
66    xglInitAndEnumerateGpusType InitAndEnumerateGpus;
67
68    struct loader_icd *next;
69};
70
71
72struct loader_msg_callback {
73    XGL_DBG_MSG_CALLBACK_FUNCTION func;
74    void *data;
75
76    struct loader_msg_callback *next;
77};
78
79
80static struct {
81    bool scanned;
82    struct loader_icd *icds;
83    bool layer_scanned;
84    char *layer_dirs;
85    unsigned int scanned_layer_count;
86    char *scanned_layer_names[MAX_LAYER_LIBRARIES];
87    struct loader_msg_callback *msg_callbacks;
88
89    bool debug_echo_enable;
90    bool break_on_error;
91    bool break_on_warning;
92} loader;
93
94static XGL_RESULT loader_msg_callback_add(XGL_DBG_MSG_CALLBACK_FUNCTION func,
95                                          void *data)
96{
97    struct loader_msg_callback *cb;
98
99    cb = malloc(sizeof(*cb));
100    if (!cb)
101        return XGL_ERROR_OUT_OF_MEMORY;
102
103    cb->func = func;
104    cb->data = data;
105
106    cb->next = loader.msg_callbacks;
107    loader.msg_callbacks = cb;
108
109    return XGL_SUCCESS;
110}
111
112static XGL_RESULT loader_msg_callback_remove(XGL_DBG_MSG_CALLBACK_FUNCTION func)
113{
114    struct loader_msg_callback *cb = loader.msg_callbacks;
115
116    /*
117     * Find the first match (last registered).
118     *
119     * XXX What if the same callback function is registered more than once?
120     */
121    while (cb) {
122        if (cb->func == func) {
123            break;
124        }
125
126        cb = cb->next;
127    }
128
129    if (!cb)
130        return XGL_ERROR_INVALID_POINTER;
131
132    free(cb);
133
134    return XGL_SUCCESS;
135}
136
137static void loader_msg_callback_clear(void)
138{
139    struct loader_msg_callback *cb = loader.msg_callbacks;
140
141    while (cb) {
142        struct loader_msg_callback *next = cb->next;
143        free(cb);
144        cb = next;
145    }
146
147    loader.msg_callbacks = NULL;
148}
149
150static void loader_log(XGL_DBG_MSG_TYPE msg_type, int32_t msg_code,
151                       const char *format, ...)
152{
153    const struct loader_msg_callback *cb = loader.msg_callbacks;
154    char msg[256];
155    va_list ap;
156    int ret;
157
158    va_start(ap, format);
159    ret = vsnprintf(msg, sizeof(msg), format, ap);
160    if (ret >= sizeof(msg) || ret < 0) {
161        msg[sizeof(msg) - 1] = '\0';
162    }
163    va_end(ap);
164
165    if (loader.debug_echo_enable || !cb) {
166        fputs(msg, stderr);
167        fputc('\n', stderr);
168    }
169
170    while (cb) {
171        cb->func(msg_type, XGL_VALIDATION_LEVEL_0, XGL_NULL_HANDLE, 0,
172                msg_code, msg, cb->data);
173        cb = cb->next;
174    }
175
176    switch (msg_type) {
177    case XGL_DBG_MSG_ERROR:
178        if (loader.break_on_error) {
179            exit(1);
180        }
181        /* fall through */
182    case XGL_DBG_MSG_WARNING:
183        if (loader.break_on_warning) {
184            exit(1);
185        }
186        break;
187    default:
188        break;
189    }
190}
191
192static void
193loader_icd_destroy(struct loader_icd *icd)
194{
195    dlclose(icd->handle);
196    free(icd);
197}
198
199static struct loader_icd *
200loader_icd_create(const char *filename)
201{
202    struct loader_icd *icd;
203
204    icd = malloc(sizeof(*icd));
205    if (!icd)
206        return NULL;
207
208    memset(icd, 0, sizeof(*icd));
209
210    icd->handle = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
211    if (!icd->handle) {
212        loader_log(XGL_DBG_MSG_WARNING, 0, dlerror());
213        free(icd);
214        return NULL;
215    }
216
217#define LOOKUP(icd, func) do {                              \
218    icd->func = (xgl ##func## Type) dlsym(icd->handle, "xgl" #func); \
219    if (!icd->func) {                                       \
220        loader_log(XGL_DBG_MSG_WARNING, 0, dlerror());      \
221        loader_icd_destroy(icd);                            \
222        return NULL;                                        \
223    }                                                       \
224} while (0)
225    LOOKUP(icd, GetProcAddr);
226    LOOKUP(icd, InitAndEnumerateGpus);
227#undef LOOKUP
228
229    return icd;
230}
231
232static XGL_RESULT loader_icd_register_msg_callbacks(const struct loader_icd *icd)
233{
234    const struct loader_msg_callback *cb = loader.msg_callbacks;
235    XGL_RESULT res;
236
237    while (cb) {
238        for (uint32_t i = 0; i < icd->gpu_count; i++) {
239            res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(cb->func, cb->data);
240            if (res != XGL_SUCCESS) {
241                break;
242            }
243        }
244        cb = cb->next;
245    }
246
247    /* roll back on errors */
248    if (cb) {
249        const struct loader_msg_callback *tmp = loader.msg_callbacks;
250
251        while (tmp != cb) {
252            for (uint32_t i = 0; i < icd->gpu_count; i++) {
253                (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(cb->func);
254            }
255            tmp = tmp->next;
256        }
257
258        return res;
259    }
260
261    return XGL_SUCCESS;
262}
263
264static XGL_RESULT loader_icd_set_global_options(const struct loader_icd *icd)
265{
266#define SETB(icd, opt, val) do {                                \
267    if (val) {                                                  \
268        for (uint32_t i = 0; i < icd->gpu_count; i++) {         \
269            const XGL_RESULT res =                              \
270                (icd->loader_dispatch + i)->DbgSetGlobalOption(opt, sizeof(val), &val); \
271            if (res != XGL_SUCCESS)                             \
272                return res;                                     \
273        }                                                       \
274    }                                                           \
275} while (0)
276    SETB(icd, XGL_DBG_OPTION_DEBUG_ECHO_ENABLE, loader.debug_echo_enable);
277    SETB(icd, XGL_DBG_OPTION_BREAK_ON_ERROR, loader.break_on_error);
278    SETB(icd, XGL_DBG_OPTION_BREAK_ON_WARNING, loader.break_on_warning);
279#undef SETB
280
281return XGL_SUCCESS;
282}
283
284static struct loader_icd *loader_icd_add(const char *filename)
285{
286    struct loader_icd *icd;
287
288    icd = loader_icd_create(filename);
289    if (!icd)
290        return NULL;
291
292    /* prepend to the list */
293    icd->next = loader.icds;
294    loader.icds = icd;
295
296    return icd;
297}
298
299#ifndef DEFAULT_XGL_DRIVERS_PATH
300// TODO: Is this a good default location?
301// Need to search for both 32bit and 64bit ICDs
302#define DEFAULT_XGL_DRIVERS_PATH "/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
303#endif
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 *libPaths, *p, *next;
318    DIR *sysdir;
319    struct dirent *dent;
320    char icd_library[1024];
321    char path[1024];
322    int len;
323
324    libPaths = NULL;
325    if (geteuid() == getuid()) {
326       /* don't allow setuid apps to use LIBXGL_DRIVERS_PATH */
327       libPaths = getenv("LIBXGL_DRIVERS_PATH");
328    }
329    if (libPaths == NULL)
330       libPaths = DEFAULT_XGL_DRIVERS_PATH;
331
332    for (p = libPaths; *p; p = next) {
333       next = strchr(p, ':');
334       if (next == NULL) {
335          len = strlen(p);
336          next = p + len;
337       }
338       else {
339          len = next - p;
340          sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
341          p = path;
342          next++;
343       }
344
345       sysdir = opendir(p);
346       if (sysdir) {
347          dent = readdir(sysdir);
348          while (dent) {
349             /* look for ICDs starting with "libXGL_" */
350             if (!strncmp(dent->d_name, "libXGL_", 7)) {
351                snprintf(icd_library, 1024, "%s/%s",p,dent->d_name);
352                loader_icd_add(icd_library);
353             }
354
355             dent = readdir(sysdir);
356          }
357          closedir(sysdir);
358       }
359    }
360
361
362    loader.scanned = true;
363}
364
365#ifndef DEFAULT_XGL_LAYERS_PATH
366// TODO: Are these good default locations?
367#define DEFAULT_XGL_LAYERS_PATH ".:/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
368#endif
369
370static void layer_lib_scan(const char * libInPaths)
371{
372    const char *p, *next;
373    char *libPaths;
374    DIR *curdir;
375    struct dirent *dent;
376    int len, i;
377    char temp_str[1024];
378
379    len = 0;
380    loader.layer_dirs = NULL;
381    if (libInPaths){
382        len = strlen(libInPaths);
383        p = libInPaths;
384    }
385    else {
386        if (geteuid() == getuid()) {
387            p = getenv("LIBXGL_LAYERS_PATH");
388            if (p != NULL)
389                len = strlen(p);
390        }
391    }
392
393    if (len == 0) {
394        len = strlen(DEFAULT_XGL_LAYERS_PATH);
395        p = DEFAULT_XGL_LAYERS_PATH;
396    }
397
398    if (len == 0) {
399        // Have no paths to search
400        return;
401    }
402    loader.layer_dirs = malloc(len+1);
403    if (loader.layer_dirs == NULL)
404        return;
405
406    // Alloc passed, so we know there is enough space to hold the string, don't need strncpy
407    strcpy(loader.layer_dirs, p);
408    libPaths = loader.layer_dirs;
409
410    /* cleanup any previously scanned libraries */
411    for (i = 0; i < loader.scanned_layer_count; i++) {
412        if (loader.scanned_layer_names[i] != NULL)
413            free(loader.scanned_layer_names[i]);
414        loader.scanned_layer_names[i] = NULL;
415    }
416    loader.scanned_layer_count = 0;
417
418    for (p = libPaths; *p; p = next) {
419       next = strchr(p, ':');
420       if (next == NULL) {
421          len = strlen(p);
422          next = p + len;
423       }
424       else {
425          len = next - p;
426          *(char *) next = '\0';
427          next++;
428       }
429
430       curdir = opendir(p);
431       if (curdir) {
432          dent = readdir(curdir);
433          while (dent) {
434             /* look for wrappers starting with "libXGLlayer" */
435             if (!strncmp(dent->d_name, "libXGLLayer", strlen("libXGLLayer"))) {
436                void * handle;
437                snprintf(temp_str, sizeof(temp_str), "%s/%s",p,dent->d_name);
438                if ((handle = dlopen(temp_str, RTLD_LAZY)) == NULL) {
439                    dent = readdir(curdir);
440                    continue;
441                }
442                if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
443                    loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
444                    break;
445                }
446                if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
447                     loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
448                     break;
449                }
450                strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
451                loader.scanned_layer_count++;
452                dlclose(handle);
453             }
454
455             dent = readdir(curdir);
456          }
457          closedir(curdir);
458       }
459    }
460
461    loader.layer_scanned = true;
462}
463
464static void loader_init_dispatch_table(XGL_LAYER_DISPATCH_TABLE *tab, xglGetProcAddrType fpGPA, XGL_PHYSICAL_GPU gpu)
465{
466    loader_initialize_dispatch_table(tab, fpGPA, gpu);
467
468    if (tab->EnumerateLayers == NULL)
469        tab->EnumerateLayers = xglEnumerateLayers;
470}
471
472static struct loader_icd * loader_get_icd(const XGL_BASE_LAYER_OBJECT *gpu, uint32_t *gpu_index)
473{
474    for (struct loader_icd * icd = loader.icds; icd; icd = icd->next) {
475        for (uint32_t i = 0; i < icd->gpu_count; i++)
476            if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject == gpu->baseObject) {
477                *gpu_index = i;
478                return icd;
479            }
480    }
481    return NULL;
482}
483
484static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
485{
486    if (icd->layer_count[gpu_index])
487        return true;
488    else
489        return false;
490}
491
492static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair * pLayerNames, uint32_t count)
493{
494    if (!icd)
495        return;
496
497    struct loader_layers *obj;
498    bool foundLib;
499    for (uint32_t i = 0; i < count; i++) {
500        foundLib = false;
501        for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) {
502            if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) {
503                foundLib = true;
504                break;
505            }
506        }
507        if (!foundLib) {
508            obj = &(icd->layer_libs[gpu_index][i]);
509            strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
510            obj->name[sizeof(obj->name) - 1] = '\0';
511            if ((obj->lib_handle = dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)) == NULL) {
512                loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to open layer library %s got error %d", pLayerNames[i].lib_name, dlerror());
513                continue;
514            } else {
515                loader_log(XGL_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name);
516            }
517            free(pLayerNames[i].layer_name);
518            icd->layer_count[gpu_index]++;
519        }
520    }
521}
522
523static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const char * layer_name, const char **lib_name)
524{
525    void *handle;
526    xglEnumerateLayersType fpEnumerateLayers;
527    char layer_buf[16][256];
528    char * layers[16];
529
530    for (int i = 0; i < 16; i++)
531         layers[i] = &layer_buf[i][0];
532
533    for (unsigned int j = 0; j < loader.scanned_layer_count; j++) {
534        *lib_name = loader.scanned_layer_names[j];
535        if ((handle = dlopen(*lib_name, RTLD_LAZY)) == NULL)
536            continue;
537        if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) {
538            //use default layer name based on library name libXGLLayer<name>.so
539            char * lib_str = malloc(strlen(*lib_name) + 1 + strlen(layer_name));
540            snprintf(lib_str, strlen(*lib_name) + strlen(layer_name), "libXGLLayer%s.so", layer_name);
541            dlclose(handle);
542            if (!strcmp(basename(*lib_name), lib_str)) {
543                free(lib_str);
544                return true;
545            }
546            else {
547                free(lib_str);
548                continue;
549            }
550        }
551        else {
552            size_t cnt;
553            fpEnumerateLayers(NULL, 16, 256, &cnt, layers, (void *) icd->gpus + gpu_index);
554            for (unsigned int i = 0; i < cnt; i++) {
555                if (!strcmp((char *) layers[i], layer_name)) {
556                    dlclose(handle);
557                    return true;
558                }
559            }
560        }
561
562        dlclose(handle);
563    }
564
565    return false;
566}
567
568static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames)
569{
570    const char *layerEnv;
571    uint32_t len, count = 0;
572    char *p, *pOrig, *next, *name;
573
574    layerEnv = getenv("LIBXGL_LAYER_NAMES");
575    if (!layerEnv)
576        return 0;
577    p = malloc(strlen(layerEnv) + 1);
578    if (!p)
579        return 0;
580    strcpy(p, layerEnv);
581    pOrig = p;
582
583    while (p && *p && count < MAX_LAYER_LIBRARIES) {
584        const char *lib_name = NULL;
585        next = strchr(p, ':');
586        if (next == NULL) {
587            len = strlen(p);
588            next = p + len;
589        }
590        else {
591            len = next - p;
592            *(char *) next = '\0';
593            next++;
594        }
595        name = basename(p);
596        if (!find_layer_name(icd, gpu_index, name, &lib_name)) {
597            p = next;
598            continue;
599        }
600
601        len = strlen(name);
602        pLayerNames[count].layer_name = malloc(len + 1);
603        if (!pLayerNames[count].layer_name) {
604            free(pOrig);
605            return count;
606        }
607        strncpy((char *) pLayerNames[count].layer_name, name, len);
608        pLayerNames[count].layer_name[len] = '\0';
609        pLayerNames[count].lib_name = lib_name;
610        count++;
611        p = next;
612
613    };
614
615    free(pOrig);
616    return count;
617}
618
619static 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)
620{
621    static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES];
622
623    *ppLayerNames =  &layerNames[0];
624    if (!pCreateInfo) {
625        return loader_get_layer_env(icd, gpu_index, layerNames);
626    }
627
628    const XGL_LAYER_CREATE_INFO *pCi =
629        (const XGL_LAYER_CREATE_INFO *) pCreateInfo->pNext;
630
631    while (pCi) {
632        if (pCi->sType == XGL_STRUCTURE_TYPE_LAYER_CREATE_INFO) {
633            const char *name;
634            uint32_t len;
635            for (uint32_t i = 0; i < pCi->layerCount; i++) {
636                const char * lib_name = NULL;
637                name = *(pCi->ppActiveLayerNames + i);
638                if (!find_layer_name(icd, gpu_index, name, &lib_name))
639                    return loader_get_layer_env(icd, gpu_index, layerNames);
640                len = strlen(name);
641                layerNames[i].layer_name = malloc(len + 1);
642                if (!layerNames[i].layer_name)
643                    return i;
644                strncpy((char *) layerNames[i].layer_name, name, len);
645                layerNames[i].layer_name[len] = '\0';
646                layerNames[i].lib_name = lib_name;
647            }
648            return pCi->layerCount + loader_get_layer_env(icd, gpu_index, layerNames);
649        }
650        pCi = pCi->pNext;
651    }
652    return loader_get_layer_env(icd, gpu_index, layerNames);
653}
654
655static void loader_deactivate_layer()
656{
657    struct loader_icd *icd;
658    struct loader_layers *libs;
659
660    for (icd = loader.icds; icd; icd = icd->next) {
661        if (icd->gpus)
662            free(icd->gpus);
663        icd->gpus = NULL;
664        if (icd->loader_dispatch)
665            free(icd->loader_dispatch);
666        icd->loader_dispatch = NULL;
667        for (uint32_t j = 0; j < icd->gpu_count; j++) {
668            if (icd->layer_count[j] > 0) {
669                for (uint32_t i = 0; i < icd->layer_count[j]; i++) {
670                    libs = &(icd->layer_libs[j][i]);
671                    if (libs->lib_handle)
672                        dlclose(libs->lib_handle);
673                    libs->lib_handle = NULL;
674                }
675                if (icd->wrappedGpus[j])
676                    free(icd->wrappedGpus[j]);
677            }
678            icd->layer_count[j] = 0;
679        }
680        icd->gpu_count = 0;
681    }
682}
683
684extern uint32_t loader_activate_layers(XGL_PHYSICAL_GPU gpu, const XGL_DEVICE_CREATE_INFO* pCreateInfo)
685{
686    uint32_t gpu_index;
687    uint32_t count;
688    struct layer_name_pair *pLayerNames;
689    struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index);
690
691    if (!icd)
692        return 0;
693    assert(gpu_index < XGL_MAX_PHYSICAL_GPUS);
694
695    /* activate any layer libraries */
696    if (!loader_layers_activated(icd, gpu_index)) {
697        XGL_BASE_LAYER_OBJECT *gpuObj = (XGL_BASE_LAYER_OBJECT *) gpu;
698        XGL_BASE_LAYER_OBJECT *nextGpuObj, *baseObj = gpuObj->baseObject;
699        xglGetProcAddrType nextGPA = xglGetProcAddr;
700
701        count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames);
702        if (!count)
703            return 0;
704        loader_init_layer_libs(icd, gpu_index, pLayerNames, count);
705
706        icd->wrappedGpus[gpu_index] = malloc(sizeof(XGL_BASE_LAYER_OBJECT) * icd->layer_count[gpu_index]);
707        if (! icd->wrappedGpus[gpu_index])
708                loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer");
709        for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
710            nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
711            nextGpuObj->pGPA = nextGPA;
712            nextGpuObj->baseObject = baseObj;
713            nextGpuObj->nextObject = gpuObj;
714            gpuObj = nextGpuObj;
715
716            char funcStr[256];
717            snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name);
718            if ((nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
719                nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, "xglGetProcAddr");
720            if (!nextGPA) {
721                loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to find xglGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name);
722                continue;
723            }
724
725            if (i == 0) {
726                loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj);
727                //Insert the new wrapped objects into the list with loader object at head
728                ((XGL_BASE_LAYER_OBJECT *) gpu)->nextObject = gpuObj;
729                ((XGL_BASE_LAYER_OBJECT *) gpu)->pGPA = nextGPA;
730                gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1;
731                gpuObj->nextObject = baseObj;
732                gpuObj->pGPA = icd->GetProcAddr;
733            }
734
735        }
736    }
737    else {
738        //make sure requested Layers matches currently activated Layers
739        count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames);
740        for (uint32_t i = 0; i < count; i++) {
741            if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) {
742                loader_log(XGL_DBG_MSG_ERROR, 0, "Layers activated != Layers requested");
743                break;
744            }
745        }
746        if (count != icd->layer_count[gpu_index]) {
747            loader_log(XGL_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested");
748        }
749    }
750    return icd->layer_count[gpu_index];
751}
752
753LOADER_EXPORT void * XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const char * pName) {
754
755    if (gpu == NULL)
756        return NULL;
757    XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) gpu;
758    XGL_LAYER_DISPATCH_TABLE * disp_table = * (XGL_LAYER_DISPATCH_TABLE **) gpuw->baseObject;
759    void *addr;
760
761    if (disp_table == NULL)
762        return NULL;
763
764    addr = loader_lookup_dispatch_table(disp_table, pName);
765    if (addr)
766        return addr;
767    else  {
768        if (disp_table->GetProcAddr == NULL)
769            return NULL;
770        return disp_table->GetProcAddr(gpuw->nextObject, pName);
771    }
772}
773
774LOADER_EXPORT XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO* pAppInfo, const XGL_ALLOC_CALLBACKS* pAllocCb, uint32_t maxGpus, uint32_t* pGpuCount, XGL_PHYSICAL_GPU* pGpus)
775{
776    static pthread_once_t once = PTHREAD_ONCE_INIT;
777    struct loader_icd *icd;
778    uint32_t count = 0;
779    XGL_RESULT res;
780
781    // cleanup any prior layer initializations
782    loader_deactivate_layer();
783
784    pthread_once(&once, loader_icd_scan);
785
786    if (!loader.icds)
787        return XGL_ERROR_UNAVAILABLE;
788
789    icd = loader.icds;
790    while (icd) {
791        XGL_PHYSICAL_GPU gpus[XGL_MAX_PHYSICAL_GPUS];
792        XGL_BASE_LAYER_OBJECT * wrappedGpus;
793        xglGetProcAddrType getProcAddr = icd->GetProcAddr;
794        uint32_t n, max = maxGpus - count;
795
796        if (max > XGL_MAX_PHYSICAL_GPUS) {
797            max = XGL_MAX_PHYSICAL_GPUS;
798        }
799
800        res = icd->InitAndEnumerateGpus(pAppInfo, pAllocCb, max, &n, gpus);
801        if (res == XGL_SUCCESS && n) {
802            wrappedGpus = (XGL_BASE_LAYER_OBJECT*) malloc(n * sizeof(XGL_BASE_LAYER_OBJECT));
803            icd->gpus = wrappedGpus;
804            icd->gpu_count = n;
805            icd->loader_dispatch = (XGL_LAYER_DISPATCH_TABLE *) malloc(n * sizeof(XGL_LAYER_DISPATCH_TABLE));
806            for (int i = 0; i < n; i++) {
807                (wrappedGpus + i)->baseObject = gpus[i];
808                (wrappedGpus + i)->pGPA = getProcAddr;
809                (wrappedGpus + i)->nextObject = gpus[i];
810                memcpy(pGpus + count, &wrappedGpus, sizeof(*pGpus));
811                loader_init_dispatch_table(icd->loader_dispatch + i, getProcAddr, gpus[i]);
812                const XGL_LAYER_DISPATCH_TABLE * *disp = (const XGL_LAYER_DISPATCH_TABLE *  *) gpus[i];
813                *disp = icd->loader_dispatch + i;
814            }
815
816            if (loader_icd_set_global_options(icd) != XGL_SUCCESS ||
817                loader_icd_register_msg_callbacks(icd) != XGL_SUCCESS) {
818                loader_log(XGL_DBG_MSG_WARNING, 0,
819                        "ICD ignored: failed to migrate settings");
820                loader_icd_destroy(icd);
821            }
822            count += n;
823
824            if (count >= maxGpus) {
825                break;
826            }
827        }
828
829        icd = icd->next;
830    }
831
832    /* we have nothing to log anymore */
833    loader_msg_callback_clear();
834
835    /* get layer libraries */
836    if (!loader.layer_scanned)
837        layer_lib_scan(NULL);
838
839    *pGpuCount = count;
840
841    return (count > 0) ? XGL_SUCCESS : res;
842}
843
844LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
845{
846    uint32_t gpu_index;
847    uint32_t count = 0;
848    char *lib_name;
849    struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index);
850    void *handle;
851    xglEnumerateLayersType fpEnumerateLayers;
852    char layer_buf[16][256];
853    char * layers[16];
854
855    if (pOutLayerCount == NULL || pOutLayers == NULL)
856        return XGL_ERROR_INVALID_POINTER;
857
858    for (int i = 0; i < 16; i++)
859         layers[i] = &layer_buf[i][0];
860
861    for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
862        lib_name = loader.scanned_layer_names[j];
863        if ((handle = dlopen(lib_name, RTLD_LAZY)) == NULL)
864            continue;
865        if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) {
866            //use default layer name based on library name libXGLLayer<name>.so
867            char *pEnd, *cpyStr;
868            int siz;
869            dlclose(handle);
870            lib_name = basename(lib_name);
871            pEnd = strrchr(lib_name, '.');
872            siz = pEnd - lib_name - strlen("libXGLLayer") + 1;
873            if (pEnd == NULL || siz <= 0)
874                continue;
875            cpyStr = malloc(siz);
876            if (cpyStr == NULL) {
877                free(cpyStr);
878                continue;
879            }
880            strncpy(cpyStr, lib_name + strlen("libXGLLayer"), siz);
881            cpyStr[siz - 1] = '\0';
882            if (siz > maxStringSize)
883                siz = maxStringSize;
884            strncpy((char *) (pOutLayers[count]), cpyStr, siz);
885            pOutLayers[count][siz - 1] = '\0';
886            count++;
887            free(cpyStr);
888        }
889        else {
890            size_t cnt;
891            uint32_t n;
892            XGL_RESULT res;
893            n = (maxStringSize < 256) ? maxStringSize : 256;
894            res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (void *) icd->gpus + gpu_index);
895            dlclose(handle);
896            if (res != XGL_SUCCESS)
897                continue;
898            if (cnt + count > maxLayerCount)
899                cnt = maxLayerCount - count;
900            for (unsigned int i = count; i < cnt + count; i++) {
901                strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n);
902                if (n > 0)
903                    pOutLayers[i - count][n - 1] = '\0';
904            }
905            count += cnt;
906        }
907    }
908
909    *pOutLayerCount = count;
910
911    return XGL_SUCCESS;
912}
913
914LOADER_EXPORT XGL_RESULT XGLAPI xglDbgRegisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData)
915{
916    const struct loader_icd *icd;
917    XGL_RESULT res;
918    uint32_t gpu_idx;
919
920    if (!loader.scanned) {
921        return loader_msg_callback_add(pfnMsgCallback, pUserData);
922    }
923
924    for (icd = loader.icds; icd; icd = icd->next) {
925        for (uint32_t i = 0; i < icd->gpu_count; i++) {
926            res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(pfnMsgCallback, pUserData);
927            if (res != XGL_SUCCESS) {
928                gpu_idx = i;
929                break;
930            }
931        }
932        if (res != XGL_SUCCESS)
933            break;
934    }
935
936    /* roll back on errors */
937    if (icd) {
938        for (const struct loader_icd * tmp = loader.icds; tmp != icd; tmp = tmp->next) {
939            for (uint32_t i = 0; i < icd->gpu_count; i++)
940                (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback);
941        }
942        /* and gpus on current icd */
943        for (uint32_t i = 0; i < gpu_idx; i++)
944            (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback);
945
946        return res;
947    }
948
949    return XGL_SUCCESS;
950}
951
952LOADER_EXPORT XGL_RESULT XGLAPI xglDbgUnregisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback)
953{
954    XGL_RESULT res = XGL_SUCCESS;
955
956    if (!loader.scanned) {
957        return loader_msg_callback_remove(pfnMsgCallback);
958    }
959
960    for (const struct loader_icd * icd = loader.icds; icd; icd = icd->next) {
961        for (uint32_t i = 0; i < icd->gpu_count; i++) {
962            XGL_RESULT r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback);
963            if (r != XGL_SUCCESS) {
964                res = r;
965            }
966        }
967    }
968    return res;
969}
970
971LOADER_EXPORT XGL_RESULT XGLAPI xglDbgSetGlobalOption(XGL_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData)
972{
973    XGL_RESULT res = XGL_SUCCESS;
974
975    if (!loader.scanned) {
976        if (dataSize == 0)
977            return XGL_ERROR_INVALID_VALUE;
978
979        switch (dbgOption) {
980        case XGL_DBG_OPTION_DEBUG_ECHO_ENABLE:
981            loader.debug_echo_enable = *((const bool *) pData);
982            break;
983        case XGL_DBG_OPTION_BREAK_ON_ERROR:
984            loader.break_on_error = *((const bool *) pData);
985            break;
986        case XGL_DBG_OPTION_BREAK_ON_WARNING:
987            loader.break_on_warning = *((const bool *) pData);
988            break;
989        default:
990            res = XGL_ERROR_INVALID_VALUE;
991            break;
992        }
993
994        return res;
995    }
996
997    for (const struct loader_icd * icd = loader.icds; icd; icd = icd->next) {
998        for (uint32_t i = 0; i < icd->gpu_count; i++) {
999            XGL_RESULT r = (icd->loader_dispatch + i)->DbgSetGlobalOption(dbgOption, dataSize, pData);
1000            /* unfortunately we cannot roll back */
1001            if (r != XGL_SUCCESS) {
1002                res = r;
1003            }
1004        }
1005    }
1006
1007    return res;
1008}
1009