loader.c revision eb2728bbe6efe03eae35e0452e35b04b38e75559
1/* 2 * Vulkan 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 "vkIcd.h" 47// The following is #included again to catch certain OS-specific functions 48// being used: 49#include "loader_platform.h" 50 51struct loader_layers { 52 loader_platform_dl_handle lib_handle; 53 char name[256]; 54}; 55 56struct layer_name_pair { 57 char *layer_name; 58 const char *lib_name; 59}; 60 61struct extension_property { 62 char extName[VK_MAX_EXTENSION_NAME]; 63 uint32_t version; 64 bool hosted; // does the extension reside in one driver/layer 65}; 66 67struct loader_icd { 68 const struct loader_scanned_icds *scanned_icds; 69 70 VkLayerDispatchTable *loader_dispatch; 71 uint32_t layer_count[VK_MAX_PHYSICAL_GPUS]; 72 struct loader_layers layer_libs[VK_MAX_PHYSICAL_GPUS][MAX_LAYER_LIBRARIES]; 73 VkBaseLayerObject *wrappedGpus[VK_MAX_PHYSICAL_GPUS]; 74 uint32_t gpu_count; 75 VkBaseLayerObject *gpus; 76 77 struct loader_icd *next; 78}; 79 80 81struct loader_scanned_icds { 82 loader_platform_dl_handle handle; 83 84 PFN_vkGetProcAddr GetProcAddr; 85 PFN_vkCreateInstance CreateInstance; 86 PFN_vkDestroyInstance DestroyInstance; 87 PFN_vkEnumerateGpus EnumerateGpus; 88 PFN_vkGetGlobalExtensionInfo GetGlobalExtensionInfo; 89 VkInstance instance; 90 struct loader_scanned_icds *next; 91 uint32_t extension_count; 92 struct extension_property *extensions; 93}; 94 95struct loader_scanned_layers { 96 char *name; 97 uint32_t extension_count; 98 struct extension_property *extensions; 99}; 100// Note: Since the following is a static structure, all members are initialized 101// to zero. 102static struct { 103 struct loader_instance *instances; 104 bool icds_scanned; 105 struct loader_scanned_icds *scanned_icd_list; 106 bool layer_scanned; 107 char *layer_dirs; 108 unsigned int scanned_layer_count; 109 struct loader_scanned_layers scanned_layers[MAX_LAYER_LIBRARIES]; 110 size_t scanned_ext_list_capacity; 111 uint32_t scanned_ext_list_count; // coalesced from all layers/drivers 112 struct extension_property **scanned_ext_list; 113} loader; 114 115static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd); 116static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer); 117static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts); 118 119#if defined(WIN32) 120char *loader_get_registry_string(const HKEY hive, 121 const LPCTSTR sub_key, 122 const char *value) 123{ 124 DWORD access_flags = KEY_QUERY_VALUE; 125 DWORD value_type; 126 HKEY key; 127 LONG rtn_value; 128 char *rtn_str = NULL; 129 size_t rtn_len = 0; 130 size_t allocated_len = 0; 131 132 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key); 133 if (rtn_value != ERROR_SUCCESS) { 134 // We didn't find the key. Try the 32-bit hive (where we've seen the 135 // key end up on some people's systems): 136 access_flags |= KEY_WOW64_32KEY; 137 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key); 138 if (rtn_value != ERROR_SUCCESS) { 139 // We still couldn't find the key, so give up: 140 return NULL; 141 } 142 } 143 144 rtn_value = RegQueryValueEx(key, value, NULL, &value_type, 145 (PVOID) rtn_str, &rtn_len); 146 if (rtn_value == ERROR_SUCCESS) { 147 // If we get to here, we found the key, and need to allocate memory 148 // large enough for rtn_str, and query again: 149 allocated_len = rtn_len + 4; 150 rtn_str = malloc(allocated_len); 151 rtn_value = RegQueryValueEx(key, value, NULL, &value_type, 152 (PVOID) rtn_str, &rtn_len); 153 if (rtn_value == ERROR_SUCCESS) { 154 // We added 4 extra bytes to rtn_str, so that we can ensure that 155 // the string is NULL-terminated (albeit, in a brute-force manner): 156 rtn_str[allocated_len-1] = '\0'; 157 } else { 158 // This should never occur, but in case it does, clean up: 159 free(rtn_str); 160 rtn_str = NULL; 161 } 162 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL 163 164 // Close the registry key that was opened: 165 RegCloseKey(key); 166 167 return rtn_str; 168} 169 170 171// For ICD developers, look in the registry, and look for an environment 172// variable for a path(s) where to find the ICD(s): 173static char *loader_get_registry_and_env(const char *env_var, 174 const char *registry_value) 175{ 176 char *env_str = getenv(env_var); 177 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str); 178 char *registry_str = NULL; 179 DWORD registry_len = 0; 180 char *rtn_str = NULL; 181 size_t rtn_len; 182 183 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE, 184 "Software\\Vulkan", 185 registry_value); 186 registry_len = (registry_str) ? strlen(registry_str) : 0; 187 188 rtn_len = env_len + registry_len + 1; 189 if (rtn_len <= 2) { 190 // We found neither the desired registry value, nor the environment 191 // variable; return NULL: 192 return NULL; 193 } else { 194 // We found something, and so we need to allocate memory for the string 195 // to return: 196 rtn_str = malloc(rtn_len); 197 } 198 199 if (registry_len == 0) { 200 // We didn't find the desired registry value, and so we must have found 201 // only the environment variable: 202 _snprintf(rtn_str, rtn_len, "%s", env_str); 203 } else if (env_str != NULL) { 204 // We found both the desired registry value and the environment 205 // variable, so concatenate them both: 206 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str); 207 } else { 208 // We must have only found the desired registry value: 209 _snprintf(rtn_str, rtn_len, "%s", registry_str); 210 } 211 212 if (registry_str) { 213 free(registry_str); 214 } 215 216 return(rtn_str); 217} 218#endif // WIN32 219 220 221static void loader_log(VK_DBG_MSG_TYPE msg_type, int32_t msg_code, 222 const char *format, ...) 223{ 224 char msg[256]; 225 va_list ap; 226 int ret; 227 228 va_start(ap, format); 229 ret = vsnprintf(msg, sizeof(msg), format, ap); 230 if ((ret >= (int) sizeof(msg)) || ret < 0) { 231 msg[sizeof(msg) - 1] = '\0'; 232 } 233 va_end(ap); 234 235 fputs(msg, stderr); 236 fputc('\n', stderr); 237} 238 239static bool has_extension(struct extension_property *exts, uint32_t count, 240 const char *name, bool must_be_hosted) 241{ 242 uint32_t i; 243 for (i = 0; i < count; i++) { 244 if (!strcmp(name, exts[i].extName) && (!must_be_hosted || exts[i].hosted)) 245 return true; 246 } 247 return false; 248} 249 250static void get_global_extensions(PFN_vkGetGlobalExtensionInfo fp_get, 251 uint32_t *count_out, 252 struct extension_property **props_out) 253{ 254 uint32_t i, count, cur; 255 size_t siz = sizeof(count); 256 struct extension_property *ext_props; 257 VkExtensionProperties vk_prop; 258 VkResult res; 259 260 *count_out = 0; 261 *props_out = NULL; 262 res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count); 263 if (res != VK_SUCCESS) { 264 loader_log(VK_DBG_MSG_WARNING, 0, "Error getting global extension count from ICD"); 265 return; 266 } 267 ext_props = (struct extension_property *) malloc(sizeof(struct extension_property) * count); 268 if (ext_props == NULL) { 269 loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory didn't get global extensions from ICD"); 270 return; 271 } 272 siz = sizeof(VkExtensionProperties); 273 cur = 0; 274 for (i = 0; i < count; i++) { 275 res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &vk_prop); 276 if (res == VK_SUCCESS) { 277 (ext_props + cur)->hosted = false; 278 (ext_props + cur)->version = vk_prop.version; 279 strncpy((ext_props + cur)->extName, vk_prop.extName, VK_MAX_EXTENSION_NAME); 280 (ext_props + cur)->extName[VK_MAX_EXTENSION_NAME - 1] = '\0'; 281 cur++; 282 } 283 *count_out = cur; 284 *props_out = ext_props; 285 } 286 return; 287} 288 289static void loader_init_ext_list() 290{ 291 loader.scanned_ext_list_capacity = 256 * sizeof(struct extension_property *); 292 loader.scanned_ext_list = malloc(loader.scanned_ext_list_capacity); 293 memset(loader.scanned_ext_list, 0, loader.scanned_ext_list_capacity); 294 loader.scanned_ext_list_count = 0; 295} 296 297#if 0 // currently no place to call this 298static void loader_destroy_ext_list() 299{ 300 free(loader.scanned_ext_list); 301 loader.scanned_ext_list_capacity = 0; 302 loader.scanned_ext_list_count = 0; 303} 304#endif 305 306static void loader_add_to_ext_list(uint32_t count, 307 struct extension_property *prop_list) 308{ 309 uint32_t i, j; 310 bool duplicate; 311 struct extension_property *cur_ext; 312 313 if (loader.scanned_ext_list == NULL || loader.scanned_ext_list_capacity == 0) 314 loader_init_ext_list(); 315 316 if (loader.scanned_ext_list == NULL) 317 return; 318 319 struct extension_property *ext_list, **ext_list_addr; 320 321 for (i = 0; i < count; i++) { 322 cur_ext = prop_list + i; 323 324 // look for duplicates or not 325 duplicate = false; 326 for (j = 0; j < loader.scanned_ext_list_count; j++) { 327 ext_list = loader.scanned_ext_list[j]; 328 if (!strcmp(cur_ext->extName, ext_list->extName)) { 329 duplicate = true; 330 ext_list->hosted = false; 331 break; 332 } 333 } 334 335 // add to list at end 336 if (!duplicate) { 337 // check for enough capacity 338 if (loader.scanned_ext_list_count * sizeof(struct extension_property *) 339 >= loader.scanned_ext_list_capacity) { 340 // double capacity 341 loader.scanned_ext_list_capacity *= 2; 342 loader.scanned_ext_list = realloc(loader.scanned_ext_list, 343 loader.scanned_ext_list_capacity); 344 } 345 ext_list_addr = &(loader.scanned_ext_list[loader.scanned_ext_list_count++]); 346 *ext_list_addr = cur_ext; 347 cur_ext->hosted = true; 348 } 349 350 } 351} 352 353static void loader_coalesce_extensions() 354{ 355 uint32_t i; 356 struct loader_scanned_icds *icd_list = loader.scanned_icd_list; 357 358 // traverse scanned icd list adding non-duplicate extensions to the list 359 while (icd_list != NULL) { 360 loader_add_to_ext_list(icd_list->extension_count, icd_list->extensions); 361 icd_list = icd_list->next; 362 }; 363 364 //Traverse layers list adding non-duplicate extensions to the list 365 for (i = 0; i < loader.scanned_layer_count; i++) { 366 loader_add_to_ext_list(loader.scanned_layers[i].extension_count, 367 loader.scanned_layers[i].extensions); 368 } 369} 370 371static void loader_icd_destroy(struct loader_icd *icd) 372{ 373 loader_platform_close_library(icd->scanned_icds->handle); 374 free(icd); 375} 376 377static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned) 378{ 379 struct loader_icd *icd; 380 381 icd = malloc(sizeof(*icd)); 382 if (!icd) 383 return NULL; 384 385 memset(icd, 0, sizeof(*icd)); 386 387 icd->scanned_icds = scanned; 388 389 return icd; 390} 391 392static struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst, 393 const struct loader_scanned_icds *scanned) 394{ 395 struct loader_icd *icd; 396 397 icd = loader_icd_create(scanned); 398 if (!icd) 399 return NULL; 400 401 /* prepend to the list */ 402 icd->next = ptr_inst->icds; 403 ptr_inst->icds = icd; 404 405 return icd; 406} 407 408static void loader_scanned_icd_add(const char *filename) 409{ 410 loader_platform_dl_handle handle; 411 void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst; 412 void *fp_get_global_ext_info; 413 struct loader_scanned_icds *new_node; 414 415 // Used to call: dlopen(filename, RTLD_LAZY); 416 handle = loader_platform_open_library(filename); 417 if (!handle) { 418 loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_open_library_error(filename)); 419 return; 420 } 421 422#define LOOKUP(func_ptr, func) do { \ 423 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \ 424 if (!func_ptr) { \ 425 loader_log(VK_DBG_MSG_WARNING, 0, loader_platform_get_proc_address_error("vk" #func)); \ 426 return; \ 427 } \ 428} while (0) 429 430 LOOKUP(fp_gpa, GetProcAddr); 431 LOOKUP(fp_create_inst, CreateInstance); 432 LOOKUP(fp_destroy_inst, DestroyInstance); 433 LOOKUP(fp_enumerate, EnumerateGpus); 434 LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo); 435#undef LOOKUP 436 437 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)); 438 if (!new_node) { 439 loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory can't add icd"); 440 return; 441 } 442 443 new_node->handle = handle; 444 new_node->GetProcAddr = fp_gpa; 445 new_node->CreateInstance = fp_create_inst; 446 new_node->DestroyInstance = fp_destroy_inst; 447 new_node->EnumerateGpus = fp_enumerate; 448 new_node->GetGlobalExtensionInfo = fp_get_global_ext_info; 449 new_node->extension_count = 0; 450 new_node->extensions = NULL; 451 new_node->next = loader.scanned_icd_list; 452 453 loader.scanned_icd_list = new_node; 454 455 if (fp_get_global_ext_info) { 456 get_global_extensions((PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info, 457 &new_node->extension_count, 458 &new_node->extensions); 459 } else { 460 loader_log(VK_DBG_MSG_WARNING, 0, "Couldn't get global extensions from ICD"); 461 } 462} 463 464/** 465 * Try to \c loader_icd_scan VK driver(s). 466 * 467 * This function scans the default system path or path 468 * specified by the \c LIBVK_DRIVERS_PATH environment variable in 469 * order to find loadable VK ICDs with the name of libVK_*. 470 * 471 * \returns 472 * void; but side effect is to set loader_icd_scanned to true 473 */ 474static void loader_icd_scan(void) 475{ 476 const char *p, *next; 477 char *libPaths = NULL; 478 DIR *sysdir; 479 struct dirent *dent; 480 char icd_library[1024]; 481 char path[1024]; 482 uint32_t len; 483#if defined(WIN32) 484 bool must_free_libPaths; 485 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV, 486 DRIVER_PATH_REGISTRY_VALUE); 487 if (libPaths != NULL) { 488 must_free_libPaths = true; 489 } else { 490 must_free_libPaths = false; 491 libPaths = DEFAULT_VK_DRIVERS_PATH; 492 } 493#else // WIN32 494 if (geteuid() == getuid()) { 495 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */ 496 libPaths = getenv(DRIVER_PATH_ENV); 497 } 498 if (libPaths == NULL) { 499 libPaths = DEFAULT_VK_DRIVERS_PATH; 500 } 501#endif // WIN32 502 503 for (p = libPaths; *p; p = next) { 504 next = strchr(p, PATH_SEPERATOR); 505 if (next == NULL) { 506 len = (uint32_t) strlen(p); 507 next = p + len; 508 } 509 else { 510 len = (uint32_t) (next - p); 511 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p); 512 p = path; 513 next++; 514 } 515 516 // TODO/TBD: Do we want to do this on Windows, or just let Windows take 517 // care of its own search path (which it apparently has)? 518 sysdir = opendir(p); 519 if (sysdir) { 520 dent = readdir(sysdir); 521 while (dent) { 522 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and 523 * ending with VK_LIBRARY_SUFFIX 524 */ 525 if (!strncmp(dent->d_name, 526 VK_DRIVER_LIBRARY_PREFIX, 527 VK_DRIVER_LIBRARY_PREFIX_LEN)) { 528 uint32_t nlen = (uint32_t) strlen(dent->d_name); 529 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN; 530 if ((nlen > VK_LIBRARY_SUFFIX_LEN) && 531 !strncmp(suf, 532 VK_LIBRARY_SUFFIX, 533 VK_LIBRARY_SUFFIX_LEN)) { 534 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name); 535 loader_scanned_icd_add(icd_library); 536 } 537 } 538 539 dent = readdir(sysdir); 540 } 541 closedir(sysdir); 542 } 543 } 544 545#if defined(WIN32) 546 // Free any allocated memory: 547 if (must_free_libPaths) { 548 free(libPaths); 549 } 550#endif // WIN32 551 552 // Note that we've scanned for ICDs: 553 loader.icds_scanned = true; 554} 555 556 557static void layer_lib_scan(void) 558{ 559 const char *p, *next; 560 char *libPaths = NULL; 561 DIR *curdir; 562 struct dirent *dent; 563 size_t len, i; 564 char temp_str[1024]; 565 uint32_t count; 566 PFN_vkGetGlobalExtensionInfo fp_get_ext; 567 568#if defined(WIN32) 569 bool must_free_libPaths; 570 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV, 571 LAYERS_PATH_REGISTRY_VALUE); 572 if (libPaths != NULL) { 573 must_free_libPaths = true; 574 } else { 575 must_free_libPaths = false; 576 libPaths = DEFAULT_VK_LAYERS_PATH; 577 } 578#else // WIN32 579 if (geteuid() == getuid()) { 580 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */ 581 libPaths = getenv(LAYERS_PATH_ENV); 582 } 583 if (libPaths == NULL) { 584 libPaths = DEFAULT_VK_LAYERS_PATH; 585 } 586#endif // WIN32 587 588 if (libPaths == NULL) { 589 // Have no paths to search: 590 return; 591 } 592 len = strlen(libPaths); 593 loader.layer_dirs = malloc(len+1); 594 if (loader.layer_dirs == NULL) { 595 free(libPaths); 596 return; 597 } 598 // Alloc passed, so we know there is enough space to hold the string, don't 599 // need strncpy 600 strcpy(loader.layer_dirs, libPaths); 601#if defined(WIN32) 602 // Free any allocated memory: 603 if (must_free_libPaths) { 604 free(libPaths); 605 must_free_libPaths = false; 606 } 607#endif // WIN32 608 libPaths = loader.layer_dirs; 609 610 /* cleanup any previously scanned libraries */ 611 for (i = 0; i < loader.scanned_layer_count; i++) { 612 if (loader.scanned_layers[i].name != NULL) 613 free(loader.scanned_layers[i].name); 614 if (loader.scanned_layers[i].extensions != NULL) 615 free(loader.scanned_layers[i].extensions); 616 loader.scanned_layers[i].name = NULL; 617 loader.scanned_layers[i].extensions = NULL; 618 } 619 loader.scanned_layer_count = 0; 620 count = 0; 621 622 for (p = libPaths; *p; p = next) { 623 next = strchr(p, PATH_SEPERATOR); 624 if (next == NULL) { 625 len = (uint32_t) strlen(p); 626 next = p + len; 627 } 628 else { 629 len = (uint32_t) (next - p); 630 *(char *) next = '\0'; 631 next++; 632 } 633 634 curdir = opendir(p); 635 if (curdir) { 636 dent = readdir(curdir); 637 while (dent) { 638 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and 639 * ending with VK_LIBRARY_SUFFIX 640 */ 641 if (!strncmp(dent->d_name, 642 VK_LAYER_LIBRARY_PREFIX, 643 VK_LAYER_LIBRARY_PREFIX_LEN)) { 644 uint32_t nlen = (uint32_t) strlen(dent->d_name); 645 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN; 646 if ((nlen > VK_LIBRARY_SUFFIX_LEN) && 647 !strncmp(suf, 648 VK_LIBRARY_SUFFIX, 649 VK_LIBRARY_SUFFIX_LEN)) { 650 loader_platform_dl_handle handle; 651 snprintf(temp_str, sizeof(temp_str), 652 "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name); 653 // Used to call: dlopen(temp_str, RTLD_LAZY) 654 if ((handle = loader_platform_open_library(temp_str)) == NULL) { 655 dent = readdir(curdir); 656 continue; 657 } 658 if (count == MAX_LAYER_LIBRARIES) { 659 loader_log(VK_DBG_MSG_ERROR, 0, 660 "%s ignored: max layer libraries exceed", 661 temp_str); 662 break; 663 } 664 fp_get_ext = loader_platform_get_proc_address(handle, 665 "vkGetGlobalExtensionInfo"); 666 667 if (!fp_get_ext) { 668 loader_log(VK_DBG_MSG_WARNING, 0, 669 "Couldn't dlsym vkGetGlobalExtensionInfo from library %s", 670 temp_str); 671 dent = readdir(curdir); 672 loader_platform_close_library(handle); 673 continue; 674 } 675 676 loader.scanned_layers[count].name = 677 malloc(strlen(temp_str) + 1); 678 if (loader.scanned_layers[count].name == NULL) { 679 loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str); 680 break; 681 } 682 683 get_global_extensions(fp_get_ext, 684 &loader.scanned_layers[count].extension_count, 685 &loader.scanned_layers[count].extensions); 686 687 688 strcpy(loader.scanned_layers[count].name, temp_str); 689 count++; 690 loader_platform_close_library(handle); 691 } 692 } 693 694 dent = readdir(curdir); 695 } // while (dir_entry) 696 if (count == MAX_LAYER_LIBRARIES) 697 break; 698 closedir(curdir); 699 } // if (curdir)) 700 } // for (libpaths) 701 702 loader.scanned_layer_count = count; 703 loader.layer_scanned = true; 704} 705 706static void loader_init_dispatch_table(VkLayerDispatchTable *tab, PFN_vkGetProcAddr fpGPA, VkPhysicalGpu gpu) 707{ 708 loader_initialize_dispatch_table(tab, fpGPA, gpu); 709 710 if (tab->EnumerateLayers == NULL) 711 tab->EnumerateLayers = vkEnumerateLayers; 712} 713 714extern struct loader_icd * loader_get_icd(const VkBaseLayerObject *gpu, uint32_t *gpu_index) 715{ 716 /* 717 * NOTE: at this time icd->gpus is pointing to wrapped GPUs, but no where else 718 * are wrapped gpus used. Should go away. The incoming gpu is NOT wrapped so 719 * need to test it against the wrapped GPU's base object. 720 */ 721 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 722 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 723 for (uint32_t i = 0; i < icd->gpu_count; i++) 724 if ((icd->gpus + i) == gpu || (icd->gpus +i)->baseObject == 725 gpu) { 726 *gpu_index = i; 727 return icd; 728 } 729 } 730 } 731 return NULL; 732} 733 734static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index) 735{ 736 if (icd->layer_count[gpu_index]) 737 return true; 738 else 739 return false; 740} 741 742static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair * pLayerNames, uint32_t count) 743{ 744 if (!icd) 745 return; 746 747 struct loader_layers *obj; 748 bool foundLib; 749 for (uint32_t i = 0; i < count; i++) { 750 foundLib = false; 751 for (uint32_t j = 0; j < icd->layer_count[gpu_index]; j++) { 752 if (icd->layer_libs[gpu_index][j].lib_handle && !strcmp(icd->layer_libs[gpu_index][j].name, (char *) pLayerNames[i].layer_name)) { 753 foundLib = true; 754 break; 755 } 756 } 757 if (!foundLib) { 758 obj = &(icd->layer_libs[gpu_index][i]); 759 strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1); 760 obj->name[sizeof(obj->name) - 1] = '\0'; 761 // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND) 762 if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) { 763 loader_log(VK_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name)); 764 continue; 765 } else { 766 loader_log(VK_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name); 767 } 768 free(pLayerNames[i].layer_name); 769 icd->layer_count[gpu_index]++; 770 } 771 } 772} 773 774static bool find_layer_extension(struct loader_icd *icd, uint32_t gpu_index, const char *pExtName, const char **lib_name) 775{ 776 char *search_name; 777 uint32_t j; 778 779 /* 780 * The loader provides the abstraction that make layers and extensions work via 781 * the currently defined extension mechanism. That is, when app queries for an extension 782 * via vkGetGlobalExtensionInfo, the loader will call both the driver as well as any layers 783 * to see who implements that extension. Then, if the app enables the extension during 784 * vkCreateInstance the loader will find and load any layers that implement that extension. 785 */ 786 787 // TODO: what about GetPhysicalDeviceExtension for device specific layers/extensions 788 789 for (j = 0; j < loader.scanned_layer_count; j++) { 790 if (lib_name) { 791 *lib_name = loader.scanned_layers[j].name; 792 } 793 if (has_extension(loader.scanned_layers[j].extensions, 794 loader.scanned_layers[j].extension_count, pExtName, 795 true)) 796 797 return true; 798 799 // Extension not found in list for the layer, so test the layer name 800 // as if it is an extension name. Use default layer name based on 801 // library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX 802 char *pEnd; 803 size_t siz; 804 805 search_name = loader.scanned_layers[j].name; 806 search_name = basename(search_name); 807 search_name += strlen(VK_LAYER_LIBRARY_PREFIX); 808 pEnd = strrchr(search_name, '.'); 809 siz = (int) (pEnd - search_name); 810 if (siz != strlen(pExtName)) 811 continue; 812 813 if (strncmp(search_name, pExtName, siz) == 0) { 814 return true; 815 } 816 } 817 if (lib_name) { 818 *lib_name = NULL; 819 } 820 return false; 821} 822 823static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames) 824{ 825 char *layerEnv; 826 uint32_t len, count = 0; 827 char *p, *pOrig, *next, *name; 828 829#if defined(WIN32) 830 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV, 831 LAYER_NAMES_REGISTRY_VALUE); 832#else // WIN32 833 layerEnv = getenv(LAYER_NAMES_ENV); 834#endif // WIN32 835 if (layerEnv == NULL) { 836 return 0; 837 } 838 p = malloc(strlen(layerEnv) + 1); 839 if (p == NULL) { 840#if defined(WIN32) 841 free(layerEnv); 842#endif // WIN32 843 return 0; 844 } 845 strcpy(p, layerEnv); 846#if defined(WIN32) 847 free(layerEnv); 848#endif // WIN32 849 pOrig = p; 850 851 while (p && *p && count < MAX_LAYER_LIBRARIES) { 852 const char *lib_name = NULL; 853 next = strchr(p, PATH_SEPERATOR); 854 if (next == NULL) { 855 len = (uint32_t) strlen(p); 856 next = p + len; 857 } else { 858 len = (uint32_t) (next - p); 859 *(char *) next = '\0'; 860 next++; 861 } 862 name = basename(p); 863 if (!find_layer_extension(icd, gpu_index, name, &lib_name)) { 864 p = next; 865 continue; 866 } 867 868 len = (uint32_t) strlen(name); 869 pLayerNames[count].layer_name = malloc(len + 1); 870 if (!pLayerNames[count].layer_name) { 871 free(pOrig); 872 return count; 873 } 874 strncpy((char *) pLayerNames[count].layer_name, name, len); 875 pLayerNames[count].layer_name[len] = '\0'; 876 pLayerNames[count].lib_name = lib_name; 877 count++; 878 p = next; 879 880 } 881 882 free(pOrig); 883 return count; 884} 885 886static uint32_t loader_get_layer_libs(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names, struct layer_name_pair **ppLayerNames) 887{ 888 static struct layer_name_pair layerNames[MAX_LAYER_LIBRARIES]; 889 const char *lib_name = NULL; 890 uint32_t count = 0; 891 892 *ppLayerNames = &layerNames[0]; 893 /* Load any layers specified in the environment first */ 894 count = loader_get_layer_env(icd, gpu_index, layerNames); 895 896 for (uint32_t i = 0; i < ext_count; i++) { 897 const char *pExtName = ext_names[i]; 898 899 if (find_layer_extension(icd, gpu_index, pExtName, &lib_name)) { 900 uint32_t len; 901 902 /* 903 * the library name is NULL if the driver supports this 904 * extension and thus no layer to load. 905 */ 906 if (lib_name == NULL) 907 continue; 908 909 len = (uint32_t) strlen(pExtName); 910 for (uint32_t j = 0; j < count; j++) { 911 if (len == strlen(layerNames[j].layer_name) && 912 strncmp(pExtName, layerNames[j].layer_name, len) == 0) { 913 // Extension / Layer already on the list 914 continue; 915 } 916 } 917 918 layerNames[count].layer_name = malloc(len + 1); 919 if (!layerNames[count].layer_name) 920 return count; 921 strncpy((char *) layerNames[count].layer_name, pExtName, len); 922 layerNames[count].layer_name[len] = '\0'; 923 layerNames[count].lib_name = lib_name; 924 count++; 925 } 926 } 927 928 return count; 929} 930 931static void loader_deactivate_layer(const struct loader_instance *instance) 932{ 933 struct loader_icd *icd; 934 struct loader_layers *libs; 935 936 for (icd = instance->icds; icd; icd = icd->next) { 937 if (icd->gpus) 938 free(icd->gpus); 939 icd->gpus = NULL; 940 if (icd->loader_dispatch) 941 free(icd->loader_dispatch); 942 icd->loader_dispatch = NULL; 943 for (uint32_t j = 0; j < icd->gpu_count; j++) { 944 if (icd->layer_count[j] > 0) { 945 for (uint32_t i = 0; i < icd->layer_count[j]; i++) { 946 libs = &(icd->layer_libs[j][i]); 947 if (libs->lib_handle) 948 loader_platform_close_library(libs->lib_handle); 949 libs->lib_handle = NULL; 950 } 951 if (icd->wrappedGpus[j]) 952 free(icd->wrappedGpus[j]); 953 } 954 icd->layer_count[j] = 0; 955 } 956 icd->gpu_count = 0; 957 } 958} 959 960extern uint32_t loader_activate_layers(struct loader_icd *icd, uint32_t gpu_index, uint32_t ext_count, const char *const* ext_names) 961{ 962 uint32_t count; 963 VkBaseLayerObject *gpu; 964 struct layer_name_pair *pLayerNames; 965 if (!icd) 966 return 0; 967 assert(gpu_index < VK_MAX_PHYSICAL_GPUS); 968 969 gpu = icd->gpus + gpu_index; 970 /* activate any layer libraries */ 971 if (!loader_layers_activated(icd, gpu_index)) { 972 VkBaseLayerObject *gpuObj = gpu; 973 VkBaseLayerObject *nextGpuObj, *baseObj = gpuObj->baseObject; 974 PFN_vkGetProcAddr nextGPA = vkGetProcAddr; 975 976 count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames); 977 if (!count) 978 return 0; 979 loader_init_layer_libs(icd, gpu_index, pLayerNames, count); 980 981 icd->wrappedGpus[gpu_index] = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]); 982 if (! icd->wrappedGpus[gpu_index]) 983 loader_log(VK_DBG_MSG_ERROR, 0, "Failed to malloc Gpu objects for layer"); 984 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) { 985 nextGpuObj = (icd->wrappedGpus[gpu_index] + i); 986 nextGpuObj->pGPA = nextGPA; 987 nextGpuObj->baseObject = baseObj; 988 nextGpuObj->nextObject = gpuObj; 989 gpuObj = nextGpuObj; 990 991 char funcStr[256]; 992 snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name); 993 if ((nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL) 994 nextGPA = (PFN_vkGetProcAddr) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, "vkGetProcAddr"); 995 if (!nextGPA) { 996 loader_log(VK_DBG_MSG_ERROR, 0, "Failed to find vkGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name); 997 continue; 998 } 999 1000 if (i == 0) { 1001 loader_init_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, gpuObj); 1002 //Insert the new wrapped objects into the list with loader object at head 1003 gpu->nextObject = gpuObj; 1004 gpu->pGPA = nextGPA; 1005 gpuObj = icd->wrappedGpus[gpu_index] + icd->layer_count[gpu_index] - 1; 1006 gpuObj->nextObject = baseObj; 1007 gpuObj->pGPA = icd->scanned_icds->GetProcAddr; 1008 } 1009 1010 } 1011 } 1012 else { 1013 //make sure requested Layers matches currently activated Layers 1014 count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames); 1015 for (uint32_t i = 0; i < count; i++) { 1016 if (strcmp(icd->layer_libs[gpu_index][i].name, pLayerNames[i].layer_name)) { 1017 loader_log(VK_DBG_MSG_ERROR, 0, "Layers activated != Layers requested"); 1018 break; 1019 } 1020 } 1021 if (count != icd->layer_count[gpu_index]) { 1022 loader_log(VK_DBG_MSG_ERROR, 0, "Number of Layers activated != number requested"); 1023 } 1024 } 1025 return icd->layer_count[gpu_index]; 1026} 1027 1028LOADER_EXPORT VkResult VKAPI vkCreateInstance( 1029 const VkInstanceCreateInfo* pCreateInfo, 1030 VkInstance* pInstance) 1031{ 1032 struct loader_instance *ptr_instance = NULL; 1033 struct loader_scanned_icds *scanned_icds; 1034 struct loader_icd *icd; 1035 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 1036 uint32_t i; 1037 1038 /* Scan/discover all ICD libraries in a single-threaded manner */ 1039 loader_platform_thread_once(&once_icd, loader_icd_scan); 1040 1041 /* get layer libraries in a single-threaded manner */ 1042 loader_platform_thread_once(&once_layer, layer_lib_scan); 1043 1044 /* merge any duplicate extensions */ 1045 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 1046 1047 ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance)); 1048 if (ptr_instance == NULL) { 1049 return VK_ERROR_OUT_OF_MEMORY; 1050 } 1051 memset(ptr_instance, 0, sizeof(struct loader_instance)); 1052 ptr_instance->extension_count = pCreateInfo->extensionCount; 1053 ptr_instance->extension_names = (ptr_instance->extension_count > 0) ? 1054 malloc(sizeof (char *) * ptr_instance->extension_count) : NULL; 1055 for (i = 0; i < ptr_instance->extension_count; i++) { 1056 ptr_instance->extension_names[i] = malloc(strlen(pCreateInfo->ppEnabledExtensionNames[i] + 1)); 1057 if (ptr_instance->extension_names[i] == NULL) 1058 return VK_ERROR_OUT_OF_MEMORY; 1059 strcpy(ptr_instance->extension_names[i], pCreateInfo->ppEnabledExtensionNames[i]); 1060 } 1061 ptr_instance->next = loader.instances; 1062 loader.instances = ptr_instance; 1063 1064 scanned_icds = loader.scanned_icd_list; 1065 while (scanned_icds) { 1066 icd = loader_icd_add(ptr_instance, scanned_icds); 1067 if (icd) { 1068 res = scanned_icds->CreateInstance(pCreateInfo, 1069 &(scanned_icds->instance)); 1070 if (res != VK_SUCCESS) 1071 { 1072 ptr_instance->icds = ptr_instance->icds->next; 1073 loader_icd_destroy(icd); 1074 scanned_icds->instance = NULL; 1075 loader_log(VK_DBG_MSG_WARNING, 0, 1076 "ICD ignored: failed to CreateInstance on device"); 1077 } 1078 } 1079 scanned_icds = scanned_icds->next; 1080 } 1081 1082 if (ptr_instance->icds == NULL) { 1083 return VK_ERROR_INCOMPATIBLE_DRIVER; 1084 } 1085 1086 *pInstance = (VkInstance) ptr_instance; 1087 return VK_SUCCESS; 1088} 1089 1090LOADER_EXPORT VkResult VKAPI vkDestroyInstance( 1091 VkInstance instance) 1092{ 1093 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 1094 struct loader_scanned_icds *scanned_icds; 1095 VkResult res; 1096 uint32_t i; 1097 1098 // Remove this instance from the list of instances: 1099 struct loader_instance *prev = NULL; 1100 struct loader_instance *next = loader.instances; 1101 while (next != NULL) { 1102 if (next == ptr_instance) { 1103 // Remove this instance from the list: 1104 for (i = 0; i < ptr_instance->extension_count; i++) { 1105 free(ptr_instance->extension_names[i]); 1106 } 1107 if (prev) 1108 prev->next = next->next; 1109 else 1110 loader.instances = next->next; 1111 break; 1112 } 1113 prev = next; 1114 next = next->next; 1115 } 1116 if (next == NULL) { 1117 // This must be an invalid instance handle or empty list 1118 return VK_ERROR_INVALID_HANDLE; 1119 } 1120 1121 // cleanup any prior layer initializations 1122 loader_deactivate_layer(ptr_instance); 1123 1124 scanned_icds = loader.scanned_icd_list; 1125 while (scanned_icds) { 1126 if (scanned_icds->instance) 1127 res = scanned_icds->DestroyInstance(scanned_icds->instance); 1128 if (res != VK_SUCCESS) 1129 loader_log(VK_DBG_MSG_WARNING, 0, 1130 "ICD ignored: failed to DestroyInstance on device"); 1131 scanned_icds->instance = NULL; 1132 scanned_icds = scanned_icds->next; 1133 } 1134 1135 free(ptr_instance); 1136 1137 return VK_SUCCESS; 1138} 1139 1140LOADER_EXPORT VkResult VKAPI vkEnumerateGpus( 1141 1142 VkInstance instance, 1143 uint32_t maxGpus, 1144 uint32_t* pGpuCount, 1145 VkPhysicalGpu* pGpus) 1146{ 1147 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 1148 struct loader_icd *icd; 1149 uint32_t count = 0; 1150 VkResult res; 1151 1152 //in spirit of VK don't error check on the instance parameter 1153 icd = ptr_instance->icds; 1154 while (icd) { 1155 VkPhysicalGpu gpus[VK_MAX_PHYSICAL_GPUS]; 1156 VkBaseLayerObject * wrapped_gpus; 1157 PFN_vkGetProcAddr get_proc_addr = icd->scanned_icds->GetProcAddr; 1158 uint32_t n, max = maxGpus - count; 1159 1160 if (max > VK_MAX_PHYSICAL_GPUS) { 1161 max = VK_MAX_PHYSICAL_GPUS; 1162 } 1163 1164 res = icd->scanned_icds->EnumerateGpus(icd->scanned_icds->instance, 1165 max, &n, 1166 gpus); 1167 if (res == VK_SUCCESS && n) { 1168 wrapped_gpus = (VkBaseLayerObject*) malloc(n * 1169 sizeof(VkBaseLayerObject)); 1170 icd->gpus = wrapped_gpus; 1171 icd->gpu_count = n; 1172 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n * 1173 sizeof(VkLayerDispatchTable)); 1174 for (unsigned int i = 0; i < n; i++) { 1175 (wrapped_gpus + i)->baseObject = gpus[i]; 1176 (wrapped_gpus + i)->pGPA = get_proc_addr; 1177 (wrapped_gpus + i)->nextObject = gpus[i]; 1178 memcpy(pGpus + count, gpus, sizeof(*pGpus)); 1179 loader_init_dispatch_table(icd->loader_dispatch + i, 1180 get_proc_addr, gpus[i]); 1181 1182 /* Verify ICD compatibility */ 1183 if (!valid_loader_magic_value(gpus[i])) { 1184 loader_log(VK_DBG_MSG_WARNING, 0, 1185 "Loader: Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\n"); 1186 assert(0); 1187 } 1188 1189 const VkLayerDispatchTable **disp; 1190 disp = (const VkLayerDispatchTable **) gpus[i]; 1191 *disp = icd->loader_dispatch + i; 1192 loader_activate_layers(icd, i, ptr_instance->extension_count, 1193 (const char *const*) ptr_instance->extension_names); 1194 } 1195 1196 count += n; 1197 1198 if (count >= maxGpus) { 1199 break; 1200 } 1201 } 1202 1203 icd = icd->next; 1204 } 1205 1206 *pGpuCount = count; 1207 1208 return (count > 0) ? VK_SUCCESS : res; 1209} 1210 1211LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char * pName) 1212{ 1213 if (gpu == NULL) { 1214 return NULL; 1215 } 1216 VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu; 1217 VkLayerDispatchTable * disp_table = * (VkLayerDispatchTable **) gpuw->baseObject; 1218 void *addr; 1219 1220 if (disp_table == NULL) 1221 return NULL; 1222 1223 addr = loader_lookup_dispatch_table(disp_table, pName); 1224 if (addr) 1225 return addr; 1226 else { 1227 if (disp_table->GetProcAddr == NULL) 1228 return NULL; 1229 return disp_table->GetProcAddr(gpuw->nextObject, pName); 1230 } 1231} 1232 1233//TODO make sure createInstance enables extensions that are valid (loader does) 1234//TODO make sure CreateDevice enables extensions that are valid (left for layers/drivers to do) 1235 1236//TODO how is layer extension going to be enabled? 1237//Need to call createInstance on the layer or something 1238 1239LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo( 1240 VkExtensionInfoType infoType, 1241 uint32_t extensionIndex, 1242 size_t* pDataSize, 1243 void* pData) 1244{ 1245 VkExtensionProperties *ext_props; 1246 uint32_t *count; 1247 /* Scan/discover all ICD libraries in a single-threaded manner */ 1248 loader_platform_thread_once(&once_icd, loader_icd_scan); 1249 1250 /* get layer libraries in a single-threaded manner */ 1251 loader_platform_thread_once(&once_layer, layer_lib_scan); 1252 1253 /* merge any duplicate extensions */ 1254 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 1255 1256 1257 if (pDataSize == NULL) 1258 return VK_ERROR_INVALID_POINTER; 1259 1260 switch (infoType) { 1261 case VK_EXTENSION_INFO_TYPE_COUNT: 1262 *pDataSize = sizeof(uint32_t); 1263 if (pData == NULL) 1264 return VK_SUCCESS; 1265 count = (uint32_t *) pData; 1266 *count = loader.scanned_ext_list_count; 1267 break; 1268 case VK_EXTENSION_INFO_TYPE_PROPERTIES: 1269 *pDataSize = sizeof(VkExtensionProperties); 1270 if (pData == NULL) 1271 return VK_SUCCESS; 1272 if (extensionIndex >= loader.scanned_ext_list_count) 1273 return VK_ERROR_INVALID_VALUE; 1274 ext_props = (VkExtensionProperties *) pData; 1275 ext_props->version = loader.scanned_ext_list[extensionIndex]->version; 1276 strncpy(ext_props->extName, loader.scanned_ext_list[extensionIndex]->extName 1277 , VK_MAX_EXTENSION_NAME); 1278 ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0'; 1279 break; 1280 default: 1281 loader_log(VK_DBG_MSG_WARNING, 0, "Invalid infoType in vkGetGlobalExtensionInfo"); 1282 return VK_ERROR_INVALID_VALUE; 1283 }; 1284 1285 return VK_SUCCESS; 1286} 1287 1288LOADER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved) 1289{ 1290 uint32_t gpu_index; 1291 size_t count = 0; 1292 char *lib_name; 1293 struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index); 1294 loader_platform_dl_handle handle; 1295 PFN_vkEnumerateLayers fpEnumerateLayers; 1296 char layer_buf[16][256]; 1297 char * layers[16]; 1298 1299 if (pOutLayerCount == NULL || pOutLayers == NULL) 1300 return VK_ERROR_INVALID_POINTER; 1301 1302 if (!icd) 1303 return VK_ERROR_UNAVAILABLE; 1304 1305 for (int i = 0; i < 16; i++) 1306 layers[i] = &layer_buf[i][0]; 1307 1308 for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) { 1309 lib_name = loader.scanned_layers[j].name; 1310 // Used to call: dlopen(*lib_name, RTLD_LAZY) 1311 if ((handle = loader_platform_open_library(lib_name)) == NULL) 1312 continue; 1313 if ((fpEnumerateLayers = loader_platform_get_proc_address(handle, "vkEnumerateLayers")) == NULL) { 1314 //use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX 1315 char *pEnd, *cpyStr; 1316 size_t siz; 1317 loader_platform_close_library(handle); 1318 lib_name = basename(lib_name); 1319 pEnd = strrchr(lib_name, '.'); 1320 siz = (int) (pEnd - lib_name - strlen(VK_LAYER_LIBRARY_PREFIX) + 1); 1321 if (pEnd == NULL || siz <= 0) 1322 continue; 1323 cpyStr = malloc(siz); 1324 if (cpyStr == NULL) { 1325 free(cpyStr); 1326 continue; 1327 } 1328 strncpy(cpyStr, lib_name + strlen(VK_LAYER_LIBRARY_PREFIX), siz); 1329 cpyStr[siz - 1] = '\0'; 1330 if (siz > maxStringSize) 1331 siz = (int) maxStringSize; 1332 strncpy((char *) (pOutLayers[count]), cpyStr, siz); 1333 pOutLayers[count][siz - 1] = '\0'; 1334 count++; 1335 free(cpyStr); 1336 } else { 1337 size_t cnt; 1338 uint32_t n; 1339 VkResult res; 1340 n = (uint32_t) ((maxStringSize < 256) ? maxStringSize : 256); 1341 res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (char *) icd->gpus + gpu_index); 1342 loader_platform_close_library(handle); 1343 if (res != VK_SUCCESS) 1344 continue; 1345 if (cnt + count > maxLayerCount) 1346 cnt = maxLayerCount - count; 1347 for (uint32_t i = (uint32_t) count; i < cnt + count; i++) { 1348 strncpy((char *) (pOutLayers[i]), (char *) layers[i - count], n); 1349 if (n > 0) 1350 pOutLayers[i - count][n - 1] = '\0'; 1351 } 1352 count += cnt; 1353 } 1354 } 1355 1356 *pOutLayerCount = count; 1357 1358 return VK_SUCCESS; 1359} 1360 1361LOADER_EXPORT VkResult VKAPI vkDbgRegisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback, void* pUserData) 1362{ 1363 const struct loader_icd *icd; 1364 struct loader_instance *inst; 1365 VkResult res; 1366 uint32_t gpu_idx; 1367 1368 if (instance == VK_NULL_HANDLE) 1369 return VK_ERROR_INVALID_HANDLE; 1370 1371 assert(loader.icds_scanned); 1372 1373 for (inst = loader.instances; inst; inst = inst->next) { 1374 if (inst == instance) 1375 break; 1376 } 1377 1378 if (inst == VK_NULL_HANDLE) 1379 return VK_ERROR_INVALID_HANDLE; 1380 1381 for (icd = inst->icds; icd; icd = icd->next) { 1382 for (uint32_t i = 0; i < icd->gpu_count; i++) { 1383 res = (icd->loader_dispatch + i)->DbgRegisterMsgCallback(icd->scanned_icds->instance, 1384 pfnMsgCallback, pUserData); 1385 if (res != VK_SUCCESS) { 1386 gpu_idx = i; 1387 break; 1388 } 1389 } 1390 if (res != VK_SUCCESS) 1391 break; 1392 } 1393 1394 1395 /* roll back on errors */ 1396 if (icd) { 1397 for (const struct loader_icd *tmp = inst->icds; tmp != icd; 1398 tmp = tmp->next) { 1399 for (uint32_t i = 0; i < icd->gpu_count; i++) 1400 (tmp->loader_dispatch + i)->DbgUnregisterMsgCallback(tmp->scanned_icds->instance, pfnMsgCallback); 1401 } 1402 /* and gpus on current icd */ 1403 for (uint32_t i = 0; i < gpu_idx; i++) 1404 (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback); 1405 1406 return res; 1407 } 1408 1409 return VK_SUCCESS; 1410} 1411 1412LOADER_EXPORT VkResult VKAPI vkDbgUnregisterMsgCallback(VkInstance instance, VK_DBG_MSG_CALLBACK_FUNCTION pfnMsgCallback) 1413{ 1414 VkResult res = VK_SUCCESS; 1415 struct loader_instance *inst; 1416 if (instance == VK_NULL_HANDLE) 1417 return VK_ERROR_INVALID_HANDLE; 1418 1419 assert(loader.icds_scanned); 1420 1421 for (inst = loader.instances; inst; inst = inst->next) { 1422 if (inst == instance) 1423 break; 1424 } 1425 1426 if (inst == VK_NULL_HANDLE) 1427 return VK_ERROR_INVALID_HANDLE; 1428 1429 for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) { 1430 for (uint32_t i = 0; i < icd->gpu_count; i++) { 1431 VkResult r; 1432 r = (icd->loader_dispatch + i)->DbgUnregisterMsgCallback(icd->scanned_icds->instance, pfnMsgCallback); 1433 if (r != VK_SUCCESS) { 1434 res = r; 1435 } 1436 } 1437 } 1438 return res; 1439} 1440 1441LOADER_EXPORT VkResult VKAPI vkDbgSetGlobalOption(VkInstance instance, VK_DBG_GLOBAL_OPTION dbgOption, size_t dataSize, const void* pData) 1442{ 1443 VkResult res = VK_SUCCESS; 1444 struct loader_instance *inst; 1445 if (instance == VK_NULL_HANDLE) 1446 return VK_ERROR_INVALID_HANDLE; 1447 1448 assert(loader.icds_scanned); 1449 1450 for (inst = loader.instances; inst; inst = inst->next) { 1451 if (inst == instance) 1452 break; 1453 } 1454 1455 if (inst == VK_NULL_HANDLE) 1456 return VK_ERROR_INVALID_HANDLE; 1457 for (const struct loader_icd * icd = inst->icds; icd; icd = icd->next) { 1458 for (uint32_t i = 0; i < icd->gpu_count; i++) { 1459 VkResult r; 1460 r = (icd->loader_dispatch + i)->DbgSetGlobalOption(icd->scanned_icds->instance, dbgOption, 1461 dataSize, pData); 1462 /* unfortunately we cannot roll back */ 1463 if (r != VK_SUCCESS) { 1464 res = r; 1465 } 1466 } 1467 } 1468 1469 return res; 1470} 1471