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