loader.c revision c0db2af877997d454f3a9702f278e17cba9aa076
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 * Ian Elliott <ian@lunarg.com> 29 */ 30#define _GNU_SOURCE 31#include <stdio.h> 32#include <stdlib.h> 33#include <stdarg.h> 34#include <stdbool.h> 35#include <string.h> 36 37#include <sys/types.h> 38#if defined(WIN32) 39#include "dirent_on_windows.h" 40#else // WIN32 41#include <dirent.h> 42#endif // WIN32 43#include "loader_platform.h" 44#include "table_ops.h" 45#include "loader.h" 46#include "xglIcd.h" 47// The following is #included again to catch certain OS-specific functions 48// being used: 49#include "loader_platform.h" 50 51struct loader_instance { 52 struct loader_icd *icds; 53 struct loader_instance *next; 54}; 55 56struct loader_layers { 57 loader_platform_dl_handle lib_handle; 58 char name[256]; 59}; 60 61struct layer_name_pair { 62 char *layer_name; 63 const char *lib_name; 64}; 65 66struct loader_icd { 67 const struct loader_scanned_icds *scanned_icds; 68 69 XGL_LAYER_DISPATCH_TABLE *loader_dispatch; 70 uint32_t layer_count[XGL_MAX_PHYSICAL_GPUS]; 71 struct loader_layers layer_libs[XGL_MAX_PHYSICAL_GPUS][MAX_LAYER_LIBRARIES]; 72 XGL_BASE_LAYER_OBJECT *wrappedGpus[XGL_MAX_PHYSICAL_GPUS]; 73 uint32_t gpu_count; 74 XGL_BASE_LAYER_OBJECT *gpus; 75 76 struct loader_icd *next; 77}; 78 79 80struct loader_scanned_icds { 81 loader_platform_dl_handle handle; 82 xglGetProcAddrType GetProcAddr; 83 xglCreateInstanceType CreateInstance; 84 xglDestroyInstanceType DestroyInstance; 85 xglEnumerateGpusType EnumerateGpus; 86 XGL_INSTANCE instance; 87 struct loader_scanned_icds *next; 88}; 89 90// Note: Since the following is a static structure, all members are initialized 91// to zero. 92static struct { 93 struct loader_instance *instances; 94 bool icds_scanned; 95 struct loader_scanned_icds *scanned_icd_list; 96 bool layer_scanned; 97 char *layer_dirs; 98 unsigned int scanned_layer_count; 99 char *scanned_layer_names[MAX_LAYER_LIBRARIES]; 100} loader; 101 102 103#if defined(WIN32) 104char *loader_get_registry_string(const HKEY hive, 105 const LPCTSTR sub_key, 106 const char *value) 107{ 108 DWORD access_flags = KEY_QUERY_VALUE; 109 DWORD value_type; 110 HKEY key; 111 LONG rtn_value; 112 char *rtn_str = NULL; 113 size_t rtn_len = 0; 114 size_t allocated_len = 0; 115 116 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key); 117 if (rtn_value != ERROR_SUCCESS) { 118 // We didn't find the key. Try the 32-bit hive (where we've seen the 119 // key end up on some people's systems): 120 access_flags |= KEY_WOW64_32KEY; 121 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key); 122 if (rtn_value != ERROR_SUCCESS) { 123 // We still couldn't find the key, so give up: 124 return NULL; 125 } 126 } 127 128 rtn_value = RegQueryValueEx(key, value, NULL, &value_type, 129 (PVOID) rtn_str, &rtn_len); 130 if (rtn_value == ERROR_SUCCESS) { 131 // If we get to here, we found the key, and need to allocate memory 132 // large enough for rtn_str, and query again: 133 allocated_len = rtn_len + 4; 134 rtn_str = malloc(allocated_len); 135 rtn_value = RegQueryValueEx(key, value, NULL, &value_type, 136 (PVOID) rtn_str, &rtn_len); 137 if (rtn_value == ERROR_SUCCESS) { 138 // We added 4 extra bytes to rtn_str, so that we can ensure that 139 // the string is NULL-terminated (albeit, in a brute-force manner): 140 rtn_str[allocated_len-1] = '\0'; 141 } else { 142 // This should never occur, but in case it does, clean up: 143 free(rtn_str); 144 rtn_str = NULL; 145 } 146 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL 147 148 // Close the registry key that was opened: 149 RegCloseKey(key); 150 151 return rtn_str; 152} 153 154 155// For ICD developers, look in the registry, and look for an environment 156// variable for a path(s) where to find the ICD(s): 157static char *loader_get_registry_and_env(const char *env_var, 158 const char *registry_value) 159{ 160 char *env_str = getenv(env_var); 161 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str); 162 char *registry_str = NULL; 163 DWORD registry_len = 0; 164 char *rtn_str = NULL; 165 size_t rtn_len; 166 167 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE, 168 "Software\\XGL", 169 registry_value); 170 registry_len = (registry_str) ? strlen(registry_str) : 0; 171 172 rtn_len = env_len + registry_len + 1; 173 if (rtn_len <= 2) { 174 // We found neither the desired registry value, nor the environment 175 // variable; return NULL: 176 return NULL; 177 } else { 178 // We found something, and so we need to allocate memory for the string 179 // to return: 180 rtn_str = malloc(rtn_len); 181 } 182 183 if (registry_len == 0) { 184 // We didn't find the desired registry value, and so we must have found 185 // only the environment variable: 186 _snprintf(rtn_str, rtn_len, "%s", env_str); 187 } else if (env_str != NULL) { 188 // We found both the desired registry value and the environment 189 // variable, so concatenate them both: 190 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str); 191 } else { 192 // We must have only found the desired registry value: 193 _snprintf(rtn_str, rtn_len, "%s", registry_str); 194 } 195 196 if (registry_str) { 197 free(registry_str); 198 } 199 200 return(rtn_str); 201} 202#endif // WIN32 203 204 205static void loader_log(XGL_DBG_MSG_TYPE msg_type, int32_t msg_code, 206 const char *format, ...) 207{ 208 char msg[256]; 209 va_list ap; 210 int ret; 211 212 va_start(ap, format); 213 ret = vsnprintf(msg, sizeof(msg), format, ap); 214 if ((ret >= (int) sizeof(msg)) || ret < 0) { 215 msg[sizeof(msg) - 1] = '\0'; 216 } 217 va_end(ap); 218 219 fputs(msg, stderr); 220 fputc('\n', stderr); 221} 222 223static void 224loader_icd_destroy(struct loader_icd *icd) 225{ 226 loader_platform_close_library(icd->scanned_icds->handle); 227 free(icd); 228} 229 230static struct loader_icd * 231loader_icd_create(const struct loader_scanned_icds *scanned) 232{ 233 struct loader_icd *icd; 234 235 icd = malloc(sizeof(*icd)); 236 if (!icd) 237 return NULL; 238 239 memset(icd, 0, sizeof(*icd)); 240 241 icd->scanned_icds = scanned; 242 243 return icd; 244} 245 246static struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst, 247 const struct loader_scanned_icds *scanned) 248{ 249 struct loader_icd *icd; 250 251 icd = loader_icd_create(scanned); 252 if (!icd) 253 return NULL; 254 255 /* prepend to the list */ 256 icd->next = ptr_inst->icds; 257 ptr_inst->icds = icd; 258 259 return icd; 260} 261 262static void loader_scanned_icd_add(const char *filename) 263{ 264 loader_platform_dl_handle handle; 265 void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst; 266 struct loader_scanned_icds *new_node; 267 268 // Used to call: dlopen(filename, RTLD_LAZY); 269 handle = loader_platform_open_library(filename); 270 if (!handle) { 271 loader_log(XGL_DBG_MSG_WARNING, 0, loader_platform_open_library_error(filename)); 272 return; 273 } 274 275#define LOOKUP(func_ptr, func) do { \ 276 func_ptr = (xgl ##func## Type) loader_platform_get_proc_address(handle, "xgl" #func); \ 277 if (!func_ptr) { \ 278 loader_log(XGL_DBG_MSG_WARNING, 0, loader_platform_get_proc_address_error("xgl" #func)); \ 279 return; \ 280 } \ 281} while (0) 282 283 LOOKUP(fp_gpa, GetProcAddr); 284 LOOKUP(fp_create_inst, CreateInstance); 285 LOOKUP(fp_destroy_inst, DestroyInstance); 286 LOOKUP(fp_enumerate, EnumerateGpus); 287#undef LOOKUP 288 289 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)); 290 if (!new_node) { 291 loader_log(XGL_DBG_MSG_WARNING, 0, "Out of memory can't add icd"); 292 return; 293 } 294 295 new_node->handle = handle; 296 new_node->GetProcAddr = fp_gpa; 297 new_node->CreateInstance = fp_create_inst; 298 new_node->DestroyInstance = fp_destroy_inst; 299 new_node->EnumerateGpus = fp_enumerate; 300 new_node->next = loader.scanned_icd_list; 301 loader.scanned_icd_list = new_node; 302} 303 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 *p, *next; 318 char *libPaths = NULL; 319 DIR *sysdir; 320 struct dirent *dent; 321 char icd_library[1024]; 322 char path[1024]; 323 uint32_t len; 324#if defined(WIN32) 325 bool must_free_libPaths; 326 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV, 327 DRIVER_PATH_REGISTRY_VALUE); 328 if (libPaths != NULL) { 329 must_free_libPaths = true; 330 } else { 331 must_free_libPaths = false; 332 libPaths = DEFAULT_XGL_DRIVERS_PATH; 333 } 334#else // WIN32 335 if (geteuid() == getuid()) { 336 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */ 337 libPaths = getenv(DRIVER_PATH_ENV); 338 } 339 if (libPaths == NULL) { 340 libPaths = DEFAULT_XGL_DRIVERS_PATH; 341 } 342#endif // WIN32 343 344 for (p = libPaths; *p; p = next) { 345 next = strchr(p, PATH_SEPERATOR); 346 if (next == NULL) { 347 len = (uint32_t) strlen(p); 348 next = p + len; 349 } 350 else { 351 len = (uint32_t) (next - p); 352 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p); 353 p = path; 354 next++; 355 } 356 357 // TODO/TBD: Do we want to do this on Windows, or just let Windows take 358 // care of its own search path (which it apparently has)? 359 sysdir = opendir(p); 360 if (sysdir) { 361 dent = readdir(sysdir); 362 while (dent) { 363 /* Look for ICDs starting with XGL_DRIVER_LIBRARY_PREFIX and 364 * ending with XGL_LIBRARY_SUFFIX 365 */ 366 if (!strncmp(dent->d_name, 367 XGL_DRIVER_LIBRARY_PREFIX, 368 XGL_DRIVER_LIBRARY_PREFIX_LEN)) { 369 uint32_t nlen = (uint32_t) strlen(dent->d_name); 370 const char *suf = dent->d_name + nlen - XGL_LIBRARY_SUFFIX_LEN; 371 if ((nlen > XGL_LIBRARY_SUFFIX_LEN) && 372 !strncmp(suf, 373 XGL_LIBRARY_SUFFIX, 374 XGL_LIBRARY_SUFFIX_LEN)) { 375 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name); 376 loader_scanned_icd_add(icd_library); 377 } 378 } 379 380 dent = readdir(sysdir); 381 } 382 closedir(sysdir); 383 } 384 } 385 386#if defined(WIN32) 387 // Free any allocated memory: 388 if (must_free_libPaths) { 389 free(libPaths); 390 } 391#endif // WIN32 392 393 // Note that we've scanned for ICDs: 394 loader.icds_scanned = true; 395} 396 397 398static void layer_lib_scan(void) 399{ 400 const char *p, *next; 401 char *libPaths = NULL; 402 DIR *curdir; 403 struct dirent *dent; 404 size_t len, i; 405 char temp_str[1024]; 406 407#if defined(WIN32) 408 bool must_free_libPaths; 409 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV, 410 LAYERS_PATH_REGISTRY_VALUE); 411 if (libPaths != NULL) { 412 must_free_libPaths = true; 413 } else { 414 must_free_libPaths = false; 415 libPaths = DEFAULT_XGL_LAYERS_PATH; 416 } 417#else // WIN32 418 if (geteuid() == getuid()) { 419 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */ 420 libPaths = getenv(LAYERS_PATH_ENV); 421 } 422 if (libPaths == NULL) { 423 libPaths = DEFAULT_XGL_LAYERS_PATH; 424 } 425#endif // WIN32 426 427 if (libPaths == NULL) { 428 // Have no paths to search: 429 return; 430 } 431 len = strlen(libPaths); 432 loader.layer_dirs = malloc(len+1); 433 if (loader.layer_dirs == NULL) { 434 free(libPaths); 435 return; 436 } 437 // Alloc passed, so we know there is enough space to hold the string, don't 438 // need strncpy 439 strcpy(loader.layer_dirs, libPaths); 440#if defined(WIN32) 441 // Free any allocated memory: 442 if (must_free_libPaths) { 443 free(libPaths); 444 must_free_libPaths = false; 445 } 446#endif // WIN32 447 libPaths = loader.layer_dirs; 448 449 /* cleanup any previously scanned libraries */ 450 for (i = 0; i < loader.scanned_layer_count; i++) { 451 if (loader.scanned_layer_names[i] != NULL) 452 free(loader.scanned_layer_names[i]); 453 loader.scanned_layer_names[i] = NULL; 454 } 455 loader.scanned_layer_count = 0; 456 457 for (p = libPaths; *p; p = next) { 458 next = strchr(p, PATH_SEPERATOR); 459 if (next == NULL) { 460 len = (uint32_t) strlen(p); 461 next = p + len; 462 } 463 else { 464 len = (uint32_t) (next - p); 465 *(char *) next = '\0'; 466 next++; 467 } 468 469 curdir = opendir(p); 470 if (curdir) { 471 dent = readdir(curdir); 472 while (dent) { 473 /* Look for layers starting with XGL_LAYER_LIBRARY_PREFIX and 474 * ending with XGL_LIBRARY_SUFFIX 475 */ 476 if (!strncmp(dent->d_name, 477 XGL_LAYER_LIBRARY_PREFIX, 478 XGL_LAYER_LIBRARY_PREFIX_LEN)) { 479 uint32_t nlen = (uint32_t) strlen(dent->d_name); 480 const char *suf = dent->d_name + nlen - XGL_LIBRARY_SUFFIX_LEN; 481 if ((nlen > XGL_LIBRARY_SUFFIX_LEN) && 482 !strncmp(suf, 483 XGL_LIBRARY_SUFFIX, 484 XGL_LIBRARY_SUFFIX_LEN)) { 485 loader_platform_dl_handle handle; 486 snprintf(temp_str, sizeof(temp_str), "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name); 487 // Used to call: dlopen(temp_str, RTLD_LAZY) 488 if ((handle = loader_platform_open_library(temp_str)) == NULL) { 489 dent = readdir(curdir); 490 continue; 491 } 492 if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) { 493 loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str); 494 break; 495 } 496 if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) { 497 loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str); 498 break; 499 } 500 strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str); 501 loader.scanned_layer_count++; 502 loader_platform_close_library(handle); 503 } 504 } 505 506 dent = readdir(curdir); 507 } 508 closedir(curdir); 509 } 510 } 511 512 loader.layer_scanned = true; 513} 514 515static void loader_init_dispatch_table(XGL_LAYER_DISPATCH_TABLE *tab, xglGetProcAddrType fpGPA, XGL_PHYSICAL_GPU gpu) 516{ 517 loader_initialize_dispatch_table(tab, fpGPA, gpu); 518 519 if (tab->EnumerateLayers == NULL) 520 tab->EnumerateLayers = xglEnumerateLayers; 521} 522 523static struct loader_icd * loader_get_icd(const XGL_BASE_LAYER_OBJECT *gpu, uint32_t *gpu_index) 524{ 525 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 526 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 527 for (uint32_t i = 0; i < icd->gpu_count; i++) 528 if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject == 529 gpu->baseObject) { 530 *gpu_index = i; 531 return icd; 532 } 533 } 534 } 535 return NULL; 536} 537 538static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index) 539{ 540 if (icd->layer_count[gpu_index]) 541 return true; 542 else 543 return false; 544} 545 546static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair * pLayerNames, uint32_t count) 547{ 548 if (!icd) 549 return; 550 551 struct loader_layers *obj; 552 bool foundLib; 553 for (uint32_t i = 0; i < count; i++) { 554 foundLib = false; 555 for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) { 556 if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) { 557 foundLib = true; 558 break; 559 } 560 } 561 if (!foundLib) { 562 obj = &(icd->layer_libs[gpu_index][i]); 563 strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1); 564 obj->name[sizeof(obj->name) - 1] = '\0'; 565 // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND) 566 if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) { 567 loader_log(XGL_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name)); 568 continue; 569 } else { 570 loader_log(XGL_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name); 571 } 572 free(pLayerNames[i].layer_name); 573 icd->layer_count[gpu_index]++; 574 } 575 } 576} 577 578static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const char * layer_name, const char **lib_name) 579{ 580 loader_platform_dl_handle handle; 581 xglEnumerateLayersType fpEnumerateLayers; 582 char layer_buf[16][256]; 583 char * layers[16]; 584 585 for (int i = 0; i < 16; i++) 586 layers[i] = &layer_buf[i][0]; 587 588 for (unsigned int j = 0; j < loader.scanned_layer_count; j++) { 589 *lib_name = loader.scanned_layer_names[j]; 590 // Used to call: dlopen(*lib_name, RTLD_LAZY) 591 if ((handle = loader_platform_open_library(*lib_name)) == NULL) 592 continue; 593 if ((fpEnumerateLayers = (xglEnumerateLayersType) loader_platform_get_proc_address(handle, "xglEnumerateLayers")) == NULL) { 594 char * lib_str = malloc(strlen(*lib_name) + 1 + strlen(layer_name)); 595 //use default layer name 596 snprintf(lib_str, strlen(*lib_name) + strlen(layer_name), 597 XGL_LAYER_LIBRARY_PREFIX "%s" XGL_LIBRARY_SUFFIX, 598 layer_name); 599 loader_platform_close_library(handle); 600 if (!strcmp(*lib_name, lib_str)) { 601 free(lib_str); 602 return true; 603 } 604 else { 605 free(lib_str); 606 continue; 607 } 608 } 609 else { 610 size_t cnt; 611 fpEnumerateLayers(NULL, 16, 256, &cnt, layers, (char *) icd->gpus + gpu_index); 612 for (unsigned int i = 0; i < cnt; i++) { 613 if (!strcmp((char *) layers[i], layer_name)) { 614 loader_platform_close_library(handle); 615 return true; 616 } 617 } 618 } 619 620 loader_platform_close_library(handle); 621 } 622 623 return false; 624} 625 626static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames) 627{ 628 char *layerEnv; 629 uint32_t len, count = 0; 630 char *p, *pOrig, *next, *name; 631 632#if defined(WIN32) 633 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV, 634 LAYER_NAMES_REGISTRY_VALUE); 635#else // WIN32 636 layerEnv = getenv(LAYER_NAMES_ENV); 637#endif // WIN32 638 if (layerEnv == NULL) { 639 return 0; 640 } 641 p = malloc(strlen(layerEnv) + 1); 642 if (p == NULL) { 643#if defined(WIN32) 644 free(layerEnv); 645#endif // WIN32 646 return 0; 647 } 648 strcpy(p, layerEnv); 649#if defined(WIN32) 650 free(layerEnv); 651#endif // WIN32 652 pOrig = p; 653 654 while (p && *p && count < MAX_LAYER_LIBRARIES) { 655 const char *lib_name = NULL; 656 next = strchr(p, PATH_SEPERATOR); 657 if (next == NULL) { 658 len = (uint32_t) strlen(p); 659 next = p + len; 660 } 661 else { 662 len = (uint32_t) (next - p); 663 *(char *) next = '\0'; 664 next++; 665 } 666 name = basename(p); 667 if (!find_layer_name(icd, gpu_index, name, &lib_name)) { 668 p = next; 669 continue; 670 } 671 672 len = (uint32_t) strlen(name); 673 pLayerNames[count].layer_name = malloc(len + 1); 674 if (!pLayerNames[count].layer_name) { 675 free(pOrig); 676 return count; 677 } 678 strncpy((char *) pLayerNames[count].layer_name, name, len); 679 pLayerNames[count].layer_name[len] = '\0'; 680 pLayerNames[count].lib_name = lib_name; 681 count++; 682 p = next; 683 684 }; 685 686 free(pOrig); 687 return count; 688} 689 690static 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) 691{ 692 static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES]; 693 int env_layer_count = 0; 694 695 *ppLayerNames = &layerNames[0]; 696 /* Load any layers specified in the environment first */ 697 env_layer_count = loader_get_layer_env(icd, gpu_index, layerNames); 698 699 const XGL_LAYER_CREATE_INFO *pCi = 700 (const XGL_LAYER_CREATE_INFO *) pCreateInfo->pNext; 701 702 while (pCi) { 703 if (pCi->sType == XGL_STRUCTURE_TYPE_LAYER_CREATE_INFO) { 704 const char *name; 705 uint32_t len, j = 0; 706 for (uint32_t i = env_layer_count; i < (env_layer_count + pCi->layerCount); i++) { 707 const char * lib_name = NULL; 708 name = *(pCi->ppActiveLayerNames + j); 709 if (!find_layer_name(icd, gpu_index, name, &lib_name)) { 710 return i; 711 } 712 len = (uint32_t) strlen(name); 713 layerNames[i].layer_name = malloc(len + 1); 714 if (!layerNames[i].layer_name) 715 return i; 716 strncpy((char *) layerNames[i].layer_name, name, len); 717 layerNames[i].layer_name[len] = '\0'; 718 layerNames[i].lib_name = lib_name; 719 j++; 720 } 721 return pCi->layerCount + env_layer_count; 722 } 723 pCi = pCi->pNext; 724 } 725 return env_layer_count; 726} 727 728static void loader_deactivate_layer(const struct loader_instance *instance) 729{ 730 struct loader_icd *icd; 731 struct loader_layers *libs; 732 733 for (icd = instance->icds; icd; icd = icd->next) { 734 if (icd->gpus) 735 free(icd->gpus); 736 icd->gpus = NULL; 737 if (icd->loader_dispatch) 738 free(icd->loader_dispatch); 739 icd->loader_dispatch = NULL; 740 for (uint32_t j = 0; j < icd->gpu_count; j++) { 741 if (icd->layer_count[j] > 0) { 742 for (uint32_t i = 0; i < icd->layer_count[j]; i++) { 743 libs = &(icd->layer_libs[j][i]); 744 if (libs->lib_handle) 745 loader_platform_close_library(libs->lib_handle); 746 libs->lib_handle = NULL; 747 } 748 if (icd->wrappedGpus[j]) 749 free(icd->wrappedGpus[j]); 750 } 751 icd->layer_count[j] = 0; 752 } 753 icd->gpu_count = 0; 754 } 755} 756 757extern uint32_t loader_activate_layers(XGL_PHYSICAL_GPU gpu, const XGL_DEVICE_CREATE_INFO* pCreateInfo) 758{ 759 uint32_t gpu_index; 760 uint32_t count; 761 struct layer_name_pair *pLayerNames; 762 struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index); 763 764 if (!icd) 765 return 0; 766 assert(gpu_index < XGL_MAX_PHYSICAL_GPUS); 767 768 /* activate any layer libraries */ 769 if (!loader_layers_activated(icd, gpu_index)) { 770 XGL_BASE_LAYER_OBJECT *gpuObj = (XGL_BASE_LAYER_OBJECT *) gpu; 771 XGL_BASE_LAYER_OBJECT *nextGpuObj, *baseObj = gpuObj->baseObject; 772 xglGetProcAddrType nextGPA = xglGetProcAddr; 773 774 count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames); 775 if (!count) 776 return 0; 777 loader_init_layer_libs(icd, gpu_index, pLayerNames, count); 778 779 icd->wrappedGpus[gpu_index] = malloc(sizeof(XGL_BASE_LAYER_OBJECT) * icd->layer_count[gpu_index]); 780 if (! icd->wrappedGpus[gpu_index]) 781 loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer"); 782 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) { 783 nextGpuObj = (icd->wrappedGpus[gpu_index] + i); 784 nextGpuObj->pGPA = nextGPA; 785 nextGpuObj->baseObject = baseObj; 786 nextGpuObj->nextObject = gpuObj; 787 gpuObj = nextGpuObj; 788 789 char funcStr[256]; 790 snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name); 791 if ((nextGPA = (xglGetProcAddrType) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL) 792 nextGPA = (xglGetProcAddrType) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, "xglGetProcAddr"); 793 if (!nextGPA) { 794 loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to find xglGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name); 795 continue; 796 } 797 798 if (i == 0) { 799 loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj); 800 //Insert the new wrapped objects into the list with loader object at head 801 ((XGL_BASE_LAYER_OBJECT *) gpu)->nextObject = gpuObj; 802 ((XGL_BASE_LAYER_OBJECT *) gpu)->pGPA = nextGPA; 803 gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1; 804 gpuObj->nextObject = baseObj; 805 gpuObj->pGPA = icd->scanned_icds->GetProcAddr; 806 } 807 808 } 809 } 810 else { 811 //make sure requested Layers matches currently activated Layers 812 count = loader_get_layer_libs(icd, gpu_index, pCreateInfo, &pLayerNames); 813 for (uint32_t i = 0; i < count; i++) { 814 if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) { 815 loader_log(XGL_DBG_MSG_ERROR, 0, "Layers activated != Layers requested"); 816 break; 817 } 818 } 819 if (count != icd->layer_count[gpu_index]) { 820 loader_log(XGL_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested"); 821 } 822 } 823 return icd->layer_count[gpu_index]; 824} 825 826LOADER_EXPORT XGL_RESULT XGLAPI xglCreateInstance( 827 const XGL_APPLICATION_INFO* pAppInfo, 828 const XGL_ALLOC_CALLBACKS* pAllocCb, 829 XGL_INSTANCE* pInstance) 830{ 831 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd); 832 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer); 833 struct loader_instance *ptr_instance = NULL; 834 struct loader_scanned_icds *scanned_icds; 835 struct loader_icd *icd; 836 XGL_RESULT res = XGL_ERROR_INITIALIZATION_FAILED; 837 838 /* Scan/discover all ICD libraries in a single-threaded manner */ 839 loader_platform_thread_once(&once_icd, loader_icd_scan); 840 841 /* get layer libraries in a single-threaded manner */ 842 loader_platform_thread_once(&once_layer, layer_lib_scan); 843 844 ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance)); 845 if (ptr_instance == NULL) { 846 return XGL_ERROR_OUT_OF_MEMORY; 847 } 848 memset(ptr_instance, 0, sizeof(struct loader_instance)); 849 850 ptr_instance->next = loader.instances; 851 loader.instances = ptr_instance; 852 853 scanned_icds = loader.scanned_icd_list; 854 while (scanned_icds) { 855 icd = loader_icd_add(ptr_instance, scanned_icds); 856 if (icd) { 857 res = scanned_icds->CreateInstance(pAppInfo, pAllocCb, 858 &(scanned_icds->instance)); 859 if (res != XGL_SUCCESS) 860 { 861 ptr_instance->icds = ptr_instance->icds->next; 862 loader_icd_destroy(icd); 863 scanned_icds->instance = NULL; 864 loader_log(XGL_DBG_MSG_WARNING, 0, 865 "ICD ignored: failed to CreateInstance on device"); 866 } 867 } 868 scanned_icds = scanned_icds->next; 869 } 870 871 if (ptr_instance->icds == NULL) { 872 return XGL_ERROR_INCOMPATIBLE_DRIVER; 873 } 874 875 *pInstance = (XGL_INSTANCE) ptr_instance; 876 return XGL_SUCCESS; 877} 878 879LOADER_EXPORT XGL_RESULT XGLAPI xglDestroyInstance( 880 XGL_INSTANCE instance) 881{ 882 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 883 struct loader_scanned_icds *scanned_icds; 884 XGL_RESULT res; 885 886 // Remove this instance from the list of instances: 887 struct loader_instance *prev = NULL; 888 struct loader_instance *next = loader.instances; 889 while (next != NULL) { 890 if (next == ptr_instance) { 891 // Remove this instance from the list: 892 if (prev) 893 prev->next = next->next; 894 else 895 loader.instances = next->next; 896 break; 897 } 898 prev = next; 899 next = next->next; 900 } 901 if (next == NULL) { 902 // This must be an invalid instance handle or empty list 903 return XGL_ERROR_INVALID_HANDLE; 904 } 905 906 // cleanup any prior layer initializations 907 loader_deactivate_layer(ptr_instance); 908 909 scanned_icds = loader.scanned_icd_list; 910 while (scanned_icds) { 911 if (scanned_icds->instance) 912 res = scanned_icds->DestroyInstance(scanned_icds->instance); 913 if (res != XGL_SUCCESS) 914 loader_log(XGL_DBG_MSG_WARNING, 0, 915 "ICD ignored: failed to DestroyInstance on device"); 916 scanned_icds->instance = NULL; 917 scanned_icds = scanned_icds->next; 918 } 919 920 free(ptr_instance); 921 922 return XGL_SUCCESS; 923} 924 925LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateGpus( 926 927 XGL_INSTANCE instance, 928 uint32_t maxGpus, 929 uint32_t* pGpuCount, 930 XGL_PHYSICAL_GPU* pGpus) 931{ 932 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 933 struct loader_icd *icd; 934 uint32_t count = 0; 935 XGL_RESULT res; 936 937 //in spirit of XGL don't error check on the instance parameter 938 icd = ptr_instance->icds; 939 while (icd) { 940 XGL_PHYSICAL_GPU gpus[XGL_MAX_PHYSICAL_GPUS]; 941 XGL_BASE_LAYER_OBJECT * wrapped_gpus; 942 xglGetProcAddrType get_proc_addr = icd->scanned_icds->GetProcAddr; 943 uint32_t n, max = maxGpus - count; 944 945 if (max > XGL_MAX_PHYSICAL_GPUS) { 946 max = XGL_MAX_PHYSICAL_GPUS; 947 } 948 949 res = icd->scanned_icds->EnumerateGpus(icd->scanned_icds->instance, 950 max, &n, 951 gpus); 952 if (res == XGL_SUCCESS && n) { 953 wrapped_gpus = (XGL_BASE_LAYER_OBJECT*) malloc(n * 954 sizeof(XGL_BASE_LAYER_OBJECT)); 955 icd->gpus = wrapped_gpus; 956 icd->gpu_count = n; 957 icd->loader_dispatch = (XGL_LAYER_DISPATCH_TABLE *) malloc(n * 958 sizeof(XGL_LAYER_DISPATCH_TABLE)); 959 for (unsigned int i = 0; i < n; i++) { 960 (wrapped_gpus + i)->baseObject = gpus[i]; 961 (wrapped_gpus + i)->pGPA = get_proc_addr; 962 (wrapped_gpus + i)->nextObject = gpus[i]; 963 memcpy(pGpus + count, &wrapped_gpus, sizeof(*pGpus)); 964 loader_init_dispatch_table(icd->loader_dispatch + i, 965 get_proc_addr, gpus[i]); 966 967 /* Verify ICD compatibility */ 968 if (!valid_loader_magic_value(gpus[i])) { 969 loader_log(XGL_DBG_MSG_WARNING, 0, 970 "Loader: Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\n"); 971 assert(0); 972 } 973 974 const XGL_LAYER_DISPATCH_TABLE **disp; 975 disp = (const XGL_LAYER_DISPATCH_TABLE **) gpus[i]; 976 *disp = icd->loader_dispatch + i; 977 } 978 979 count += n; 980 981 if (count >= maxGpus) { 982 break; 983 } 984 } 985 986 icd = icd->next; 987 } 988 989 *pGpuCount = count; 990 991 return (count > 0) ? XGL_SUCCESS : res; 992} 993 994LOADER_EXPORT void * XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const char * pName) 995{ 996 if (gpu == NULL) { 997 return NULL; 998 } 999 XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) gpu; 1000 XGL_LAYER_DISPATCH_TABLE * disp_table = * (XGL_LAYER_DISPATCH_TABLE **) gpuw->baseObject; 1001 void *addr; 1002 1003 if (disp_table == NULL) 1004 return NULL; 1005 1006 addr = loader_lookup_dispatch_table(disp_table, pName); 1007 if (addr) 1008 return addr; 1009 else { 1010 if (disp_table->GetProcAddr == NULL) 1011 return NULL; 1012 return disp_table->GetProcAddr(gpuw->nextObject, pName); 1013 } 1014} 1015 1016LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved) 1017{ 1018 uint32_t gpu_index; 1019 size_t count = 0; 1020 char *lib_name; 1021 struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index); 1022 loader_platform_dl_handle handle; 1023 xglEnumerateLayersType fpEnumerateLayers; 1024 char layer_buf[16][256]; 1025 char * layers[16]; 1026 1027 if (pOutLayerCount == NULL || pOutLayers == NULL) 1028 return XGL_ERROR_INVALID_POINTER; 1029 1030 if (!icd) 1031 return XGL_ERROR_UNAVAILABLE; 1032 1033 for (int i = 0; i < 16; i++) 1034 layers[i] = &layer_buf[i][0]; 1035 1036 for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) { 1037 lib_name = loader.scanned_layer_names[j]; 1038 // Used to call: dlopen(*lib_name, RTLD_LAZY) 1039 if ((handle = loader_platform_open_library(lib_name)) == NULL) 1040 continue; 1041 if ((fpEnumerateLayers = loader_platform_get_proc_address(handle, "xglEnumerateLayers")) == NULL) { 1042 //use default layer name based on library name XGL_LAYER_LIBRARY_PREFIX<name>.XGL_LIBRARY_SUFFIX 1043 char *pEnd, *cpyStr; 1044 size_t siz; 1045 loader_platform_close_library(handle); 1046 lib_name = basename(lib_name); 1047 pEnd = strrchr(lib_name, '.'); 1048 siz = (int) (pEnd - lib_name - strlen(XGL_LAYER_LIBRARY_PREFIX) + 1); 1049 if (pEnd == NULL || siz <= 0) 1050 continue; 1051 cpyStr = malloc(siz); 1052 if (cpyStr == NULL) { 1053 free(cpyStr); 1054 continue; 1055 } 1056 strncpy(cpyStr, lib_name + strlen(XGL_LAYER_LIBRARY_PREFIX), siz); 1057 cpyStr[siz - 1] = '\0'; 1058 if (siz > maxStringSize) 1059 siz = (int) maxStringSize; 1060 strncpy((char *) (pOutLayers[count]), cpyStr, siz); 1061 pOutLayers[count][siz - 1] = '\0'; 1062 count++; 1063 free(cpyStr); 1064 } 1065 else { 1066 size_t cnt; 1067 uint32_t n; 1068 XGL_RESULT res; 1069 n = (uint32_t) ((maxStringSize < 256) ? maxStringSize : 256); 1070 res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (char *) icd->gpus + gpu_index); 1071 loader_platform_close_library(handle); 1072 if (res != XGL_SUCCESS) 1073 continue; 1074 if (cnt + count > maxLayerCount) 1075 cnt = maxLayerCount - count; 1076 for (uint32_t i = (uint32_t) count; i < cnt + count; i++) { 1077 strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n); 1078 if (n > 0) 1079 pOutLayers[i - count][n - 1] = '\0'; 1080 } 1081 count += cnt; 1082 } 1083 } 1084 1085 *pOutLayerCount = count; 1086 1087 return XGL_SUCCESS; 1088} 1089 1090LOADER_EXPORT XGL_RESULT XGLAPI xglDbgRegisterMsgCallback(XGL_INSTANCE instance, XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData) 1091{ 1092 const struct loader_icd *icd; 1093 struct loader_instance *inst; 1094 XGL_RESULT res; 1095 uint32_t gpu_idx; 1096 1097 if (instance == XGL_NULL_HANDLE) 1098 return XGL_ERROR_INVALID_HANDLE; 1099 1100 assert(loader.icds_scanned); 1101 1102 for (inst = loader.instances; inst; inst = inst->next) { 1103 if (inst == instance) 1104 break; 1105 } 1106 1107 if (inst == XGL_NULL_HANDLE) 1108 return XGL_ERROR_INVALID_HANDLE; 1109 1110 for (icd = inst->icds; icd; icd = icd->next) { 1111 for (uint32_t i = 0; i < icd->gpu_count; i++) { 1112 res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(icd->scanned_icds->instance, 1113 pfnMsgCallback, pUserData); 1114 if (res != XGL_SUCCESS) { 1115 gpu_idx = i; 1116 break; 1117 } 1118 } 1119 if (res != XGL_SUCCESS) 1120 break; 1121 } 1122 1123 1124 /* roll back on errors */ 1125 if (icd) { 1126 for (const struct loader_icd *tmp = inst->icds; tmp != icd; 1127 tmp = tmp->next) { 1128 for (uint32_t i = 0; i < icd->gpu_count; i++) 1129 (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(tmp->scanned_icds->instance, pfnMsgCallback); 1130 } 1131 /* and gpus on current icd */ 1132 for (uint32_t i = 0; i < gpu_idx; i++) 1133 (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback); 1134 1135 return res; 1136 } 1137 1138 return XGL_SUCCESS; 1139} 1140 1141LOADER_EXPORT XGL_RESULT XGLAPI xglDbgUnregisterMsgCallback(XGL_INSTANCE instance, XGL_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback) 1142{ 1143 XGL_RESULT res = XGL_SUCCESS; 1144 struct loader_instance *inst; 1145 if (instance == XGL_NULL_HANDLE) 1146 return XGL_ERROR_INVALID_HANDLE; 1147 1148 assert(loader.icds_scanned); 1149 1150 for (inst = loader.instances; inst; inst = inst->next) { 1151 if (inst == instance) 1152 break; 1153 } 1154 1155 if (inst == XGL_NULL_HANDLE) 1156 return XGL_ERROR_INVALID_HANDLE; 1157 1158 for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) { 1159 for (uint32_t i = 0; i < icd->gpu_count; i++) { 1160 XGL_RESULT r; 1161 r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback); 1162 if (r != XGL_SUCCESS) { 1163 res = r; 1164 } 1165 } 1166 } 1167 return res; 1168} 1169 1170LOADER_EXPORT XGL_RESULT XGLAPI xglDbgSetGlobalOption(XGL_INSTANCE instance, XGL_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData) 1171{ 1172 XGL_RESULT res = XGL_SUCCESS; 1173 struct loader_instance *inst; 1174 if (instance == XGL_NULL_HANDLE) 1175 return XGL_ERROR_INVALID_HANDLE; 1176 1177 assert(loader.icds_scanned); 1178 1179 for (inst = loader.instances; inst; inst = inst->next) { 1180 if (inst == instance) 1181 break; 1182 } 1183 1184 if (inst == XGL_NULL_HANDLE) 1185 return XGL_ERROR_INVALID_HANDLE; 1186 for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) { 1187 for (uint32_t i = 0; i < icd->gpu_count; i++) { 1188 XGL_RESULT r; 1189 r = (icd->loader_dispatch + i)->DbgSetGlobalOption(icd->scanned_icds->instance, dbgOption, 1190 dataSize, pData); 1191 /* unfortunately we cannot roll back */ 1192 if (r != XGL_SUCCESS) { 1193 res = r; 1194 } 1195 } 1196 } 1197 1198 return res; 1199} 1200