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