loader.c revision 68af55ef8c0319cd5b0ec0f75f60d05870dfeb89
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 XGL_UINT 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 XGL_UINT gpu_count; 63 XGL_BASE_LAYER_OBJECT *gpus; 64 65 GetProcAddrType GetProcAddr; 66 InitAndEnumerateGpusType InitAndEnumerateGpus; 67 68 struct loader_icd *next; 69}; 70 71 72struct loader_msg_callback { 73 XGL_DBG_MSG_CALLBACK_FUNCTION func; 74 XGL_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 XGL_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, XGL_INT 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 = (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 (XGL_UINT 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 (XGL_UINT 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 (XGL_UINT 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 continue; 440 if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) { 441 loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str); 442 break; 443 } 444 if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) { 445 loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str); 446 break; 447 } 448 strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str); 449 loader.scanned_layer_count++; 450 dlclose(handle); 451 } 452 453 dent = readdir(curdir); 454 } 455 closedir(curdir); 456 } 457 } 458 459 loader.layer_scanned = true; 460} 461 462static void loader_init_dispatch_table(XGL_LAYER_DISPATCH_TABLE *tab, GetProcAddrType fpGPA, XGL_PHYSICAL_GPU gpu) 463{ 464 loader_initialize_dispatch_table(tab, fpGPA, gpu); 465 466 if (tab->EnumerateLayers == NULL) 467 tab->EnumerateLayers = xglEnumerateLayers; 468} 469 470static struct loader_icd * loader_get_icd(const XGL_BASE_LAYER_OBJECT *gpu, XGL_UINT *gpu_index) 471{ 472 for (struct loader_icd * icd = loader.icds; icd; icd = icd->next) { 473 for (XGL_UINT i = 0; i < icd->gpu_count; i++) 474 if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject == gpu->baseObject) { 475 *gpu_index = i; 476 return icd; 477 } 478 } 479 return NULL; 480} 481 482static bool loader_layers_activated(const struct loader_icd *icd, const XGL_UINT gpu_index) 483{ 484 if (icd->layer_count[gpu_index]) 485 return true; 486 else 487 return false; 488} 489 490static void loader_init_layer_libs(struct loader_icd *icd, XGL_UINT gpu_index, struct layer_name_pair * pLayerNames, XGL_UINT count) 491{ 492 if (!icd) 493 return; 494 495 struct loader_layers *obj; 496 bool foundLib; 497 for (XGL_UINT i = 0; i < count; i++) { 498 foundLib = false; 499 for (XGL_UINT j = 0; j < icd->layer_count[gpu_index]; j++) { 500 if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) { 501 foundLib = true; 502 break; 503 } 504 } 505 if (!foundLib) { 506 obj = &(icd->layer_libs[gpu_index][i]); 507 strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1); 508 obj->name[sizeof(obj->name) - 1] = '\0'; 509 if ((obj->lib_handle = dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)) == NULL) { 510 loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to open layer library %s got error %d", pLayerNames[i].lib_name, dlerror()); 511 continue; 512 } else { 513 loader_log(XGL_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name); 514 } 515 free(pLayerNames[i].layer_name); 516 icd->layer_count[gpu_index]++; 517 } 518 } 519} 520 521static bool find_layer_name(struct loader_icd *icd, XGL_UINT gpu_index, const char * layer_name, const char **lib_name) 522{ 523 void *handle; 524 EnumerateLayersType fpEnumerateLayers; 525 XGL_CHAR layer_buf[16][256]; 526 XGL_CHAR * layers[16]; 527 528 for (int i = 0; i < 16; i++) 529 layers[i] = &layer_buf[i][0]; 530 531 for (unsigned int j = 0; j < loader.scanned_layer_count; j++) { 532 *lib_name = loader.scanned_layer_names[j]; 533 if ((handle = dlopen(*lib_name, RTLD_LAZY)) == NULL) 534 continue; 535 if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) { 536 //use default layer name based on library name libXGLLayer<name>.so 537 char * lib_str = malloc(strlen(*lib_name) + 1 + strlen(layer_name)); 538 snprintf(lib_str, strlen(*lib_name) + strlen(layer_name), "libXGLLayer%s.so", layer_name); 539 dlclose(handle); 540 if (!strcmp(basename(*lib_name), lib_str)) { 541 free(lib_str); 542 return true; 543 } 544 else { 545 free(lib_str); 546 continue; 547 } 548 } 549 else { 550 XGL_SIZE cnt; 551 fpEnumerateLayers(NULL, 16, 256, layers, &cnt, (XGL_VOID *) icd->gpus + gpu_index); 552 for (unsigned int i = 0; i < cnt; i++) { 553 if (!strcmp((char *) layers[i], layer_name)) { 554 dlclose(handle); 555 return true; 556 } 557 } 558 } 559 560 dlclose(handle); 561 } 562 563 return false; 564} 565 566static XGL_UINT loader_get_layer_env(struct loader_icd *icd, XGL_UINT gpu_index, struct layer_name_pair *pLayerNames) 567{ 568 const char *layerEnv; 569 XGL_UINT len, count = 0; 570 char *p, *pOrig, *next, *name; 571 572 layerEnv = getenv("LIBXGL_LAYER_NAMES"); 573 if (!layerEnv) 574 return 0; 575 p = malloc(strlen(layerEnv) + 1); 576 if (!p) 577 return 0; 578 strcpy(p, layerEnv); 579 pOrig = p; 580 581 while (p && *p && count < MAX_LAYER_LIBRARIES) { 582 const char *lib_name = NULL; 583 next = strchr(p, ':'); 584 if (next == NULL) { 585 len = strlen(p); 586 next = p + len; 587 } 588 else { 589 len = next - p; 590 *(char *) next = '\0'; 591 next++; 592 } 593 name = basename(p); 594 if (!find_layer_name(icd, gpu_index, name, &lib_name)) { 595 p = next; 596 continue; 597 } 598 599 len = strlen(name); 600 pLayerNames[count].layer_name = malloc(len + 1); 601 if (!pLayerNames[count].layer_name) { 602 free(pOrig); 603 return count; 604 } 605 strncpy((char *) pLayerNames[count].layer_name, name, len); 606 pLayerNames[count].layer_name[len] = '\0'; 607 pLayerNames[count].lib_name = lib_name; 608 count++; 609 p = next; 610 611 }; 612 613 free(pOrig); 614 return count; 615} 616 617static XGL_UINT loader_get_layer_libs(struct loader_icd *icd, XGL_UINT gpu_index, const XGL_DEVICE_CREATE_INFO* pCreateInfo, struct layer_name_pair **ppLayerNames) 618{ 619 static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES]; 620 621 *ppLayerNames = &layerNames[0]; 622 if (!pCreateInfo) { 623 return loader_get_layer_env(icd, gpu_index, layerNames); 624 } 625 626 XGL_LAYER_CREATE_INFO *pCi = (XGL_LAYER_CREATE_INFO *) pCreateInfo->pNext; 627 628 while (pCi) { 629 if (pCi->sType == XGL_STRUCTURE_TYPE_LAYER_CREATE_INFO) { 630 const char *name; 631 XGL_UINT len; 632 for (XGL_UINT i = 0; i < pCi->layerCount; i++) { 633 const char * lib_name = NULL; 634 name = *(pCi->ppActiveLayerNames + i); 635 if (!find_layer_name(icd, gpu_index, name, &lib_name)) 636 return loader_get_layer_env(icd, gpu_index, layerNames); 637 len = strlen(name); 638 layerNames[i].layer_name = malloc(len + 1); 639 if (!layerNames[i].layer_name) 640 return i; 641 strncpy((char *) layerNames[i].layer_name, name, len); 642 layerNames[i].layer_name[len] = '\0'; 643 layerNames[i].lib_name = lib_name; 644 } 645 return pCi->layerCount + loader_get_layer_env(icd, gpu_index, layerNames); 646 } 647 pCi = pCi->pNext; 648 } 649 return loader_get_layer_env(icd, gpu_index, layerNames); 650} 651 652static void loader_deactivate_layer() 653{ 654 struct loader_icd *icd; 655 struct loader_layers *libs; 656 657 for (icd = loader.icds; icd; icd = icd->next) { 658 if (icd->gpus) 659 free(icd->gpus); 660 icd->gpus = NULL; 661 if (icd->loader_dispatch) 662 free(icd->loader_dispatch); 663 icd->loader_dispatch = NULL; 664 for (XGL_UINT j = 0; j < icd->gpu_count; j++) { 665 if (icd->layer_count[j] > 0) { 666 for (XGL_UINT i = 0; i < icd->layer_count[j]; i++) { 667 libs = &(icd->layer_libs[j][i]); 668 if (libs->lib_handle) 669 dlclose(libs->lib_handle); 670 libs->lib_handle = NULL; 671 } 672 if (icd->wrappedGpus[j]) 673 free(icd->wrappedGpus[j]); 674 } 675 icd->layer_count[j] = 0; 676 } 677 icd->gpu_count = 0; 678 } 679} 680 681extern XGL_UINT loader_activate_layers(XGL_PHYSICAL_GPU gpu, const XGL_DEVICE_CREATE_INFO* pCreateInfo) 682{ 683 XGL_UINT gpu_index; 684 XGL_UINT count; 685 struct layer_name_pair *pLayerNames; 686 struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index); 687 688 if (!icd) 689 return 0; 690 assert(gpu_index < XGL_MAX_PHYSICAL_GPUS); 691 692 /* activate any layer libraries */ 693 if (!loader_layers_activated(icd, gpu_index)) { 694 XGL_BASE_LAYER_OBJECT *gpuObj = (XGL_BASE_LAYER_OBJECT *) gpu; 695 XGL_BASE_LAYER_OBJECT *nextGpuObj, *baseObj = gpuObj->baseObject; 696 GetProcAddrType nextGPA = xglGetProcAddr; 697 698 count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames); 699 if (!count) 700 return 0; 701 loader_init_layer_libs(icd, gpu_index, pLayerNames, count); 702 703 icd->wrappedGpus[gpu_index] = malloc(sizeof(XGL_BASE_LAYER_OBJECT) * icd->layer_count[gpu_index]); 704 if (! icd->wrappedGpus[gpu_index]) 705 loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer"); 706 for (XGL_INT i = icd->layer_count[gpu_index] - 1; i >= 0; i--) { 707 nextGpuObj = (icd->wrappedGpus[gpu_index] + i); 708 nextGpuObj->pGPA = nextGPA; 709 nextGpuObj->baseObject = baseObj; 710 nextGpuObj->nextObject = gpuObj; 711 gpuObj = nextGpuObj; 712 713 char funcStr[256]; 714 snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name); 715 if ((nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL) 716 nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, "xglGetProcAddr"); 717 if (!nextGPA) { 718 loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to find xglGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name); 719 continue; 720 } 721 722 if (i == 0) { 723 loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj); 724 //Insert the new wrapped objects into the list with loader object at head 725 ((XGL_BASE_LAYER_OBJECT *) gpu)->nextObject = gpuObj; 726 ((XGL_BASE_LAYER_OBJECT *) gpu)->pGPA = nextGPA; 727 gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1; 728 gpuObj->nextObject = baseObj; 729 gpuObj->pGPA = icd->GetProcAddr; 730 } 731 732 } 733 } 734 else { 735 //make sure requested Layers matches currently activated Layers 736 count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames); 737 for (XGL_UINT i = 0; i < count; i++) { 738 if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) { 739 loader_log(XGL_DBG_MSG_ERROR, 0, "Layers activated != Layers requested"); 740 break; 741 } 742 } 743 if (count != icd->layer_count[gpu_index]) { 744 loader_log(XGL_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested"); 745 } 746 } 747 return icd->layer_count[gpu_index]; 748} 749 750LOADER_EXPORT XGL_VOID * XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const XGL_CHAR * pName) { 751 752 if (gpu == NULL) 753 return NULL; 754 XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) gpu; 755 XGL_LAYER_DISPATCH_TABLE * disp_table = * (XGL_LAYER_DISPATCH_TABLE **) gpuw->baseObject; 756 void *addr; 757 758 if (disp_table == NULL) 759 return NULL; 760 761 addr = loader_lookup_dispatch_table(disp_table, pName); 762 if (addr) 763 return addr; 764 else { 765 if (disp_table->GetProcAddr == NULL) 766 return NULL; 767 return disp_table->GetProcAddr(gpuw->nextObject, pName); 768 } 769} 770 771LOADER_EXPORT XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO* pAppInfo, const XGL_ALLOC_CALLBACKS* pAllocCb, XGL_UINT maxGpus, XGL_UINT* pGpuCount, XGL_PHYSICAL_GPU* pGpus) 772{ 773 static pthread_once_t once = PTHREAD_ONCE_INIT; 774 struct loader_icd *icd; 775 XGL_UINT count = 0; 776 XGL_RESULT res; 777 778 // cleanup any prior layer initializations 779 loader_deactivate_layer(); 780 781 pthread_once(&once, loader_icd_scan); 782 783 if (!loader.icds) 784 return XGL_ERROR_UNAVAILABLE; 785 786 icd = loader.icds; 787 while (icd) { 788 XGL_PHYSICAL_GPU gpus[XGL_MAX_PHYSICAL_GPUS]; 789 XGL_BASE_LAYER_OBJECT * wrappedGpus; 790 GetProcAddrType getProcAddr = icd->GetProcAddr; 791 XGL_UINT n, max = maxGpus - count; 792 793 if (max > XGL_MAX_PHYSICAL_GPUS) { 794 max = XGL_MAX_PHYSICAL_GPUS; 795 } 796 797 res = icd->InitAndEnumerateGpus(pAppInfo, pAllocCb, max, &n, gpus); 798 if (res == XGL_SUCCESS && n) { 799 wrappedGpus = (XGL_BASE_LAYER_OBJECT*) malloc(n * sizeof(XGL_BASE_LAYER_OBJECT)); 800 icd->gpus = wrappedGpus; 801 icd->gpu_count = n; 802 icd->loader_dispatch = (XGL_LAYER_DISPATCH_TABLE *) malloc(n * sizeof(XGL_LAYER_DISPATCH_TABLE)); 803 for (int i = 0; i < n; i++) { 804 (wrappedGpus + i)->baseObject = gpus[i]; 805 (wrappedGpus + i)->pGPA = getProcAddr; 806 (wrappedGpus + i)->nextObject = gpus[i]; 807 memcpy(pGpus + count, &wrappedGpus, sizeof(*pGpus)); 808 loader_init_dispatch_table(icd->loader_dispatch + i, getProcAddr, gpus[i]); 809 const XGL_LAYER_DISPATCH_TABLE * *disp = (const XGL_LAYER_DISPATCH_TABLE * *) gpus[i]; 810 *disp = icd->loader_dispatch + i; 811 } 812 813 if (loader_icd_set_global_options(icd) != XGL_SUCCESS || 814 loader_icd_register_msg_callbacks(icd) != XGL_SUCCESS) { 815 loader_log(XGL_DBG_MSG_WARNING, 0, 816 "ICD ignored: failed to migrate settings"); 817 loader_icd_destroy(icd); 818 } 819 count += n; 820 821 if (count >= maxGpus) { 822 break; 823 } 824 } 825 826 icd = icd->next; 827 } 828 829 /* we have nothing to log anymore */ 830 loader_msg_callback_clear(); 831 832 /* get layer libraries */ 833 if (!loader.layer_scanned) 834 layer_lib_scan(NULL); 835 836 *pGpuCount = count; 837 838 return (count > 0) ? XGL_SUCCESS : res; 839} 840 841LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, XGL_SIZE maxLayerCount, XGL_SIZE maxStringSize, XGL_CHAR* const* pOutLayers, XGL_SIZE* pOutLayerCount, XGL_VOID* pReserved) 842{ 843 XGL_UINT gpu_index; 844 XGL_UINT count = 0; 845 char *lib_name; 846 struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index); 847 void *handle; 848 EnumerateLayersType fpEnumerateLayers; 849 XGL_CHAR layer_buf[16][256]; 850 XGL_CHAR * layers[16]; 851 852 if (pOutLayerCount == NULL || pOutLayers == NULL) 853 return XGL_ERROR_INVALID_POINTER; 854 855 for (int i = 0; i < 16; i++) 856 layers[i] = &layer_buf[i][0]; 857 858 for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) { 859 lib_name = loader.scanned_layer_names[j]; 860 if ((handle = dlopen(lib_name, RTLD_LAZY)) == NULL) 861 continue; 862 if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) { 863 //use default layer name based on library name libXGLLayer<name>.so 864 char *pEnd, *cpyStr; 865 int siz; 866 dlclose(handle); 867 lib_name = basename(lib_name); 868 pEnd = strrchr(lib_name, '.'); 869 siz = pEnd - lib_name - strlen("libXGLLayer") + 1; 870 if (pEnd == NULL || siz <= 0) 871 continue; 872 cpyStr = malloc(siz); 873 if (cpyStr == NULL) { 874 free(cpyStr); 875 continue; 876 } 877 strncpy(cpyStr, lib_name + strlen("libXGLLayer"), siz); 878 cpyStr[siz - 1] = '\0'; 879 if (siz > maxStringSize) 880 siz = maxStringSize; 881 strncpy((char *) (pOutLayers[count]), cpyStr, siz); 882 pOutLayers[count][siz - 1] = '\0'; 883 count++; 884 free(cpyStr); 885 } 886 else { 887 XGL_SIZE cnt; 888 XGL_UINT n; 889 XGL_RESULT res; 890 n = (maxStringSize < 256) ? maxStringSize : 256; 891 res = fpEnumerateLayers(NULL, 16, n, layers, &cnt, (XGL_VOID *) icd->gpus + gpu_index); 892 dlclose(handle); 893 if (res != XGL_SUCCESS) 894 continue; 895 if (cnt + count > maxLayerCount) 896 cnt = maxLayerCount - count; 897 for (unsigned int i = count; i < cnt + count; i++) { 898 strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n); 899 if (n > 0) 900 pOutLayers[i - count][n - 1] = '\0'; 901 } 902 count += cnt; 903 } 904 } 905 906 *pOutLayerCount = count; 907 908 return XGL_SUCCESS; 909} 910 911LOADER_EXPORT XGL_RESULT XGLAPI xglDbgRegisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, XGL_VOID* pUserData) 912{ 913 const struct loader_icd *icd; 914 XGL_RESULT res; 915 XGL_UINT gpu_idx; 916 917 if (!loader.scanned) { 918 return loader_msg_callback_add(pfnMsgCallback, pUserData); 919 } 920 921 for (icd = loader.icds; icd; icd = icd->next) { 922 for (XGL_UINT i = 0; i < icd->gpu_count; i++) { 923 res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(pfnMsgCallback, pUserData); 924 if (res != XGL_SUCCESS) { 925 gpu_idx = i; 926 break; 927 } 928 } 929 if (res != XGL_SUCCESS) 930 break; 931 } 932 933 /* roll back on errors */ 934 if (icd) { 935 for (const struct loader_icd * tmp = loader.icds; tmp != icd; tmp = tmp->next) { 936 for (XGL_UINT i = 0; i < icd->gpu_count; i++) 937 (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback); 938 } 939 /* and gpus on current icd */ 940 for (XGL_UINT i = 0; i < gpu_idx; i++) 941 (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback); 942 943 return res; 944 } 945 946 return XGL_SUCCESS; 947} 948 949LOADER_EXPORT XGL_RESULT XGLAPI xglDbgUnregisterMsgCallback(XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback) 950{ 951 XGL_RESULT res = XGL_SUCCESS; 952 953 if (!loader.scanned) { 954 return loader_msg_callback_remove(pfnMsgCallback); 955 } 956 957 for (const struct loader_icd * icd = loader.icds; icd; icd = icd->next) { 958 for (XGL_UINT i = 0; i < icd->gpu_count; i++) { 959 XGL_RESULT r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(pfnMsgCallback); 960 if (r != XGL_SUCCESS) { 961 res = r; 962 } 963 } 964 } 965 return res; 966} 967 968LOADER_EXPORT XGL_RESULT XGLAPI xglDbgSetGlobalOption(XGL_DBG_GLOBAL_OPTION dbgOption, XGL_SIZE dataSize, const XGL_VOID* pData) 969{ 970 XGL_RESULT res = XGL_SUCCESS; 971 972 if (!loader.scanned) { 973 if (dataSize == 0) 974 return XGL_ERROR_INVALID_VALUE; 975 976 switch (dbgOption) { 977 case XGL_DBG_OPTION_DEBUG_ECHO_ENABLE: 978 loader.debug_echo_enable = *((const bool *) pData); 979 break; 980 case XGL_DBG_OPTION_BREAK_ON_ERROR: 981 loader.break_on_error = *((const bool *) pData); 982 break; 983 case XGL_DBG_OPTION_BREAK_ON_WARNING: 984 loader.break_on_warning = *((const bool *) pData); 985 break; 986 default: 987 res = XGL_ERROR_INVALID_VALUE; 988 break; 989 } 990 991 return res; 992 } 993 994 for (const struct loader_icd * icd = loader.icds; icd; icd = icd->next) { 995 for (XGL_UINT i = 0; i < icd->gpu_count; i++) { 996 XGL_RESULT r = (icd->loader_dispatch + i)->DbgSetGlobalOption(dbgOption, dataSize, pData); 997 /* unfortunately we cannot roll back */ 998 if (r != XGL_SUCCESS) { 999 res = r; 1000 } 1001 } 1002 } 1003 1004 return res; 1005} 1006