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