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