loader.c revision 14275da630602a14168f83629b49e63d2d2023cb
1748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/*
2748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * XGL
3748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
4748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Copyright (C) 2014 LunarG, Inc.
5748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
6748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Permission is hereby granted, free of charge, to any person obtaining a
7748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * copy of this software and associated documentation files (the "Software"),
8748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * to deal in the Software without restriction, including without limitation
9748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * and/or sell copies of the Software, and to permit persons to whom the
11748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Software is furnished to do so, subject to the following conditions:
12748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
13748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * The above copyright notice and this permission notice shall be included
14748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * in all copies or substantial portions of the Software.
15748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
16748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * DEALINGS IN THE SOFTWARE.
23748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *
24748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Authors:
25748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *   Chia-I Wu <olv@lunarg.com>
26748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *   Jon Ashburn <jon@lunarg.com>
27748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *   Courtney Goeltzenleuchter <courtney@lunarg.com>
28748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */
29748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#define _GNU_SOURCE
30748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdio.h>
31748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdlib.h>
32748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdarg.h>
33748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdbool.h>
34748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <string.h>
35748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
36748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <sys/types.h>
37748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <dirent.h>
38748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <unistd.h>
39748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <dlfcn.h>
40748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <pthread.h>
41748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <assert.h>
42748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "table_ops.h"
43748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "loader.h"
44748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
45748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct loader_instance {
46748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    const XGL_APPLICATION_INFO *app_info;
47748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    const XGL_ALLOC_CALLBACKS *alloc_cb;
48748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
49748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_icd *icds;
50748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_instance *next;
51748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat};
52748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
53748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct loader_layers {
54748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    void *lib_handle;
55748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    char name[256];
56748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat};
57748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
58748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct layer_name_pair {
59748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    char *layer_name;
60748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    const char *lib_name;
61748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat};
62748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
63748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct loader_icd {
64748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    const struct loader_scanned_icds *scanned_icds;
65748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
66748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    XGL_LAYER_DISPATCH_TABLE *loader_dispatch;
67748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    uint32_t layer_count[XGL_MAX_PHYSICAL_GPUS];
68748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_layers layer_libs[XGL_MAX_PHYSICAL_GPUS][MAX_LAYER_LIBRARIES];
69748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    XGL_BASE_LAYER_OBJECT *wrappedGpus[XGL_MAX_PHYSICAL_GPUS];
70748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    uint32_t gpu_count;
71748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    XGL_BASE_LAYER_OBJECT *gpus;
72748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
73748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_icd *next;
74748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat};
75748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
76748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
77748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct loader_msg_callback {
78748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    XGL_DBG_MSG_CALLBACK_FUNCTION func;
79748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    void *data;
80748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
81748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_msg_callback *next;
82748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat};
83748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
84748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct loader_scanned_icds {
85748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    void *handle;
86748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    xglGetProcAddrType GetProcAddr;
87748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    xglInitAndEnumerateGpusType InitAndEnumerateGpus;
88748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
89748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_scanned_icds *next;
90748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat};
91748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
92748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat// Note: Since the following is a static structure, all members are initialized
93748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat// to zero.
94748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic struct {
95748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_instance *instances;
96748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    bool icds_scanned;
97748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_scanned_icds *scanned_icd_list;
98748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    bool layer_scanned;
99748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    char *layer_dirs;
100748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    unsigned int scanned_layer_count;
101748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    char *scanned_layer_names[MAX_LAYER_LIBRARIES];
102748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_msg_callback *msg_callbacks;
103748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
104748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    bool debug_echo_enable;
105748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    bool break_on_error;
106748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    bool break_on_warning;
107748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} loader;
108748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
109748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic XGL_RESULT loader_msg_callback_add(XGL_DBG_MSG_CALLBACK_FUNCTION func,
110748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat                                          void *data)
111748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
112748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_msg_callback *cb;
113748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
114748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    cb = malloc(sizeof(*cb));
115748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    if (!cb)
116748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        return XGL_ERROR_OUT_OF_MEMORY;
117748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
118748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    cb->func = func;
119748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    cb->data = data;
120748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
121748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    cb->next = loader.msg_callbacks;
122748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    loader.msg_callbacks = cb;
123748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
124748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    return XGL_SUCCESS;
125748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
126748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
127748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic XGL_RESULT loader_msg_callback_remove(XGL_DBG_MSG_CALLBACK_FUNCTION func)
128748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
129748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_msg_callback *cb = loader.msg_callbacks;
130748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
131748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    /*
132748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat     * Find the first match (last registered).
133748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat     *
134748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat     * XXX What if the same callback function is registered more than once?
135748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat     */
136748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    while (cb) {
137748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        if (cb->func == func) {
138748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat            break;
139748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        }
140748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
141748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        cb = cb->next;
142748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    }
143748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
144748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    if (!cb)
145748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        return XGL_ERROR_INVALID_POINTER;
146748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
147748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    free(cb);
148748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
149748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    return XGL_SUCCESS;
150748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
151748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
152748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void loader_msg_callback_clear(void)
153748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
154748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    struct loader_msg_callback *cb = loader.msg_callbacks;
155748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
156748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    while (cb) {
157748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        struct loader_msg_callback *next = cb->next;
158748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        free(cb);
159        cb = next;
160    }
161
162    loader.msg_callbacks = NULL;
163}
164
165static void loader_log(XGL_DBG_MSG_TYPE msg_type, int32_t msg_code,
166                       const char *format, ...)
167{
168    const struct loader_msg_callback *cb = loader.msg_callbacks;
169    char msg[256];
170    va_list ap;
171    int ret;
172
173    va_start(ap, format);
174    ret = vsnprintf(msg, sizeof(msg), format, ap);
175    if (ret >= sizeof(msg) || ret < 0) {
176        msg[sizeof(msg) - 1] = '\0';
177    }
178    va_end(ap);
179
180    if (loader.debug_echo_enable || !cb) {
181        fputs(msg, stderr);
182        fputc('\n', stderr);
183    }
184
185    while (cb) {
186        cb->func(msg_type, XGL_VALIDATION_LEVEL_0, XGL_NULL_HANDLE, 0,
187                msg_code, msg, cb->data);
188        cb = cb->next;
189    }
190
191    switch (msg_type) {
192    case XGL_DBG_MSG_ERROR:
193        if (loader.break_on_error) {
194            exit(1);
195        }
196        /* fall through */
197    case XGL_DBG_MSG_WARNING:
198        if (loader.break_on_warning) {
199            exit(1);
200        }
201        break;
202    default:
203        break;
204    }
205}
206
207static void
208loader_icd_destroy(struct loader_icd *icd)
209{
210    dlclose(icd->scanned_icds->handle);
211    free(icd);
212}
213
214static struct loader_icd *
215loader_icd_create(const struct loader_scanned_icds *scanned)
216{
217    struct loader_icd *icd;
218
219    icd = malloc(sizeof(*icd));
220    if (!icd)
221        return NULL;
222
223    memset(icd, 0, sizeof(*icd));
224
225    icd->scanned_icds = scanned;
226
227    return icd;
228}
229
230static XGL_RESULT loader_icd_register_msg_callbacks(const struct loader_icd *icd)
231{
232    const struct loader_msg_callback *cb = loader.msg_callbacks;
233    XGL_RESULT res;
234
235    while (cb) {
236        for (uint32_t i = 0; i < icd->gpu_count; i++) {
237            res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(cb->func, cb->data);
238            if (res != XGL_SUCCESS) {
239                break;
240            }
241        }
242        cb = cb->next;
243    }
244
245    /* roll back on errors */
246    if (cb) {
247        const struct loader_msg_callback *tmp = loader.msg_callbacks;
248
249        while (tmp != cb) {
250            for (uint32_t i = 0; i < icd->gpu_count; i++) {
251                (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(cb->func);
252            }
253            tmp = tmp->next;
254        }
255
256        return res;
257    }
258
259    return XGL_SUCCESS;
260}
261
262static XGL_RESULT loader_icd_set_global_options(const struct loader_icd *icd)
263{
264#define SETB(icd, opt, val) do {                                \
265    if (val) {                                                  \
266        for (uint32_t i = 0; i < icd->gpu_count; i++) {         \
267            const XGL_RESULT res =                              \
268                (icd->loader_dispatch + i)->DbgSetGlobalOption(opt, sizeof(val), &val); \
269            if (res != XGL_SUCCESS)                             \
270                return res;                                     \
271        }                                                       \
272    }                                                           \
273} while (0)
274    SETB(icd, XGL_DBG_OPTION_DEBUG_ECHO_ENABLE, loader.debug_echo_enable);
275    SETB(icd, XGL_DBG_OPTION_BREAK_ON_ERROR, loader.break_on_error);
276    SETB(icd, XGL_DBG_OPTION_BREAK_ON_WARNING, loader.break_on_warning);
277#undef SETB
278
279return XGL_SUCCESS;
280}
281
282static struct loader_icd *loader_icd_add(const struct loader_scanned_icds *scanned)
283{
284    struct loader_icd *icd;
285
286    icd = loader_icd_create(scanned);
287    if (!icd)
288        return NULL;
289
290    /* prepend to the list */
291    icd->next = loader.instances->icds;
292    loader.instances->icds = icd;
293
294    return icd;
295}
296
297static void loader_scanned_icd_add(const char *filename)
298{
299    void *handle;
300    void *fp_gpa, *fp_init;
301    struct loader_scanned_icds *new_node;
302
303    handle = dlopen(filename, RTLD_LAZY);
304    if (!handle) {
305        loader_log(XGL_DBG_MSG_WARNING, 0, dlerror());
306        return;
307    }
308
309#define LOOKUP(func_ptr, func) do {                            \
310    func_ptr = (xgl ##func## Type) dlsym(handle, "xgl" #func); \
311    if (!func_ptr) {                                           \
312        loader_log(XGL_DBG_MSG_WARNING, 0, dlerror());         \
313        return;                                                \
314    }                                                          \
315} while (0)
316
317    LOOKUP(fp_gpa, GetProcAddr);
318    LOOKUP(fp_init, InitAndEnumerateGpus);
319#undef LOOKUP
320
321    new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds));
322    if (!new_node) {
323        loader_log(XGL_DBG_MSG_WARNING, 0, "Out of memory can't add icd");
324        return;
325    }
326
327    new_node->handle = handle;
328    new_node->GetProcAddr = fp_gpa;
329    new_node->InitAndEnumerateGpus = fp_init;
330    new_node->next = loader.scanned_icd_list;
331    loader.scanned_icd_list = new_node;
332}
333
334#ifndef DEFAULT_XGL_DRIVERS_PATH
335// TODO: Is this a good default location?
336// Need to search for both 32bit and 64bit ICDs
337#define DEFAULT_XGL_DRIVERS_PATH "/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
338#endif
339
340/**
341 * Try to \c loader_icd_scan XGL driver(s).
342 *
343 * This function scans the default system path or path
344 * specified by the \c LIBXGL_DRIVERS_PATH environment variable in
345 * order to find loadable XGL ICDs with the name of libXGL_*.
346 *
347 * \returns
348 * void; but side effect is to set loader_icd_scanned to true
349 */
350static void loader_icd_scan(void)
351{
352    const char *libPaths, *p, *next;
353    DIR *sysdir;
354    struct dirent *dent;
355    char icd_library[1024];
356    char path[1024];
357    int len;
358
359    libPaths = NULL;
360    if (geteuid() == getuid()) {
361       /* don't allow setuid apps to use LIBXGL_DRIVERS_PATH */
362       libPaths = getenv("LIBXGL_DRIVERS_PATH");
363    }
364    if (libPaths == NULL)
365       libPaths = DEFAULT_XGL_DRIVERS_PATH;
366
367    for (p = libPaths; *p; p = next) {
368       next = strchr(p, ':');
369       if (next == NULL) {
370          len = strlen(p);
371          next = p + len;
372       }
373       else {
374          len = next - p;
375          sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
376          p = path;
377          next++;
378       }
379
380       sysdir = opendir(p);
381       if (sysdir) {
382          dent = readdir(sysdir);
383          while (dent) {
384             /* look for ICDs starting with "libXGL_" */
385             if (!strncmp(dent->d_name, "libXGL_", 7)) {
386                snprintf(icd_library, 1024, "%s/%s",p,dent->d_name);
387
388                loader_scanned_icd_add(icd_library);
389             }
390
391             dent = readdir(sysdir);
392          }
393          closedir(sysdir);
394       }
395    }
396
397
398    loader.icds_scanned = true;
399}
400
401#ifndef DEFAULT_XGL_LAYERS_PATH
402// TODO: Are these good default locations?
403#define DEFAULT_XGL_LAYERS_PATH ".:/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
404#endif
405
406static void layer_lib_scan(const char * libInPaths)
407{
408    const char *p, *next;
409    char *libPaths;
410    DIR *curdir;
411    struct dirent *dent;
412    int len, i;
413    char temp_str[1024];
414
415    len = 0;
416    loader.layer_dirs = NULL;
417    if (libInPaths){
418        len = strlen(libInPaths);
419        p = libInPaths;
420    }
421    else {
422        if (geteuid() == getuid()) {
423            p = getenv("LIBXGL_LAYERS_PATH");
424            if (p != NULL)
425                len = strlen(p);
426        }
427    }
428
429    if (len == 0) {
430        len = strlen(DEFAULT_XGL_LAYERS_PATH);
431        p = DEFAULT_XGL_LAYERS_PATH;
432    }
433
434    if (len == 0) {
435        // Have no paths to search
436        return;
437    }
438    loader.layer_dirs = malloc(len+1);
439    if (loader.layer_dirs == NULL)
440        return;
441
442    // Alloc passed, so we know there is enough space to hold the string, don't need strncpy
443    strcpy(loader.layer_dirs, p);
444    libPaths = loader.layer_dirs;
445
446    /* cleanup any previously scanned libraries */
447    for (i = 0; i < loader.scanned_layer_count; i++) {
448        if (loader.scanned_layer_names[i] != NULL)
449            free(loader.scanned_layer_names[i]);
450        loader.scanned_layer_names[i] = NULL;
451    }
452    loader.scanned_layer_count = 0;
453
454    for (p = libPaths; *p; p = next) {
455       next = strchr(p, ':');
456       if (next == NULL) {
457          len = strlen(p);
458          next = p + len;
459       }
460       else {
461          len = next - p;
462          *(char *) next = '\0';
463          next++;
464       }
465
466       curdir = opendir(p);
467       if (curdir) {
468          dent = readdir(curdir);
469          while (dent) {
470             /* look for wrappers starting with "libXGLlayer" */
471             if (!strncmp(dent->d_name, "libXGLLayer", strlen("libXGLLayer"))) {
472                void * handle;
473                snprintf(temp_str, sizeof(temp_str), "%s/%s",p,dent->d_name);
474                if ((handle = dlopen(temp_str, RTLD_LAZY)) == NULL) {
475                    dent = readdir(curdir);
476                    continue;
477                }
478                if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
479                    loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
480                    break;
481                }
482                if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
483                     loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
484                     break;
485                }
486                strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
487                loader.scanned_layer_count++;
488                dlclose(handle);
489             }
490
491             dent = readdir(curdir);
492          }
493          closedir(curdir);
494       }
495    }
496
497    loader.layer_scanned = true;
498}
499
500static void loader_init_dispatch_table(XGL_LAYER_DISPATCH_TABLE *tab, xglGetProcAddrType fpGPA, XGL_PHYSICAL_GPU gpu)
501{
502    loader_initialize_dispatch_table(tab, fpGPA, gpu);
503
504    if (tab->EnumerateLayers == NULL)
505        tab->EnumerateLayers = xglEnumerateLayers;
506}
507
508static struct loader_icd * loader_get_icd(const XGL_BASE_LAYER_OBJECT *gpu, uint32_t *gpu_index)
509{
510    if (!loader.instances)
511        return NULL;
512
513    //TODO go through all instances
514    for (struct loader_icd * icd = loader.instances->icds; icd; icd = icd->next) {
515        for (uint32_t i = 0; i < icd->gpu_count; i++)
516            if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject == gpu->baseObject) {
517                *gpu_index = i;
518                return icd;
519            }
520    }
521    return NULL;
522}
523
524static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
525{
526    if (icd->layer_count[gpu_index])
527        return true;
528    else
529        return false;
530}
531
532static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair * pLayerNames, uint32_t count)
533{
534    if (!icd)
535        return;
536
537    struct loader_layers *obj;
538    bool foundLib;
539    for (uint32_t i = 0; i < count; i++) {
540        foundLib = false;
541        for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) {
542            if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) {
543                foundLib = true;
544                break;
545            }
546        }
547        if (!foundLib) {
548            obj = &(icd->layer_libs[gpu_index][i]);
549            strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
550            obj->name[sizeof(obj->name) - 1] = '\0';
551            if ((obj->lib_handle = dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)) == NULL) {
552                loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to open layer library %s got error %d", pLayerNames[i].lib_name, dlerror());
553                continue;
554            } else {
555                loader_log(XGL_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name);
556            }
557            free(pLayerNames[i].layer_name);
558            icd->layer_count[gpu_index]++;
559        }
560    }
561}
562
563static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const char * layer_name, const char **lib_name)
564{
565    void *handle;
566    xglEnumerateLayersType fpEnumerateLayers;
567    char layer_buf[16][256];
568    char * layers[16];
569
570    for (int i = 0; i < 16; i++)
571         layers[i] = &layer_buf[i][0];
572
573    for (unsigned int j = 0; j < loader.scanned_layer_count; j++) {
574        *lib_name = loader.scanned_layer_names[j];
575        if ((handle = dlopen(*lib_name, RTLD_LAZY)) == NULL)
576            continue;
577        if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) {
578            //use default layer name based on library name libXGLLayer<name>.so
579            char * lib_str = malloc(strlen(*lib_name) + 1 + strlen(layer_name));
580            snprintf(lib_str, strlen(*lib_name) + strlen(layer_name), "libXGLLayer%s.so", layer_name);
581            dlclose(handle);
582            if (!strcmp(basename(*lib_name), lib_str)) {
583                free(lib_str);
584                return true;
585            }
586            else {
587                free(lib_str);
588                continue;
589            }
590        }
591        else {
592            size_t cnt;
593            fpEnumerateLayers(NULL, 16, 256, &cnt, layers, (void *) icd->gpus + gpu_index);
594            for (unsigned int i = 0; i < cnt; i++) {
595                if (!strcmp((char *) layers[i], layer_name)) {
596                    dlclose(handle);
597                    return true;
598                }
599            }
600        }
601
602        dlclose(handle);
603    }
604
605    return false;
606}
607
608static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames)
609{
610    const char *layerEnv;
611    uint32_t len, count = 0;
612    char *p, *pOrig, *next, *name;
613
614    layerEnv = getenv("LIBXGL_LAYER_NAMES");
615    if (!layerEnv)
616        return 0;
617    p = malloc(strlen(layerEnv) + 1);
618    if (!p)
619        return 0;
620    strcpy(p, layerEnv);
621    pOrig = p;
622
623    while (p && *p && count < MAX_LAYER_LIBRARIES) {
624        const char *lib_name = NULL;
625        next = strchr(p, ':');
626        if (next == NULL) {
627            len = strlen(p);
628            next = p + len;
629        }
630        else {
631            len = next - p;
632            *(char *) next = '\0';
633            next++;
634        }
635        name = basename(p);
636        if (!find_layer_name(icd, gpu_index, name, &lib_name)) {
637            p = next;
638            continue;
639        }
640
641        len = strlen(name);
642        pLayerNames[count].layer_name = malloc(len + 1);
643        if (!pLayerNames[count].layer_name) {
644            free(pOrig);
645            return count;
646        }
647        strncpy((char *) pLayerNames[count].layer_name, name, len);
648        pLayerNames[count].layer_name[len] = '\0';
649        pLayerNames[count].lib_name = lib_name;
650        count++;
651        p = next;
652
653    };
654
655    free(pOrig);
656    return count;
657}
658
659static 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)
660{
661    static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES];
662
663    *ppLayerNames =  &layerNames[0];
664    if (!pCreateInfo) {
665        return loader_get_layer_env(icd, gpu_index, layerNames);
666    }
667
668    const XGL_LAYER_CREATE_INFO *pCi =
669        (const XGL_LAYER_CREATE_INFO *) pCreateInfo->pNext;
670
671    while (pCi) {
672        if (pCi->sType == XGL_STRUCTURE_TYPE_LAYER_CREATE_INFO) {
673            const char *name;
674            uint32_t len;
675            for (uint32_t i = 0; i < pCi->layerCount; i++) {
676                const char * lib_name = NULL;
677                name = *(pCi->ppActiveLayerNames + i);
678                if (!find_layer_name(icd, gpu_index, name, &lib_name))
679                    return loader_get_layer_env(icd, gpu_index, layerNames);
680                len = strlen(name);
681                layerNames[i].layer_name = malloc(len + 1);
682                if (!layerNames[i].layer_name)
683                    return i;
684                strncpy((char *) layerNames[i].layer_name, name, len);
685                layerNames[i].layer_name[len] = '\0';
686                layerNames[i].lib_name = lib_name;
687            }
688            return pCi->layerCount + loader_get_layer_env(icd, gpu_index, layerNames);
689        }
690        pCi = pCi->pNext;
691    }
692    return loader_get_layer_env(icd, gpu_index, layerNames);
693}
694
695static void loader_deactivate_layer(const struct loader_instance *instance)
696{
697    struct loader_icd *icd;
698    struct loader_layers *libs;
699
700    for (icd = instance->icds; icd; icd = icd->next) {
701        if (icd->gpus)
702            free(icd->gpus);
703        icd->gpus = NULL;
704        if (icd->loader_dispatch)
705            free(icd->loader_dispatch);
706        icd->loader_dispatch = NULL;
707        for (uint32_t j = 0; j < icd->gpu_count; j++) {
708            if (icd->layer_count[j] > 0) {
709                for (uint32_t i = 0; i < icd->layer_count[j]; i++) {
710                    libs = &(icd->layer_libs[j][i]);
711                    if (libs->lib_handle)
712                        dlclose(libs->lib_handle);
713                    libs->lib_handle = NULL;
714                }
715                if (icd->wrappedGpus[j])
716                    free(icd->wrappedGpus[j]);
717            }
718            icd->layer_count[j] = 0;
719        }
720        icd->gpu_count = 0;
721    }
722}
723
724extern uint32_t loader_activate_layers(XGL_PHYSICAL_GPU gpu, const XGL_DEVICE_CREATE_INFO* pCreateInfo)
725{
726    uint32_t gpu_index;
727    uint32_t count;
728    struct layer_name_pair *pLayerNames;
729    struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index);
730
731    if (!icd)
732        return 0;
733    assert(gpu_index < XGL_MAX_PHYSICAL_GPUS);
734
735    /* activate any layer libraries */
736    if (!loader_layers_activated(icd, gpu_index)) {
737        XGL_BASE_LAYER_OBJECT *gpuObj = (XGL_BASE_LAYER_OBJECT *) gpu;
738        XGL_BASE_LAYER_OBJECT *nextGpuObj, *baseObj = gpuObj->baseObject;
739        xglGetProcAddrType nextGPA = xglGetProcAddr;
740
741        count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames);
742        if (!count)
743            return 0;
744        loader_init_layer_libs(icd, gpu_index, pLayerNames, count);
745
746        icd->wrappedGpus[gpu_index] = malloc(sizeof(XGL_BASE_LAYER_OBJECT) * icd->layer_count[gpu_index]);
747        if (! icd->wrappedGpus[gpu_index])
748                loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer");
749        for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
750            nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
751            nextGpuObj->pGPA = nextGPA;
752            nextGpuObj->baseObject = baseObj;
753            nextGpuObj->nextObject = gpuObj;
754            gpuObj = nextGpuObj;
755
756            char funcStr[256];
757            snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name);
758            if ((nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
759                nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, "xglGetProcAddr");
760            if (!nextGPA) {
761                loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to find xglGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name);
762                continue;
763            }
764
765            if (i == 0) {
766                loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj);
767                //Insert the new wrapped objects into the list with loader object at head
768                ((XGL_BASE_LAYER_OBJECT *) gpu)->nextObject = gpuObj;
769                ((XGL_BASE_LAYER_OBJECT *) gpu)->pGPA = nextGPA;
770                gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1;
771                gpuObj->nextObject = baseObj;
772                gpuObj->pGPA = icd->scanned_icds->GetProcAddr;
773            }
774
775        }
776    }
777    else {
778        //make sure requested Layers matches currently activated Layers
779        count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames);
780        for (uint32_t i = 0; i < count; i++) {
781            if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) {
782                loader_log(XGL_DBG_MSG_ERROR, 0, "Layers activated != Layers requested");
783                break;
784            }
785        }
786        if (count != icd->layer_count[gpu_index]) {
787            loader_log(XGL_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested");
788        }
789    }
790    return icd->layer_count[gpu_index];
791}
792
793LOADER_EXPORT XGL_RESULT XGLAPI xglCreateInstance(
794        const XGL_APPLICATION_INFO*                 pAppInfo,
795        const XGL_ALLOC_CALLBACKS*                  pAllocCb,
796        XGL_INSTANCE*                               pInstance)
797{
798    struct loader_instance *ptr_instance = NULL;
799
800    //TODO does this XGL_INSTANCE really have to be a dispatchable object??
801    ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance));
802    if (ptr_instance == NULL) {
803        return XGL_ERROR_OUT_OF_MEMORY;
804    }
805    memset(ptr_instance, 0, sizeof(struct loader_instance));
806
807    ptr_instance->app_info = pAppInfo;
808    ptr_instance->alloc_cb = pAllocCb;
809    ptr_instance->next = loader.instances;
810    loader.instances = ptr_instance;
811
812    *pInstance = (XGL_INSTANCE) ptr_instance;
813    // FIXME/TODO/TBD: WHAT ELSE NEEDS TO BE DONE?
814
815    return XGL_SUCCESS;
816}
817
818LOADER_EXPORT XGL_RESULT XGLAPI xglDestroyInstance(
819        XGL_INSTANCE                                instance)
820{
821    struct loader_instance *ptr_instance = (struct loader_instance *) instance;
822
823    // Remove this instance from the list of instances:
824    struct loader_instance *prev = NULL;
825    struct loader_instance *next = loader.instances;
826    while (next != NULL) {
827        if (next == ptr_instance) {
828            // Remove this instance from the list:
829            if (prev)
830                prev->next = next->next;
831            break;
832        }
833        prev = next;
834        next = next->next;
835    }
836    if (next  == NULL) {
837        // This must be an invalid instance handle or empty list
838        return XGL_ERROR_INVALID_HANDLE;
839    }
840
841    // FIXME/TODO/TBD: WHAT ELSE NEEDS TO BE DONE HERE???
842
843    // Now, remove the instance:
844    free(ptr_instance);
845
846    return XGL_SUCCESS;
847}
848
849LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateGpus(
850
851        XGL_INSTANCE                                instance,
852        uint32_t                                    maxGpus,
853        uint32_t*                                   pGpuCount,
854        XGL_PHYSICAL_GPU*                           pGpus)
855{
856    // FIXME/TODO/TBD: WHAT ELSE NEEDS TO BE DONE HERE???
857    return XGL_SUCCESS;
858}
859
860LOADER_EXPORT void * XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const char * pName)
861{
862    if (gpu == NULL)
863        return NULL;
864    XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) gpu;
865    XGL_LAYER_DISPATCH_TABLE * disp_table = * (XGL_LAYER_DISPATCH_TABLE **) gpuw->baseObject;
866    void *addr;
867
868    if (disp_table == NULL)
869        return NULL;
870
871    addr = loader_lookup_dispatch_table(disp_table, pName);
872    if (addr)
873        return addr;
874    else  {
875        if (disp_table->GetProcAddr == NULL)
876            return NULL;
877        return disp_table->GetProcAddr(gpuw->nextObject, pName);
878    }
879}
880
881LOADER_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)
882{
883    static pthread_once_t once = PTHREAD_ONCE_INIT;
884    struct loader_icd *icd;
885    uint32_t count = 0;
886    XGL_RESULT res;
887    struct loader_scanned_icds *scanned_icds;
888
889    pthread_once(&once, loader_icd_scan);
890
891    // for now only one instance
892    if (loader.instances == NULL) {
893        loader.instances = malloc(sizeof(struct loader_instance));
894        if (loader.instances == NULL)
895            return XGL_ERROR_UNAVAILABLE;
896        memset(loader.instances, 0, sizeof(struct loader_instance));
897
898        scanned_icds = loader.scanned_icd_list;
899        while (scanned_icds) {
900            loader_icd_add(scanned_icds);
901            scanned_icds = scanned_icds->next;
902        }
903
904        if (loader.instances->icds == NULL)
905            return XGL_ERROR_UNAVAILABLE;
906    }
907
908    // cleanup any prior layer initializations
909    loader_deactivate_layer(loader.instances);
910
911
912    icd = loader.instances->icds;
913    while (icd) {
914        XGL_PHYSICAL_GPU gpus[XGL_MAX_PHYSICAL_GPUS];
915        XGL_BASE_LAYER_OBJECT * wrappedGpus;
916        xglGetProcAddrType getProcAddr = icd->scanned_icds->GetProcAddr;
917        uint32_t n, max = maxGpus - count;
918
919        if (max > XGL_MAX_PHYSICAL_GPUS) {
920            max = XGL_MAX_PHYSICAL_GPUS;
921        }
922
923        res = icd->scanned_icds->InitAndEnumerateGpus(pAppInfo, pAllocCb, max, &n, gpus);
924        if (res == XGL_SUCCESS && n) {
925            wrappedGpus = (XGL_BASE_LAYER_OBJECT*) malloc(n * sizeof(XGL_BASE_LAYER_OBJECT));
926            icd->gpus = wrappedGpus;
927            icd->gpu_count = n;
928            icd->loader_dispatch = (XGL_LAYER_DISPATCH_TABLE *) malloc(n * sizeof(XGL_LAYER_DISPATCH_TABLE));
929            for (int i = 0; i < n; i++) {
930                (wrappedGpus + i)->baseObject = gpus[i];
931                (wrappedGpus + i)->pGPA = getProcAddr;
932                (wrappedGpus + i)->nextObject = gpus[i];
933                memcpy(pGpus + count, &wrappedGpus, sizeof(*pGpus));
934                loader_init_dispatch_table(icd->loader_dispatch + i, getProcAddr, gpus[i]);
935                const XGL_LAYER_DISPATCH_TABLE * *disp = (const XGL_LAYER_DISPATCH_TABLE *  *) gpus[i];
936                *disp = icd->loader_dispatch + i;
937            }
938
939            if (loader_icd_set_global_options(icd) != XGL_SUCCESS ||
940                loader_icd_register_msg_callbacks(icd) != XGL_SUCCESS) {
941                loader_log(XGL_DBG_MSG_WARNING, 0,
942                        "ICD ignored: failed to migrate settings");
943                loader_icd_destroy(icd);
944            }
945            count += n;
946
947            if (count >= maxGpus) {
948                break;
949            }
950        }
951
952        icd = icd->next;
953    }
954
955    /* we have nothing to log anymore */
956    loader_msg_callback_clear();
957
958    /* get layer libraries */
959    if (!loader.layer_scanned)
960        layer_lib_scan(NULL);
961
962    *pGpuCount = count;
963
964    return (count > 0) ? XGL_SUCCESS : res;
965}
966
967LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
968{
969    uint32_t gpu_index;
970    uint32_t count = 0;
971    char *lib_name;
972    struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index);
973    void *handle;
974    xglEnumerateLayersType fpEnumerateLayers;
975    char layer_buf[16][256];
976    char * layers[16];
977
978    if (pOutLayerCount == NULL || pOutLayers == NULL)
979        return XGL_ERROR_INVALID_POINTER;
980
981    if (!icd)
982        return XGL_ERROR_UNAVAILABLE;
983
984    for (int i = 0; i < 16; i++)
985         layers[i] = &layer_buf[i][0];
986
987    for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
988        lib_name = loader.scanned_layer_names[j];
989        if ((handle = dlopen(lib_name, RTLD_LAZY)) == NULL)
990            continue;
991        if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) {
992            //use default layer name based on library name libXGLLayer<name>.so
993            char *pEnd, *cpyStr;
994            int siz;
995            dlclose(handle);
996            lib_name = basename(lib_name);
997            pEnd = strrchr(lib_name, '.');
998            siz = pEnd - lib_name - strlen("libXGLLayer") + 1;
999            if (pEnd == NULL || siz <= 0)
1000                continue;
1001            cpyStr = malloc(siz);
1002            if (cpyStr == NULL) {
1003                free(cpyStr);
1004                continue;
1005            }
1006            strncpy(cpyStr, lib_name + strlen("libXGLLayer"), siz);
1007            cpyStr[siz - 1] = '\0';
1008            if (siz > maxStringSize)
1009                siz = maxStringSize;
1010            strncpy((char *) (pOutLayers[count]), cpyStr, siz);
1011            pOutLayers[count][siz - 1] = '\0';
1012            count++;
1013            free(cpyStr);
1014        }
1015        else {
1016            size_t cnt;
1017            uint32_t n;
1018            XGL_RESULT res;
1019            n = (maxStringSize < 256) ? maxStringSize : 256;
1020            res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (void *) icd->gpus + gpu_index);
1021            dlclose(handle);
1022            if (res != XGL_SUCCESS)
1023                continue;
1024            if (cnt + count > maxLayerCount)
1025                cnt = maxLayerCount - count;
1026            for (unsigned int i = count; i < cnt + count; i++) {
1027                strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n);
1028                if (n > 0)
1029                    pOutLayers[i - count][n - 1] = '\0';
1030            }
1031            count += cnt;
1032        }
1033    }
1034
1035    *pOutLayerCount = count;
1036
1037    return XGL_SUCCESS;
1038}
1039
1040LOADER_EXPORT XGL_RESULT XGLAPI xglDbgRegisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData)
1041{
1042    const struct loader_icd *icd;
1043    XGL_RESULT res;
1044    uint32_t gpu_idx;
1045
1046    //TODO fix for uncreated instances
1047    if (!loader.icds_scanned) {
1048        return loader_msg_callback_add(pfnMsgCallback, pUserData);
1049    }
1050
1051    //TODO go through all  instances
1052    for (icd = loader.instances->icds; icd; icd = icd->next) {
1053        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1054            res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(pfnMsgCallback, pUserData);
1055            if (res != XGL_SUCCESS) {
1056                gpu_idx = i;
1057                break;
1058            }
1059        }
1060        if (res != XGL_SUCCESS)
1061            break;
1062    }
1063
1064    /* roll back on errors */
1065    if (icd) {
1066        for (const struct loader_icd * tmp = loader.instances->icds; tmp != icd; tmp = tmp->next) {
1067            for (uint32_t i = 0; i < icd->gpu_count; i++)
1068                (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback);
1069        }
1070        /* and gpus on current icd */
1071        for (uint32_t i = 0; i < gpu_idx; i++)
1072            (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback);
1073
1074        return res;
1075    }
1076
1077    return XGL_SUCCESS;
1078}
1079
1080LOADER_EXPORT XGL_RESULT XGLAPI xglDbgUnregisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback)
1081{
1082    XGL_RESULT res = XGL_SUCCESS;\
1083
1084    //TODO fix for uncreated instances
1085    if (!loader.icds_scanned) {
1086        return loader_msg_callback_remove(pfnMsgCallback);
1087    }
1088
1089    //TODO loop through all instances
1090    for (const struct loader_icd * icd = loader.instances->icds; icd; icd = icd->next) {
1091        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1092            XGL_RESULT r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback);
1093            if (r != XGL_SUCCESS) {
1094                res = r;
1095            }
1096        }
1097    }
1098    return res;
1099}
1100
1101LOADER_EXPORT XGL_RESULT XGLAPI xglDbgSetGlobalOption(XGL_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData)
1102{
1103    XGL_RESULT res = XGL_SUCCESS;
1104
1105    if (!loader.icds_scanned) {
1106        if (dataSize == 0)
1107            return XGL_ERROR_INVALID_VALUE;
1108
1109        switch (dbgOption) {
1110        case XGL_DBG_OPTION_DEBUG_ECHO_ENABLE:
1111            loader.debug_echo_enable = *((const bool *) pData);
1112            break;
1113        case XGL_DBG_OPTION_BREAK_ON_ERROR:
1114            loader.break_on_error = *((const bool *) pData);
1115            break;
1116        case XGL_DBG_OPTION_BREAK_ON_WARNING:
1117            loader.break_on_warning = *((const bool *) pData);
1118            break;
1119        default:
1120            res = XGL_ERROR_INVALID_VALUE;
1121            break;
1122        }
1123
1124        return res;
1125    }
1126
1127    //TODO loop through all instances
1128    for (const struct loader_icd * icd = loader.instances->icds; icd; icd = icd->next) {
1129        for (uint32_t i = 0; i < icd->gpu_count; i++) {
1130            XGL_RESULT r = (icd->loader_dispatch + i)->DbgSetGlobalOption(dbgOption, dataSize, pData);
1131            /* unfortunately we cannot roll back */
1132            if (r != XGL_SUCCESS) {
1133                res = r;
1134            }
1135        }
1136    }
1137
1138    return res;
1139}
1140