loader.c revision 535bd00968e86ef2c32495566b7b61400c2aad7d
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 "vk_loader_platform.h" 44#include "loader.h" 45#include "wsi_lunarg.h" 46#include "gpa_helper.h" 47#include "table_ops.h" 48#include "debug_report.h" 49#include "vk_icd.h" 50#include "cJSON.h" 51 52void loader_add_to_ext_list( 53 struct loader_extension_list *ext_list, 54 uint32_t prop_list_count, 55 const struct loader_extension_property *prop_list); 56 57static loader_platform_dl_handle loader_add_layer_lib( 58 const char *chain_type, 59 struct loader_extension_property *ext_prop); 60 61static void loader_remove_layer_lib( 62 struct loader_instance *inst, 63 struct loader_extension_property *ext_prop); 64 65struct loader_struct loader = {0}; 66 67static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName); 68 69enum loader_debug { 70 LOADER_INFO_BIT = VK_BIT(0), 71 LOADER_WARN_BIT = VK_BIT(1), 72 LOADER_PERF_BIT = VK_BIT(2), 73 LOADER_ERROR_BIT = VK_BIT(3), 74 LOADER_DEBUG_BIT = VK_BIT(4), 75}; 76 77uint32_t g_loader_debug = 0; 78uint32_t g_loader_log_msgs = 0; 79 80//thread safety lock for accessing global data structures such as "loader" 81// all entrypoints on the instance chain need to be locked except GPA 82// additionally CreateDevice and DestroyDevice needs to be locked 83loader_platform_thread_mutex loader_lock; 84 85const VkLayerInstanceDispatchTable instance_disp = { 86 .GetInstanceProcAddr = loader_GetInstanceProcAddr, 87 .CreateInstance = loader_CreateInstance, 88 .DestroyInstance = loader_DestroyInstance, 89 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices, 90 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures, 91 .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo, 92 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits, 93 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties, 94 .GetPhysicalDevicePerformance = loader_GetPhysicalDevicePerformance, 95 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount, 96 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties, 97 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties, 98 .GetPhysicalDeviceExtensionCount = loader_GetPhysicalDeviceExtensionCount, 99 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties, 100 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback, 101 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback, 102}; 103 104LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd); 105LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer); 106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts); 107 108static void loader_log(VkFlags msg_type, int32_t msg_code, 109 const char *format, ...) 110{ 111 char msg[256]; 112 va_list ap; 113 int ret; 114 115 if (!(msg_type & g_loader_log_msgs)) { 116 return; 117 } 118 119 va_start(ap, format); 120 ret = vsnprintf(msg, sizeof(msg), format, ap); 121 if ((ret >= (int) sizeof(msg)) || ret < 0) { 122 msg[sizeof(msg)-1] = '\0'; 123 } 124 va_end(ap); 125 126#if defined(WIN32) 127 OutputDebugString(msg); 128#endif 129 fputs(msg, stderr); 130 fputc('\n', stderr); 131} 132 133#if defined(WIN32) 134/** 135* Find the list of registry files (names within a key) in key "location". 136* 137* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location" 138* for a list or name/values which are added to a returned list (function return value). 139* The DWORD values within the key must be 0 or they are skipped. 140* Function return is a string with a ';' seperated list of filenames. 141* Function return is NULL if no valid name/value pairs are found in the key, 142* or the key is not found. 143* 144* \returns 145* A string list of filenames as pointer. 146* When done using the returned string list, pointer should be freed. 147*/ 148static char *loader_get_registry_files(const char *location) 149{ 150 LONG rtn_value; 151 HKEY hive, key; 152 DWORD access_flags = KEY_QUERY_VALUE; 153 char name[2048]; 154 char *out = NULL; 155 156 hive = DEFAULT_VK_REGISTRY_HIVE; 157 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key); 158 if (rtn_value != ERROR_SUCCESS) { 159 // We didn't find the key. Try the 32-bit hive (where we've seen the 160 // key end up on some people's systems): 161 access_flags |= KEY_WOW64_32KEY; 162 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key); 163 if (rtn_value != ERROR_SUCCESS) { 164 // We still couldn't find the key, so give up: 165 return NULL; 166 } 167 } 168 169 DWORD idx = 0; 170 DWORD name_size = sizeof(name); 171 DWORD value; 172 DWORD total_size = 4096; 173 DWORD value_size = sizeof(value); 174 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) { 175 if (value_size == sizeof(value) && value == 0) { 176 if (out == NULL) { 177 out = malloc(total_size); 178 out[0] = '\0'; 179 } 180 else if (strlen(out) + name_size + 1 > total_size) { 181 out = realloc(out, total_size * 2); 182 total_size *= 2; 183 } 184 if (out == NULL) { 185 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files"); 186 return NULL; 187 } 188 if (strlen(out) == 0) 189 snprintf(out, name_size + 1, "%s", name); 190 else 191 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name); 192 } 193 } 194 return out; 195} 196 197char *loader_get_registry_string(const HKEY hive, 198 const LPCTSTR sub_key, 199 const char *value) 200{ 201 DWORD access_flags = KEY_QUERY_VALUE; 202 DWORD value_type; 203 HKEY key; 204 LONG rtn_value; 205 char *rtn_str = NULL; 206 DWORD rtn_len = 0; 207 size_t allocated_len = 0; 208 209 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key); 210 if (rtn_value != ERROR_SUCCESS) { 211 // We didn't find the key. Try the 32-bit hive (where we've seen the 212 // key end up on some people's systems): 213 access_flags |= KEY_WOW64_32KEY; 214 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key); 215 if (rtn_value != ERROR_SUCCESS) { 216 // We still couldn't find the key, so give up: 217 return NULL; 218 } 219 } 220 221 rtn_value = RegQueryValueEx(key, value, NULL, &value_type, 222 (PVOID) rtn_str, (LPDWORD) &rtn_len); 223 if (rtn_value == ERROR_SUCCESS) { 224 // If we get to here, we found the key, and need to allocate memory 225 // large enough for rtn_str, and query again: 226 allocated_len = rtn_len + 4; 227 rtn_str = malloc(allocated_len); 228 rtn_value = RegQueryValueEx(key, value, NULL, &value_type, 229 (PVOID) rtn_str, (LPDWORD) &rtn_len); 230 if (rtn_value == ERROR_SUCCESS) { 231 // We added 4 extra bytes to rtn_str, so that we can ensure that 232 // the string is NULL-terminated (albeit, in a brute-force manner): 233 rtn_str[allocated_len-1] = '\0'; 234 } else { 235 // This should never occur, but in case it does, clean up: 236 free(rtn_str); 237 rtn_str = NULL; 238 } 239 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL 240 241 // Close the registry key that was opened: 242 RegCloseKey(key); 243 244 return rtn_str; 245} 246 247 248// For ICD developers, look in the registry, and look for an environment 249// variable for a path(s) where to find the ICD(s): 250static char *loader_get_registry_and_env(const char *env_var, 251 const char *registry_value) 252{ 253 char *env_str = getenv(env_var); 254 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str); 255 char *registry_str = NULL; 256 size_t registry_len = 0; 257 char *rtn_str = NULL; 258 size_t rtn_len; 259 260 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE, 261 "Software\\Vulkan", 262 registry_value); 263 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0; 264 265 rtn_len = env_len + registry_len + 1; 266 if (rtn_len <= 2) { 267 // We found neither the desired registry value, nor the environment 268 // variable; return NULL: 269 return NULL; 270 } else { 271 // We found something, and so we need to allocate memory for the string 272 // to return: 273 rtn_str = malloc(rtn_len); 274 } 275 276 if (registry_len == 0) { 277 // We didn't find the desired registry value, and so we must have found 278 // only the environment variable: 279 _snprintf(rtn_str, rtn_len, "%s", env_str); 280 } else if (env_str != NULL) { 281 // We found both the desired registry value and the environment 282 // variable, so concatenate them both: 283 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str); 284 } else { 285 // We must have only found the desired registry value: 286 _snprintf(rtn_str, rtn_len, "%s", registry_str); 287 } 288 289 if (registry_str) { 290 free(registry_str); 291 } 292 293 return(rtn_str); 294} 295#endif // WIN32 296 297bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) 298{ 299 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false; 300} 301 302/* 303 * Search the given ext_array for an extension 304 * matching the given vk_ext_prop 305 */ 306bool has_vk_extension_property_array( 307 const VkExtensionProperties *vk_ext_prop, 308 const uint32_t count, 309 const VkExtensionProperties *ext_array) 310{ 311 for (uint32_t i = 0; i < count; i++) { 312 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) 313 return true; 314 } 315 return false; 316} 317 318/* 319 * Search the given ext_list for an extension 320 * matching the given vk_ext_prop 321 */ 322bool has_vk_extension_property( 323 const VkExtensionProperties *vk_ext_prop, 324 const struct loader_extension_list *ext_list) 325{ 326 for (uint32_t i = 0; i < ext_list->count; i++) { 327 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop)) 328 return true; 329 } 330 return false; 331} 332 333/* 334 * Search the given ext_list for an extension 335 * matching the given vk_ext_prop 336 */ 337static struct loader_extension_property *get_extension_property_from_vkext( 338 const VkExtensionProperties *vk_ext_prop, 339 const struct loader_extension_list *ext_list) 340{ 341 for (uint32_t i = 0; i < ext_list->count; i++) { 342 const VkExtensionProperties *item = &ext_list->list[i].info; 343 if (compare_vk_extension_properties(item, vk_ext_prop)) 344 return &ext_list->list[i]; 345 } 346 return NULL; 347} 348 349static void loader_get_global_extensions( 350 const PFN_vkGetGlobalExtensionCount fp_get_count, 351 const PFN_vkGetGlobalExtensionProperties fp_get_props, 352 const PFN_vkGPA get_proc_addr, 353 const char *lib_name, 354 const loader_platform_dl_handle lib_handle, 355 const enum extension_origin origin, 356 struct loader_extension_list *ext_list) 357{ 358 uint32_t i, count; 359 struct loader_extension_property ext_props; 360 VkResult res; 361 PFN_vkGPA ext_get_proc_addr; 362 PFN_vkGetInstanceProcAddr get_instance_proc_addr; 363 364 res = fp_get_count(&count); 365 if (res != VK_SUCCESS) { 366 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD"); 367 return; 368 } 369 370 if (get_proc_addr == NULL) 371 get_instance_proc_addr = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr"); 372 373 for (i = 0; i < count; i++) { 374 memset(&ext_props, 0, sizeof(ext_props)); 375 res = fp_get_props(i, &ext_props.info); 376 if (res == VK_SUCCESS) { 377 //TODO eventually get this from the layer config file 378 if (get_proc_addr == NULL) { 379 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; 380 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetInstanceProcAddr", ext_props.info.name); 381 382 if ((ext_get_proc_addr = (PFN_vkGPA) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 383 ext_get_proc_addr = get_instance_proc_addr; 384 } 385 ext_props.origin = origin; 386 ext_props.lib_name = lib_name; 387 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 388 "Global Extension: %s: %s", ext_props.info.name, ext_props.info.description); 389 ext_props.get_proc_addr = (get_proc_addr == NULL) ? ext_get_proc_addr : get_proc_addr; 390 loader_add_to_ext_list(ext_list, 1, &ext_props); 391 } 392 } 393 394 return; 395} 396 397static void loader_get_physical_device_layer_extensions( 398 struct loader_instance *ptr_instance, 399 VkPhysicalDevice physical_device, 400 const struct loader_layer_properties *layer_props, 401 struct loader_extension_list *ext_list) 402{ 403 uint32_t i, count; 404 VkResult res; 405 loader_platform_dl_handle lib_handle; 406 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props; 407 PFN_vkGetPhysicalDeviceExtensionCount get_phys_dev_ext_count; 408 struct loader_extension_property ext_props; 409 PFN_vkGPA ext_get_proc_addr; 410 PFN_vkGetDeviceProcAddr get_device_proc_addr; 411 412 if (layer_props->device_extension_list.count == 0) { 413 return; 414 } 415 416 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER; 417 ext_props.lib_name = layer_props->lib_info.lib_name; 418 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination 419 420 lib_handle = loader_add_layer_lib("device", &ext_props); 421 422 get_phys_dev_ext_props = (PFN_vkGetPhysicalDeviceExtensionProperties) loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties"); 423 get_phys_dev_ext_count = (PFN_vkGetPhysicalDeviceExtensionCount) loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionCount"); 424 get_device_proc_addr = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr"); 425 if (get_phys_dev_ext_count) { 426 res = get_phys_dev_ext_count(physical_device, &count); 427 if (res == VK_SUCCESS) { 428 for (i = 0; i < count; i++) { 429 memset(&ext_props, 0, sizeof(ext_props)); 430 res = get_phys_dev_ext_props(physical_device, i, &ext_props.info); 431 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) { 432 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER; 433 //TODO eventually get this from the layer config file 434 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetDeviceProcAddr", ext_props.info.name); 435 436 if ((ext_get_proc_addr = (PFN_vkGPA) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 437 ext_get_proc_addr = get_device_proc_addr; 438 ext_props.get_proc_addr = ext_get_proc_addr; 439 ext_props.lib_name = layer_props->lib_info.lib_name; 440 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 441 "PhysicalDevice Extension: %s: %s", ext_props.info.name, ext_props.info.description); 442 loader_add_to_ext_list(ext_list, 1, &ext_props); 443 } 444 } 445 } else { 446 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name); 447 } 448 } 449 450 loader_remove_layer_lib(ptr_instance, &ext_props); 451 return; 452} 453 454static bool loader_init_ext_list(struct loader_extension_list *ext_info) 455{ 456 ext_info->capacity = 32 * sizeof(struct loader_extension_property); 457 ext_info->list = malloc(ext_info->capacity); 458 if (ext_info->list == NULL) { 459 return false; 460 } 461 memset(ext_info->list, 0, ext_info->capacity); 462 ext_info->count = 0; 463 return true; 464} 465 466void loader_destroy_ext_list(struct loader_extension_list *ext_info) 467{ 468 free(ext_info->list); 469 ext_info->count = 0; 470 ext_info->capacity = 0; 471} 472 473/** 474 * Search the given search_list for an any layer extensions in the props list. 475 * Add these to the output ext_list. Don't add duplicates to the output ext_list. 476 * Search is limited to extensions having the origin of layer libraries. 477 * Appending to output list handles layer aliases 478 */ 479static void loader_add_layer_ext_to_ext_list( 480 struct loader_extension_list *out_ext_list, 481 uint32_t prop_list_count, 482 const VkExtensionProperties *props, 483 const struct loader_extension_list *search_list) 484{ 485 struct loader_extension_property *ext_prop; 486 487 for (uint32_t i = 0; i < prop_list_count; i++) { 488 const VkExtensionProperties *search_target = &props[i]; 489 // look for duplicates 490 if (has_vk_extension_property(search_target, out_ext_list)) { 491 continue; 492 } 493 494 ext_prop = get_extension_property_from_vkext(search_target, search_list); 495 if (!ext_prop) { 496 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", search_target->name); 497 continue; 498 } 499 500 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) 501 continue; 502 if (ext_prop->alias) 503 ext_prop = ext_prop->alias; 504 loader_add_to_ext_list(out_ext_list, 1, ext_prop); 505 } 506} 507 508/* 509 * Append non-duplicate extension properties defined in prop_list 510 * to the given ext_info list 511 */ 512void loader_add_to_ext_list( 513 struct loader_extension_list *ext_list, 514 uint32_t prop_list_count, 515 const struct loader_extension_property *props) 516{ 517 uint32_t i; 518 struct loader_extension_property *cur_ext; 519 520 if (ext_list->list == NULL || ext_list->capacity == 0) { 521 loader_init_ext_list(ext_list); 522 } 523 524 if (ext_list->list == NULL) 525 return; 526 527 for (i = 0; i < prop_list_count; i++) { 528 cur_ext = (struct loader_extension_property *) &props[i]; 529 530 // look for duplicates 531 if (has_vk_extension_property(&cur_ext->info, ext_list)) { 532 continue; 533 } 534 535 // add to list at end 536 // check for enough capacity 537 if (ext_list->count * sizeof(struct loader_extension_property) 538 >= ext_list->capacity) { 539 // double capacity 540 ext_list->capacity *= 2; 541 ext_list->list = realloc(ext_list->list, ext_list->capacity); 542 } 543 544 /* 545 * Check if any extensions already on the list come from the same 546 * library and use the same Get*ProcAddr. If so, link this 547 * extension to the previous as an alias. That way when we activate 548 * extensions we only activiate the associated layer once no 549 * matter how many extensions are used. 550 */ 551 for (uint32_t j = 0; j < ext_list->count; j++) { 552 struct loader_extension_property *active_property = &ext_list->list[j]; 553 if (cur_ext->lib_name && 554 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER && 555 active_property->origin == VK_EXTENSION_ORIGIN_LAYER && 556 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 && 557 (cur_ext->get_proc_addr == active_property->get_proc_addr) && 558 active_property->alias == NULL) { 559 cur_ext->alias = active_property; 560 break; 561 } 562 } 563 564 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property)); 565 ext_list->count++; 566 } 567} 568 569/* 570 * Search the search_list for any extension with 571 * a name that matches the given ext_name. 572 * Add all matching extensions to the found_list 573 * Do not add if found VkExtensionProperties is already 574 * on the found_list. Add the aliased layer if needed. 575 */ 576static void loader_find_layer_name_add_list( 577 const char *name, 578 const struct loader_extension_list *search_list, 579 struct loader_extension_list *found_list) 580{ 581 for (uint32_t i = 0; i < search_list->count; i++) { 582 struct loader_extension_property *ext_prop = &search_list->list[i]; 583 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER && 584 0 == strcmp(ext_prop->info.name, name)) { 585 if (ext_prop->alias) 586 ext_prop = ext_prop->alias; 587 /* Found an extension with the same name, add to found_list */ 588 loader_add_to_ext_list(found_list, 1, ext_prop); 589 } 590 } 591} 592 593bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop) 594{ 595 uint32_t i; 596 597 for (i = 0; i < loader.global_extensions.count; i++) { 598 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop)) 599 return true; 600 } 601 return false; 602} 603 604/* 605 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT 606 * the extension must provide two entry points for the loader to use: 607 * - "trampoline" entry point - this is the address returned by GetProcAddr 608 * and will always do what's necessary to support a global call. 609 * - "terminator" function - this function will be put at the end of the 610 * instance chain and will contain the necessary logica to call / process 611 * the extension for the appropriate ICDs that are available. 612 * There is no generic mechanism for including these functions, the references 613 * must be placed into the appropriate loader entry points. 614 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests 615 * loader_coalesce_extensions(void) - add extension records to the list of global 616 * extension available to the app. 617 * instance_disp - add function pointer for terminator function to this array. 618 * The extension itself should be in a separate file that will be 619 * linked directly with the loader. 620 */ 621void loader_coalesce_extensions(void) 622{ 623 uint32_t i; 624 struct loader_scanned_icds *icd_list = loader.scanned_icd_list; 625 626 // traverse scanned icd list adding non-duplicate extensions to the list 627 while (icd_list != NULL) { 628 loader_add_to_ext_list(&loader.global_extensions, 629 icd_list->global_extension_list.count, 630 icd_list->global_extension_list.list); 631 icd_list = icd_list->next; 632 }; 633 634 //Traverse layers list adding non-duplicate extensions to the list 635 for (i = 0; i < loader.scanned_layers.count; i++) { 636 loader_add_to_ext_list(&loader.global_extensions, 637 loader.scanned_layers.list[i].instance_extension_list.count, 638 loader.scanned_layers.list[i].instance_extension_list.list); 639 } 640 641 // Traverse loader's extensions, adding non-duplicate extensions to the list 642 debug_report_add_instance_extensions(&loader.global_extensions); 643} 644 645static struct loader_icd *loader_get_icd_and_device(const VkDevice device, 646 struct loader_device **found_dev) 647{ 648 *found_dev = NULL; 649 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 650 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 651 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next) 652 if (dev->device == device) { 653 *found_dev = dev; 654 return icd; 655 } 656 } 657 } 658 return NULL; 659} 660 661static void loader_destroy_logical_device(struct loader_device *dev) 662{ 663 free(dev->app_extension_props); 664 if (dev->activated_layer_list.count) 665 loader_destroy_ext_list(&dev->activated_layer_list); 666 free(dev); 667} 668 669static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list) 670{ 671 struct loader_device *new_dev; 672 673 new_dev = malloc(sizeof(struct loader_device)); 674 if (!new_dev) { 675 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device"); 676 return NULL; 677 } 678 679 memset(new_dev, 0, sizeof(struct loader_device)); 680 681 new_dev->next = *device_list; 682 new_dev->device = dev; 683 *device_list = new_dev; 684 return new_dev; 685} 686 687void loader_remove_logical_device(VkDevice device) 688{ 689 struct loader_device *found_dev, *dev, *prev_dev; 690 struct loader_icd *icd; 691 icd = loader_get_icd_and_device(device, &found_dev); 692 693 if (!icd || !found_dev) 694 return; 695 696 prev_dev = NULL; 697 dev = icd->logical_device_list; 698 while (dev && dev != found_dev) { 699 prev_dev = dev; 700 dev = dev->next; 701 } 702 703 if (prev_dev) 704 prev_dev->next = found_dev->next; 705 else 706 icd->logical_device_list = found_dev->next; 707 loader_destroy_logical_device(found_dev); 708} 709 710 711static void loader_icd_destroy( 712 struct loader_instance *ptr_inst, 713 struct loader_icd *icd) 714{ 715 ptr_inst->total_icd_count--; 716 free(icd->gpus); 717 for (struct loader_device *dev = icd->logical_device_list; dev; ) { 718 struct loader_device *next_dev = dev->next; 719 loader_destroy_logical_device(dev); 720 dev = next_dev; 721 } 722 723 free(icd); 724} 725 726static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned) 727{ 728 struct loader_icd *icd; 729 730 icd = malloc(sizeof(*icd)); 731 if (!icd) 732 return NULL; 733 734 memset(icd, 0, sizeof(*icd)); 735 736 icd->scanned_icds = scanned; 737 738 return icd; 739} 740 741static struct loader_icd *loader_icd_add( 742 struct loader_instance *ptr_inst, 743 const struct loader_scanned_icds *scanned) 744{ 745 struct loader_icd *icd; 746 747 icd = loader_icd_create(scanned); 748 if (!icd) 749 return NULL; 750 751 /* prepend to the list */ 752 icd->next = ptr_inst->icds; 753 ptr_inst->icds = icd; 754 ptr_inst->total_icd_count++; 755 756 return icd; 757} 758 759static void loader_scanned_icd_add(const char *filename) 760{ 761 loader_platform_dl_handle handle; 762 void *fp_create_inst; 763 void *fp_get_global_ext_props; 764 void *fp_get_global_ext_count; 765 void *fp_get_device_ext_props; 766 void *fp_get_device_ext_count; 767 PFN_vkGPA fp_get_proc_addr; 768 struct loader_scanned_icds *new_node; 769 770 // Used to call: dlopen(filename, RTLD_LAZY); 771 handle = loader_platform_open_library(filename); 772 if (!handle) { 773 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename)); 774 return; 775 } 776 777#define LOOKUP(func_ptr, func) do { \ 778 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \ 779 if (!func_ptr) { \ 780 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \ 781 return; \ 782 } \ 783} while (0) 784 785 LOOKUP(fp_create_inst, CreateInstance); 786 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties); 787 LOOKUP(fp_get_global_ext_count, GetGlobalExtensionCount); 788 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties); 789 LOOKUP(fp_get_device_ext_count, GetPhysicalDeviceExtensionCount); 790 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr); 791#undef LOOKUP 792 793 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds) 794 + strlen(filename) + 1); 795 if (!new_node) { 796 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd"); 797 return; 798 } 799 800 new_node->handle = handle; 801 new_node->CreateInstance = fp_create_inst; 802 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props; 803 new_node->GetGlobalExtensionCount = fp_get_global_ext_count; 804 loader_init_ext_list(&new_node->global_extension_list); 805 loader_init_ext_list(&new_node->device_extension_list); 806 new_node->next = loader.scanned_icd_list; 807 808 new_node->lib_name = (char *) (new_node + 1); 809 if (!new_node->lib_name) { 810 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd"); 811 return; 812 } 813 strcpy(new_node->lib_name, filename); 814 815 loader.scanned_icd_list = new_node; 816 817 loader_get_global_extensions( 818 (PFN_vkGetGlobalExtensionCount) fp_get_global_ext_count, 819 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props, 820 fp_get_proc_addr, 821 new_node->lib_name, 822 handle, 823 VK_EXTENSION_ORIGIN_ICD, 824 &new_node->global_extension_list); 825} 826 827static void loader_icd_init_entrys(struct loader_icd *icd, 828 struct loader_scanned_icds *scanned_icds) 829{ 830 /* initialize entrypoint function pointers */ 831 832 #define LOOKUP(func) do { \ 833 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \ 834 if (!icd->func) { \ 835 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \ 836 return; \ 837 } \ 838 } while (0) 839 840 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */ 841 LOOKUP(GetDeviceProcAddr); 842 LOOKUP(DestroyInstance); 843 LOOKUP(EnumeratePhysicalDevices); 844 LOOKUP(GetPhysicalDeviceFeatures); 845 LOOKUP(GetPhysicalDeviceFormatInfo); 846 LOOKUP(GetPhysicalDeviceLimits); 847 LOOKUP(CreateDevice); 848 LOOKUP(GetPhysicalDeviceProperties); 849 LOOKUP(GetPhysicalDeviceMemoryProperties); 850 LOOKUP(GetPhysicalDevicePerformance); 851 LOOKUP(GetPhysicalDeviceQueueCount); 852 LOOKUP(GetPhysicalDeviceQueueProperties); 853 LOOKUP(GetPhysicalDeviceExtensionProperties); 854 LOOKUP(GetPhysicalDeviceExtensionCount); 855 LOOKUP(DbgCreateMsgCallback); 856 LOOKUP(DbgDestroyMsgCallback); 857#undef LOOKUP 858 859 return; 860} 861 862static void loader_debug_init(void) 863{ 864 const char *env; 865 866 if (g_loader_debug > 0) 867 return; 868 869 g_loader_debug = 0; 870 871 /* parse comma-separated debug options */ 872 env = getenv("LOADER_DEBUG"); 873 while (env) { 874 const char *p = strchr(env, ','); 875 size_t len; 876 877 if (p) 878 len = p - env; 879 else 880 len = strlen(env); 881 882 if (len > 0) { 883 if (strncmp(env, "warn", len) == 0) { 884 g_loader_debug |= LOADER_WARN_BIT; 885 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT; 886 } else if (strncmp(env, "info", len) == 0) { 887 g_loader_debug |= LOADER_INFO_BIT; 888 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT; 889 } else if (strncmp(env, "perf", len) == 0) { 890 g_loader_debug |= LOADER_PERF_BIT; 891 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT; 892 } else if (strncmp(env, "error", len) == 0) { 893 g_loader_debug |= LOADER_ERROR_BIT; 894 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT; 895 } else if (strncmp(env, "debug", len) == 0) { 896 g_loader_debug |= LOADER_DEBUG_BIT; 897 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT; 898 } 899 } 900 901 if (!p) 902 break; 903 904 env = p + 1; 905 } 906} 907 908struct loader_manifest_files { 909 uint32_t count; 910 char **filename_list; 911}; 912 913/** 914 * Get next file or dirname given a string list or registry key path 915 * 916 * \returns 917 * A pointer to first char in the next path. 918 * The next path (or NULL) in the list is returned in next_path. 919 * Note: input string is modified in some cases. PASS IN A COPY! 920 */ 921static char *loader_get_next_path(char *path) 922{ 923 uint32_t len; 924 char *next; 925 926 if (path == NULL) 927 return NULL; 928 next = strchr(path, PATH_SEPERATOR); 929 if (next == NULL) { 930 len = (uint32_t) strlen(path); 931 next = path + len; 932 } 933 else { 934 *next = '\0'; 935 next++; 936 } 937 938 return next; 939} 940 941/** 942 * Given a filename (file) and a list of paths (dir), try to find an existing 943 * file in the paths. If filename already is a path then no 944 * searching in the given paths. 945 * 946 * \returns 947 * A string in out_fullpath of either the full path or file. 948 * Side effect is that dir string maybe modified. 949 */ 950static void loader_get_fullpath(const char *file, 951 char *dir, 952 size_t out_size, 953 char *out_fullpath) 954{ 955 char *next_dir; 956 if (strchr(file,DIRECTORY_SYMBOL) == NULL) { 957 //find file exists with prepending given path 958 while (*dir) { 959 next_dir = loader_get_next_path(dir); 960 snprintf(out_fullpath, out_size, "%s%c%s", 961 dir, DIRECTORY_SYMBOL, file); 962 if (loader_platform_file_exists(out_fullpath)) { 963 return; 964 } 965 dir = next_dir; 966 } 967 } 968 snprintf(out_fullpath, out_size, "%s", file); 969} 970 971/** 972 * Read a JSON file into a buffer. 973 * 974 * \returns 975 * A pointer to a cJSON object representing the JSON parse tree. 976 * This returned buffer should be freed by caller. 977 */ 978static cJSON *loader_get_json(const char *filename) 979{ 980 FILE *file; 981 char *json_buf; 982 cJSON *json; 983 uint64_t len; 984 file = fopen(filename,"rb"); 985 fseek(file, 0, SEEK_END); 986 len = ftell(file); 987 fseek(file, 0, SEEK_SET); 988 json_buf = (char*) alloca(len+1); 989 if (json_buf == NULL) { 990 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file"); 991 fclose(file); 992 return NULL; 993 } 994 if (fread(json_buf, sizeof(char), len, file) != len) { 995 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file"); 996 fclose(file); 997 return NULL; 998 } 999 fclose(file); 1000 json_buf[len] = '\0'; 1001 1002 //parse text from file 1003 json = cJSON_Parse(json_buf); 1004 if (json == NULL) 1005 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename); 1006 return json; 1007} 1008 1009/** 1010 * Find the Vulkan library manifest files. 1011 * 1012 * This function scans the location or env_override directories/files 1013 * for a list of JSON manifest files. If env_override is non-NULL 1014 * and has a valid value. Then the location is ignored. Otherwise 1015 * location is used to look for manifest files. The location 1016 * is interpreted as Registry path on Windows and a directory path(s) 1017 * on Linux. 1018 * 1019 * \returns 1020 * A string list of manifest files to be opened in out_files param. 1021 * List has a pointer to string for each manifest filename. 1022 * When done using the list in out_files, pointers should be freed. 1023 * Location or override string lists can be either files or directories as follows: 1024 * | location | override 1025 * -------------------------------- 1026 * Win ICD | files | files 1027 * Win Layer | files | dirs 1028 * Linux ICD | dirs | files 1029 * Linux Layer| dirs | dirs 1030 */ 1031static void loader_get_manifest_files(const char *env_override, 1032 bool is_layer, 1033 const char *location, 1034 struct loader_manifest_files *out_files) 1035{ 1036 char *override = NULL; 1037 char *loc; 1038 char *file, *next_file, *name; 1039 size_t alloced_count = 64; 1040 char full_path[2048]; 1041 DIR *sysdir = NULL; 1042 bool list_is_dirs = false; 1043 struct dirent *dent; 1044 1045 out_files->count = 0; 1046 out_files->filename_list = NULL; 1047 1048 if (env_override != NULL && (override = getenv(env_override))) { 1049#if defined(__linux__) 1050 if (geteuid() != getuid()) { 1051 /* Don't allow setuid apps to use the env var: */ 1052 override = NULL; 1053 } 1054#endif 1055 } 1056 1057 if (location == NULL) { 1058 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1059 "Can't get manifest files with NULL location, env_override=%s", 1060 env_override); 1061 return; 1062 } 1063 1064#if defined(__linux__) 1065 list_is_dirs = (override == NULL || is_layer) ? true : false; 1066#else //WIN32 1067 list_is_dirs = (is_layer && override != NULL) ? true : false; 1068#endif 1069 // Make a copy of the input we are using so it is not modified 1070 // Also handle getting the location(s) from registry on Windows 1071 if (override == NULL) { 1072#if defined (_WIN32) 1073 loc = loader_get_registry_files(location); 1074 if (loc == NULL) { 1075 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files"); 1076 return; 1077 } 1078#else 1079 loc = alloca(strlen(location) + 1); 1080 if (loc == NULL) { 1081 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1082 return; 1083 } 1084 strcpy(loc, location); 1085#endif 1086 } 1087 else { 1088 loc = alloca(strlen(override) + 1); 1089 if (loc == NULL) { 1090 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1091 return; 1092 } 1093 strcpy(loc, override); 1094 } 1095 1096 file = loc; 1097 while (*file) { 1098 next_file = loader_get_next_path(file); 1099 if (list_is_dirs) { 1100 sysdir = opendir(file); 1101 name = NULL; 1102 if (sysdir) { 1103 dent = readdir(sysdir); 1104 if (dent == NULL) 1105 break; 1106 name = &(dent->d_name[0]); 1107 loader_get_fullpath(name, file, sizeof(full_path), full_path); 1108 name = full_path; 1109 } 1110 } 1111 else { 1112#if defined(__linux__) 1113 // only Linux has relative paths 1114 char *dir; 1115 // make a copy of location so it isn't modified 1116 dir = alloca(strlen(location) + 1); 1117 if (dir == NULL) { 1118 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1119 return; 1120 } 1121 strcpy(dir, location); 1122 1123 loader_get_fullpath(file, dir, sizeof(full_path), full_path); 1124 1125 name = full_path; 1126#else // WIN32 1127 name = file; 1128#endif 1129 } 1130 while (name) { 1131 /* Look for files ending with ".json" suffix */ 1132 uint32_t nlen = (uint32_t) strlen(name); 1133 const char *suf = name + nlen - 5; 1134 if ((nlen > 5) && !strncmp(suf, ".json", 5)) { 1135 if (out_files->count == 0) { 1136 out_files->filename_list = malloc(alloced_count * sizeof(char *)); 1137 } 1138 else if (out_files->count == alloced_count) { 1139 out_files->filename_list = realloc(out_files->filename_list, 1140 alloced_count * sizeof(char *) * 2); 1141 alloced_count *= 2; 1142 } 1143 if (out_files->filename_list == NULL) { 1144 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list"); 1145 return; 1146 } 1147 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1); 1148 if (out_files->filename_list[out_files->count] == NULL) { 1149 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1150 return; 1151 } 1152 strcpy(out_files->filename_list[out_files->count], name); 1153 out_files->count++; 1154 } else if (!list_is_dirs) { 1155 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name); 1156 } 1157 if (list_is_dirs) { 1158 dent = readdir(sysdir); 1159 if (dent == NULL) 1160 break; 1161 name = &(dent->d_name[0]); 1162 loader_get_fullpath(name, file, sizeof(full_path), full_path); 1163 name = full_path; 1164 } 1165 else { 1166 break; 1167 } 1168 } 1169 if (sysdir) 1170 closedir(sysdir); 1171 file = next_file; 1172 } 1173 return; 1174} 1175 1176/** 1177 * Try to find the Vulkan ICD driver(s). 1178 * 1179 * This function scans the default system loader path(s) or path 1180 * specified by the \c VK_ICD_FILENAMES environment variable in 1181 * order to find loadable VK ICDs manifest files. From these 1182 * manifest files it finds the ICD libraries. 1183 * 1184 * \returns 1185 * void 1186 */ 1187void loader_icd_scan(void) 1188{ 1189 char *file_str; 1190 struct loader_manifest_files manifest_files; 1191 1192 1193 // convenient place to initialize a mutex 1194 loader_platform_thread_create_mutex(&loader_lock); 1195 1196 // convenient place to initialize logging 1197 loader_debug_init(); 1198 1199 // Get a list of manifest files for ICDs 1200 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO, 1201 &manifest_files); 1202 for (uint32_t i = 0; i < manifest_files.count; i++) { 1203 file_str = manifest_files.filename_list[i]; 1204 if (file_str == NULL) 1205 continue; 1206 1207 cJSON *json, *icd_json; 1208 json = loader_get_json(file_str); 1209 icd_json = cJSON_GetObjectItem(json, "ICD"); 1210 if (icd_json != NULL) { 1211 icd_json = cJSON_GetObjectItem(icd_json, "library_path"); 1212 if (icd_json != NULL) { 1213 char *icd_filename = cJSON_PrintUnformatted(icd_json); 1214 char *icd_file = icd_filename; 1215 if (icd_filename != NULL) { 1216 char def_dir[] = DEFAULT_VK_DRIVERS_PATH; 1217 char *dir = def_dir; 1218 // strip off extra quotes 1219 if (icd_filename[strlen(icd_filename) - 1] == '"') 1220 icd_filename[strlen(icd_filename) - 1] = '\0'; 1221 if (icd_filename[0] == '"') 1222 icd_filename++; 1223#if defined(__linux__) 1224 char full_path[2048]; 1225 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path); 1226 loader_scanned_icd_add(full_path); 1227#else // WIN32 1228 loader_scanned_icd_add(icd_filename); 1229#endif 1230 free(icd_file); 1231 } 1232 } 1233 else 1234 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str); 1235 } 1236 else 1237 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str); 1238 1239 free(file_str); 1240 cJSON_Delete(json); 1241 } 1242 free(manifest_files.filename_list); 1243 1244} 1245 1246 1247void loader_layer_scan(void) 1248{ 1249 const char *p, *next; 1250 char *libPaths = NULL; 1251 DIR *curdir; 1252 struct dirent *dent; 1253 size_t len, i; 1254 char temp_str[1024]; 1255 uint32_t count; 1256 PFN_vkGetGlobalExtensionProperties fp_get_props; 1257 PFN_vkGetGlobalExtensionCount fp_get_count; 1258 1259#if defined(WIN32) 1260 bool must_free_libPaths; 1261 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV, 1262 LAYERS_PATH_REGISTRY_VALUE); 1263 if (libPaths != NULL) { 1264 must_free_libPaths = true; 1265 } else { 1266 must_free_libPaths = false; 1267 libPaths = DEFAULT_VK_LAYERS_PATH; 1268 } 1269#else // WIN32 1270 if (geteuid() == getuid()) { 1271 /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */ 1272 libPaths = getenv(LAYERS_PATH_ENV); 1273 } 1274 if (libPaths == NULL) { 1275 libPaths = DEFAULT_VK_LAYERS_PATH; 1276 } 1277#endif // WIN32 1278 1279 if (libPaths == NULL) { 1280 // Have no paths to search: 1281 return; 1282 } 1283 len = strlen(libPaths); 1284 loader.layer_dirs = malloc(len+1); 1285 if (loader.layer_dirs == NULL) { 1286 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories"); 1287 1288 free(libPaths); 1289 return; 1290 } 1291 // Alloc passed, so we know there is enough space to hold the string 1292 strcpy(loader.layer_dirs, libPaths); 1293#if defined(WIN32) 1294 // Free any allocated memory: 1295 if (must_free_libPaths) { 1296 free(libPaths); 1297 must_free_libPaths = false; 1298 } 1299#endif // WIN32 1300 libPaths = loader.layer_dirs; 1301 1302 if (loader.scanned_layers.capacity == 0) { 1303 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64); 1304 if (loader.scanned_layers.list == NULL) { 1305 //TODO ERR log 1306 return; 1307 } 1308 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64); 1309 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64; 1310 } 1311 else { 1312 /* cleanup any previously scanned libraries */ 1313 //TODO make sure everything is cleaned up properly 1314 for (i = 0; i < loader.scanned_layers.count; i++) { 1315 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL) 1316 free(loader.scanned_layers.list[i].lib_info.lib_name); 1317 free(loader.scanned_layers.list[i].name); 1318 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list); 1319 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list); 1320 loader.scanned_layers.list[i].lib_info.lib_name = NULL; 1321 } 1322 loader.scanned_layers.count = 0; 1323 } 1324 count = 0; 1325 1326 for (p = libPaths; *p; p = next) { 1327 next = strchr(p, PATH_SEPERATOR); 1328 if (next == NULL) { 1329 len = (uint32_t) strlen(p); 1330 next = p + len; 1331 } 1332 else { 1333 len = (uint32_t) (next - p); 1334 *(char *) next = '\0'; 1335 next++; 1336 } 1337 1338 curdir = opendir(p); 1339 if (curdir) { 1340 dent = readdir(curdir); 1341 while (dent) { 1342 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and 1343 * ending with VK_LIBRARY_SUFFIX 1344 */ 1345 if (!strncmp(dent->d_name, 1346 VK_LAYER_LIBRARY_PREFIX, 1347 VK_LAYER_LIBRARY_PREFIX_LEN)) { 1348 uint32_t nlen = (uint32_t) strlen(dent->d_name); 1349 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN; 1350 if ((nlen > VK_LIBRARY_SUFFIX_LEN) && 1351 !strncmp(suf, 1352 VK_LIBRARY_SUFFIX, 1353 VK_LIBRARY_SUFFIX_LEN)) { 1354 loader_platform_dl_handle handle; 1355 snprintf(temp_str, sizeof(temp_str), 1356 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name); 1357 // Used to call: dlopen(temp_str, RTLD_LAZY) 1358 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1359 "Attempt to open library: %s", temp_str); 1360 if ((handle = loader_platform_open_library(temp_str)) == NULL) { 1361 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed"); 1362 dent = readdir(curdir); 1363 continue; 1364 } 1365 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1366 "Opened library: %s", temp_str); 1367 1368 if (count * sizeof(struct loader_layer_properties) >= loader.scanned_layers.capacity) { 1369 loader.scanned_layers.list = realloc(loader.scanned_layers.list, 1370 loader.scanned_layers.capacity * 2); 1371 if (loader.scanned_layers.list == NULL) { 1372 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1373 "realloc failed for scanned layers"); 1374 break; 1375 } 1376 loader.scanned_layers.capacity *= 2; 1377 } 1378 1379 fp_get_count = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionCount"); 1380 fp_get_props = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionProperties"); 1381 if (!fp_get_props || !fp_get_count) { 1382 loader_log(VK_DBG_REPORT_WARN_BIT, 0, 1383 "Couldn't dlsym vkGetGlobalExtensionCount and/or vkGetGlobalExtensionProperties from library %s", 1384 temp_str); 1385 dent = readdir(curdir); 1386 loader_platform_close_library(handle); 1387 continue; 1388 } 1389 1390 loader.scanned_layers.list[count].lib_info.lib_name = 1391 malloc(strlen(temp_str) + 1); 1392 if (loader.scanned_layers.list[count].lib_info.lib_name == NULL) { 1393 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str); 1394 break; 1395 } 1396 1397 strcpy(loader.scanned_layers.list[count].lib_info.lib_name, temp_str); 1398 1399 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s", temp_str); 1400 loader_get_global_extensions( 1401 fp_get_count, 1402 fp_get_props, 1403 NULL, 1404 loader.scanned_layers.list[count].lib_info.lib_name, 1405 handle, 1406 VK_EXTENSION_ORIGIN_LAYER, 1407 &loader.scanned_layers.list[count].instance_extension_list); 1408 1409 1410 count++; 1411 loader_platform_close_library(handle); 1412 } 1413 } 1414 1415 dent = readdir(curdir); 1416 } // while (dir_entry) 1417 closedir(curdir); 1418 } // if (curdir)) 1419 } // for (libpaths) 1420 1421 loader.scanned_layers.count = count; 1422} 1423 1424static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName) 1425{ 1426 // inst is not wrapped 1427 if (inst == VK_NULL_HANDLE) { 1428 return NULL; 1429 } 1430 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst; 1431 void *addr; 1432 1433 if (!strcmp(pName, "vkGetInstanceProcAddr")) 1434 return (void *) loader_gpa_instance_internal; 1435 1436 if (disp_table == NULL) 1437 return NULL; 1438 1439 addr = loader_lookup_instance_dispatch_table(disp_table, pName); 1440 if (addr) { 1441 return addr; 1442 } 1443 1444 if (disp_table->GetInstanceProcAddr == NULL) { 1445 return NULL; 1446 } 1447 return disp_table->GetInstanceProcAddr(inst, pName); 1448} 1449 1450struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index) 1451{ 1452 1453 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 1454 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 1455 for (uint32_t i = 0; i < icd->gpu_count; i++) 1456 if (icd->gpus[i] == gpu) { 1457 *gpu_index = i; 1458 return icd; 1459 } 1460 } 1461 } 1462 return NULL; 1463} 1464 1465static loader_platform_dl_handle loader_add_layer_lib( 1466 const char *chain_type, 1467 struct loader_extension_property *ext_prop) 1468{ 1469 struct loader_lib_info *new_layer_lib_list, *my_lib; 1470 1471 /* Only loader layer libraries here */ 1472 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) { 1473 return NULL; 1474 } 1475 1476 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) { 1477 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) { 1478 /* Have already loaded this library, just increment ref count */ 1479 loader.loaded_layer_lib_list[i].ref_count++; 1480 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1481 "%s Chain: Increment layer reference count for layer library %s", 1482 chain_type, ext_prop->lib_name); 1483 return loader.loaded_layer_lib_list[i].lib_handle; 1484 } 1485 } 1486 1487 /* Haven't seen this library so load it */ 1488 new_layer_lib_list = realloc(loader.loaded_layer_lib_list, 1489 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info)); 1490 if (!new_layer_lib_list) { 1491 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed"); 1492 return NULL; 1493 } 1494 1495 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count]; 1496 1497 /* NOTE: We require that the extension property be immutable */ 1498 my_lib->lib_name = (char *) ext_prop->lib_name; 1499 my_lib->ref_count = 0; 1500 my_lib->lib_handle = NULL; 1501 1502 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) { 1503 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1504 loader_platform_open_library_error(my_lib->lib_name)); 1505 return NULL; 1506 } else { 1507 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1508 "Chain: %s: Loading layer library %s", 1509 chain_type, ext_prop->lib_name); 1510 } 1511 loader.loaded_layer_lib_count++; 1512 loader.loaded_layer_lib_list = new_layer_lib_list; 1513 my_lib->ref_count++; 1514 1515 return my_lib->lib_handle; 1516} 1517 1518static void loader_remove_layer_lib( 1519 struct loader_instance *inst, 1520 struct loader_extension_property *ext_prop) 1521{ 1522 uint32_t idx; 1523 struct loader_lib_info *new_layer_lib_list, *my_lib; 1524 1525 /* Only loader layer libraries here */ 1526 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) { 1527 return; 1528 } 1529 1530 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) { 1531 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) { 1532 /* found matching library */ 1533 idx = i; 1534 my_lib = &loader.loaded_layer_lib_list[i]; 1535 break; 1536 } 1537 } 1538 1539 my_lib->ref_count--; 1540 if (my_lib->ref_count > 0) { 1541 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1542 "Decrement reference count for layer library %s", ext_prop->lib_name); 1543 return; 1544 } 1545 1546 loader_platform_close_library(my_lib->lib_handle); 1547 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1548 "Unloading layer library %s", ext_prop->lib_name); 1549 1550 /* Need to remove unused library from list */ 1551 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info)); 1552 if (!new_layer_lib_list) { 1553 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed"); 1554 return; 1555 } 1556 1557 if (idx > 0) { 1558 /* Copy records before idx */ 1559 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0], 1560 sizeof(struct loader_lib_info) * idx); 1561 } 1562 if (idx < (loader.loaded_layer_lib_count - 1)) { 1563 /* Copy records after idx */ 1564 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1], 1565 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1)); 1566 } 1567 1568 free(loader.loaded_layer_lib_list); 1569 loader.loaded_layer_lib_count--; 1570 loader.loaded_layer_lib_list = new_layer_lib_list; 1571} 1572 1573/** 1574 * Initialize ext_prop from layer_prop. 1575 */ 1576static void loader_init_ext_prop_from_layer_prop( 1577 struct loader_extension_property *ext_prop, 1578 const struct loader_layer_properties *layer_prop) 1579{ 1580 memset(ext_prop, 0, sizeof(*ext_prop)); 1581 ext_prop->info.sType = VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES; 1582 strncpy(ext_prop->info.name, layer_prop->name, sizeof(ext_prop->info.name)); 1583 ext_prop->info.name[sizeof(ext_prop->info.name) - 1] = '\0'; 1584 1585 //TODO from list of string versions to an int, for now just use build version 1586 ext_prop->info.version = VK_API_VERSION; 1587 1588 strncpy(ext_prop->info.description, layer_prop->description, sizeof(ext_prop->info.description)); 1589 ext_prop->info.description[sizeof(ext_prop->info.name) - 1] = '\0'; 1590 ext_prop->lib_name = layer_prop->lib_info.lib_name; 1591 ext_prop->origin = VK_EXTENSION_ORIGIN_LAYER; 1592 ext_prop->alias = NULL; 1593 ext_prop->get_proc_addr = layer_prop->functions.get_instance_proc_addr; 1594} 1595 1596/** 1597 * Go through the search_list and find any layers which match type. If layer 1598 * type match is found in then add it to ext_list. 1599 */ 1600static void loader_add_layer_implicit( 1601 const enum layer_type type, 1602 struct loader_extension_list *ext_list, 1603 const uint32_t count, 1604 const struct loader_layer_properties *search_list) 1605{ 1606 uint32_t i; 1607 for (i = 0; i < count; i++) { 1608 const struct loader_layer_properties *prop = &search_list[i]; 1609 struct loader_extension_property ext_prop; 1610 if (prop->type & type) { 1611 loader_init_ext_prop_from_layer_prop(&ext_prop, prop); 1612 /* Found an extension with the same type, add to ext_list */ 1613 loader_add_to_ext_list(ext_list, 1, &ext_prop); 1614 } 1615 } 1616 1617} 1618 1619/** 1620 * Get the layer name(s) from the env_name environment variable. If layer 1621 * is found in search_list then add it to ext_list. 1622 */ 1623static void loader_add_layer_env( 1624 const char *env_name, 1625 struct loader_extension_list *ext_list, 1626 const struct loader_extension_list *search_list) 1627{ 1628 char *layerEnv; 1629 char *next, *name; 1630 1631 layerEnv = getenv(env_name); 1632 if (layerEnv == NULL) { 1633 return; 1634 } 1635 name = alloca(strlen(layerEnv) + 1); 1636 if (name == NULL) { 1637 return; 1638 } 1639 strcpy(name, layerEnv); 1640 1641 while (name && *name ) { 1642 next = loader_get_next_path(name); 1643 loader_find_layer_name_add_list(name, search_list, ext_list); 1644 name = next; 1645 } 1646 1647 return; 1648} 1649 1650void loader_deactivate_instance_layers(struct loader_instance *instance) 1651{ 1652 if (!instance->activated_layer_list.count) { 1653 return; 1654 } 1655 1656 /* Create instance chain of enabled layers */ 1657 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) { 1658 struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i]; 1659 1660 loader_remove_layer_lib(instance, ext_prop); 1661 } 1662 loader_destroy_ext_list(&instance->activated_layer_list); 1663 instance->activated_layer_list.count = 0; 1664} 1665 1666void loader_enable_instance_layers(struct loader_instance *inst) 1667{ 1668 if (inst == NULL) 1669 return; 1670 1671 if (inst->activated_layer_list.list == NULL || inst->activated_layer_list.capacity == 0) { 1672 loader_init_ext_list(&inst->activated_layer_list); 1673 } 1674 1675 if (inst->activated_layer_list.list == NULL) { 1676 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list"); 1677 return; 1678 } 1679 1680 /* Add any implicit layers first */ 1681 loader_add_layer_implicit( 1682 VK_LAYER_TYPE_INSTANCE_IMPLICIT, 1683 &inst->activated_layer_list, 1684 loader.scanned_layers.count, 1685 loader.scanned_layers.list); 1686 1687 /* Add any layers specified via environment variable first */ 1688 loader_add_layer_env( 1689 "VK_INSTANCE_LAYERS", 1690 &inst->activated_layer_list, 1691 &loader.global_extensions); 1692 1693 /* Add layers specified by the application */ 1694 loader_add_layer_ext_to_ext_list( 1695 &inst->activated_layer_list, 1696 inst->app_extension_count, 1697 inst->app_extension_props, 1698 &loader.global_extensions); 1699} 1700 1701uint32_t loader_activate_instance_layers(struct loader_instance *inst) 1702{ 1703 uint32_t layer_idx; 1704 VkBaseLayerObject *wrappedInstance; 1705 1706 if (inst == NULL) { 1707 return 0; 1708 } 1709 1710 // NOTE inst is unwrapped at this point in time 1711 VkObject baseObj = (VkObject) inst; 1712 VkObject nextObj = (VkObject) inst; 1713 VkBaseLayerObject *nextInstObj; 1714 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal; 1715 1716 if (!inst->activated_layer_list.count) { 1717 return 0; 1718 } 1719 1720 wrappedInstance = malloc(sizeof(VkBaseLayerObject) 1721 * inst->activated_layer_list.count); 1722 if (!wrappedInstance) { 1723 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer"); 1724 return 0; 1725 } 1726 1727 /* Create instance chain of enabled layers */ 1728 layer_idx = inst->activated_layer_list.count - 1; 1729 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) { 1730 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i]; 1731 loader_platform_dl_handle lib_handle; 1732 1733 /* 1734 * Note: An extension's Get*ProcAddr should not return a function pointer for 1735 * any extension entry points until the extension has been enabled. 1736 * To do this requires a different behavior from Get*ProcAddr functions implemented 1737 * in layers. 1738 * The very first call to a layer will be it's Get*ProcAddr function requesting 1739 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table 1740 * with the wrapped object given (either Instance or Device) and return the layer's 1741 * Get*ProcAddr function. The layer should also use this opportunity to record the 1742 * baseObject so that it can find the correct local dispatch table on future calls. 1743 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice 1744 * will not use a wrapped object and must look up their local dispatch table from 1745 * the given baseObject. 1746 */ 1747 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER); 1748 1749 nextInstObj = (wrappedInstance + layer_idx); 1750 nextInstObj->pGPA = nextGPA; 1751 nextInstObj->baseObject = baseObj; 1752 nextInstObj->nextObject = nextObj; 1753 nextObj = (VkObject) nextInstObj; 1754 1755 char funcStr[256]; 1756 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name); 1757 lib_handle = loader_add_layer_lib("instance", ext_prop); 1758 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 1759 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr"); 1760 if (!nextGPA) { 1761 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", ext_prop->lib_name); 1762 1763 /* TODO: Should we return nextObj, nextGPA to previous? */ 1764 continue; 1765 } 1766 1767 loader_log(VK_DBG_REPORT_INFO_BIT, 0, 1768 "Insert instance layer library %s for extension: %s", 1769 ext_prop->lib_name, ext_prop->info.name); 1770 1771 layer_idx--; 1772 } 1773 1774 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj); 1775 1776 free(wrappedInstance); 1777 return inst->activated_layer_list.count; 1778} 1779 1780void loader_activate_instance_layer_extensions(struct loader_instance *inst) 1781{ 1782 1783 loader_init_instance_extension_dispatch_table(inst->disp, 1784 inst->disp->GetInstanceProcAddr, 1785 (VkInstance) inst); 1786} 1787 1788static void loader_enable_device_layers( 1789 struct loader_device *dev, 1790 struct loader_extension_list *ext_list) 1791{ 1792 if (dev == NULL) 1793 return; 1794 1795 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) { 1796 loader_init_ext_list(&dev->activated_layer_list); 1797 } 1798 1799 if (dev->activated_layer_list.list == NULL) { 1800 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list"); 1801 return; 1802 } 1803 1804 /* Add any implicit layers first */ 1805 loader_add_layer_implicit( 1806 VK_LAYER_TYPE_DEVICE_IMPLICIT, 1807 &dev->activated_layer_list, 1808 loader.scanned_layers.count, 1809 loader.scanned_layers.list); 1810 1811 /* Add any layers specified via environment variable next */ 1812 loader_add_layer_env( 1813 "VK_DEVICE_LAYERS", 1814 &dev->activated_layer_list, 1815 &loader.global_extensions); 1816 1817 /* Add layers specified by the application */ 1818 loader_add_layer_ext_to_ext_list( 1819 &dev->activated_layer_list, 1820 dev->app_extension_count, 1821 dev->app_extension_props, 1822 ext_list); 1823} 1824 1825static VkResult scratch_vkCreateDevice( 1826 VkPhysicalDevice gpu, 1827 const VkDeviceCreateInfo *pCreateInfo, 1828 VkDevice *pDevice) 1829{ 1830 return VK_SUCCESS; 1831} 1832 1833static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name) 1834{ 1835 /* CreateDevice workaround: Make the terminator be a scratch function 1836 * that does nothing since we have already called the ICD's create device. 1837 * We can then call down the device chain and have all the layers get set up. 1838 */ 1839 if (!strcmp(name, "vkGetDeviceProcAddr")) 1840 return (void *) loader_GetDeviceChainProcAddr; 1841 if (!strcmp(name, "vkCreateDevice")) 1842 return (void *) scratch_vkCreateDevice; 1843 1844 struct loader_device *found_dev; 1845 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev); 1846 return icd->GetDeviceProcAddr(device, name); 1847} 1848 1849static uint32_t loader_activate_device_layers( 1850 VkPhysicalDevice gpu, 1851 VkDevice device, 1852 struct loader_device *dev, 1853 struct loader_icd *icd, 1854 uint32_t ext_count, 1855 const VkExtensionProperties *ext_props) 1856{ 1857 if (!icd) 1858 return 0; 1859 1860 if (!dev) { 1861 return 0; 1862 } 1863 1864 /* activate any layer libraries */ 1865 VkObject nextObj = (VkObject) device; 1866 VkObject baseObj = nextObj; 1867 VkBaseLayerObject *nextGpuObj; 1868 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr; 1869 VkBaseLayerObject *wrappedGpus; 1870 1871 1872 if (!dev->activated_layer_list.count) 1873 return 0; 1874 1875 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count); 1876 if (!wrappedGpus) { 1877 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer"); 1878 return 0; 1879 } 1880 1881 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) { 1882 1883 struct loader_extension_property *ext_prop = &dev->activated_layer_list.list[i]; 1884 loader_platform_dl_handle lib_handle; 1885 1886 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER); 1887 1888 nextGpuObj = (wrappedGpus + i); 1889 nextGpuObj->pGPA = nextGPA; 1890 nextGpuObj->baseObject = baseObj; 1891 nextGpuObj->nextObject = nextObj; 1892 nextObj = (VkObject) nextGpuObj; 1893 1894 char funcStr[256]; 1895 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name); 1896 lib_handle = loader_add_layer_lib("device", ext_prop); 1897 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 1898 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr"); 1899 if (!nextGPA) { 1900 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", ext_prop->info.name); 1901 continue; 1902 } 1903 1904 loader_log(VK_DBG_REPORT_INFO_BIT, 0, 1905 "Insert device layer library %s for extension: %s", 1906 ext_prop->lib_name, ext_prop->info.name); 1907 1908 } 1909 1910 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA, 1911 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj); 1912 free(wrappedGpus); 1913 1914 return dev->activated_layer_list.count; 1915} 1916 1917VkResult loader_CreateInstance( 1918 const VkInstanceCreateInfo* pCreateInfo, 1919 VkInstance* pInstance) 1920{ 1921 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance; 1922 struct loader_scanned_icds *scanned_icds; 1923 struct loader_icd *icd; 1924 VkResult res; 1925 1926 scanned_icds = loader.scanned_icd_list; 1927 while (scanned_icds) { 1928 icd = loader_icd_add(ptr_instance, scanned_icds); 1929 if (icd) { 1930 res = scanned_icds->CreateInstance(pCreateInfo, 1931 &(icd->instance)); 1932 if (res != VK_SUCCESS) 1933 { 1934 ptr_instance->icds = ptr_instance->icds->next; 1935 loader_icd_destroy(ptr_instance, icd); 1936 icd->instance = VK_NULL_HANDLE; 1937 loader_log(VK_DBG_REPORT_WARN_BIT, 0, 1938 "ICD ignored: failed to CreateInstance on device"); 1939 } else 1940 { 1941 loader_icd_init_entrys(icd, scanned_icds); 1942 } 1943 } 1944 scanned_icds = scanned_icds->next; 1945 } 1946 1947 if (ptr_instance->icds == NULL) { 1948 return VK_ERROR_INCOMPATIBLE_DRIVER; 1949 } 1950 1951 return res; 1952} 1953 1954VkResult loader_DestroyInstance( 1955 VkInstance instance) 1956{ 1957 struct loader_instance *ptr_instance = loader_instance(instance); 1958 struct loader_icd *icds = ptr_instance->icds; 1959 struct loader_icd *next_icd; 1960 VkResult res; 1961 1962 // Remove this instance from the list of instances: 1963 struct loader_instance *prev = NULL; 1964 struct loader_instance *next = loader.instances; 1965 while (next != NULL) { 1966 if (next == ptr_instance) { 1967 // Remove this instance from the list: 1968 free(ptr_instance->app_extension_props); 1969 if (prev) 1970 prev->next = next->next; 1971 else 1972 loader.instances = next->next; 1973 break; 1974 } 1975 prev = next; 1976 next = next->next; 1977 } 1978 if (next == NULL) { 1979 // This must be an invalid instance handle or empty list 1980 return VK_ERROR_INVALID_HANDLE; 1981 } 1982 1983 while (icds) { 1984 if (icds->instance) { 1985 res = icds->DestroyInstance(icds->instance); 1986 if (res != VK_SUCCESS) 1987 loader_log(VK_DBG_REPORT_WARN_BIT, 0, 1988 "ICD ignored: failed to DestroyInstance on device"); 1989 } 1990 next_icd = icds->next; 1991 icds->instance = VK_NULL_HANDLE; 1992 loader_icd_destroy(ptr_instance, icds); 1993 1994 icds = next_icd; 1995 } 1996 1997 1998 return VK_SUCCESS; 1999} 2000 2001VkResult loader_init_physical_device_info( 2002 struct loader_instance *ptr_instance) 2003{ 2004 struct loader_icd *icd; 2005 uint32_t n, count = 0; 2006 VkResult res = VK_ERROR_UNKNOWN; 2007 2008 icd = ptr_instance->icds; 2009 while (icd) { 2010 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL); 2011 if (res != VK_SUCCESS) 2012 return res; 2013 icd->gpu_count = n; 2014 count += n; 2015 icd = icd->next; 2016 } 2017 2018 ptr_instance->total_gpu_count = count; 2019 2020 icd = ptr_instance->icds; 2021 while (icd) { 2022 2023 n = icd->gpu_count; 2024 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice)); 2025 if (!icd->gpus) { 2026 /* TODO: Add cleanup code here */ 2027 return VK_ERROR_OUT_OF_HOST_MEMORY; 2028 } 2029 res = icd->EnumeratePhysicalDevices( 2030 icd->instance, 2031 &n, 2032 icd->gpus); 2033 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) { 2034 2035 for (unsigned int i = 0; i < n; i++) { 2036 2037 loader_init_dispatch(icd->gpus[i], ptr_instance->disp); 2038 2039 if (!loader_init_ext_list(&icd->device_extension_cache[i])) { 2040 /* TODO: Add cleanup code here */ 2041 res = VK_ERROR_OUT_OF_HOST_MEMORY; 2042 } 2043 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionProperties && icd->GetPhysicalDeviceExtensionCount) { 2044 uint32_t extension_count; 2045 2046 res = icd->GetPhysicalDeviceExtensionCount(icd->gpus[i], &extension_count); 2047 if (res == VK_SUCCESS) { 2048 struct loader_extension_property ext_props; 2049 2050 /* Gather all the ICD extensions */ 2051 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) { 2052 res = icd->GetPhysicalDeviceExtensionProperties(icd->gpus[i], 2053 extension_id, &ext_props.info); 2054 if (res == VK_SUCCESS) { 2055 ext_props.origin = VK_EXTENSION_ORIGIN_ICD; 2056 ext_props.lib_name = icd->scanned_icds->lib_name; 2057 ext_props.get_proc_addr = icd->GetDeviceProcAddr; 2058 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props); 2059 } 2060 } 2061 2062 // Traverse layers list adding non-duplicate extensions to the list 2063 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) { 2064 loader_get_physical_device_layer_extensions( 2065 ptr_instance, 2066 icd->gpus[i], 2067 &loader.scanned_layers.list[i], 2068 &icd->device_extension_cache[i]); 2069 } 2070 } 2071 } 2072 2073 if (res != VK_SUCCESS) { 2074 /* clean up any extension lists previously created before this request failed */ 2075 for (uint32_t j = 0; j < i; j++) { 2076 loader_destroy_ext_list(&icd->device_extension_cache[i]); 2077 } 2078 return res; 2079 } 2080 } 2081 2082 count += n; 2083 } 2084 2085 icd = icd->next; 2086 } 2087 2088 return VK_SUCCESS; 2089} 2090 2091VkResult loader_EnumeratePhysicalDevices( 2092 VkInstance instance, 2093 uint32_t* pPhysicalDeviceCount, 2094 VkPhysicalDevice* pPhysicalDevices) 2095{ 2096 uint32_t index = 0; 2097 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 2098 struct loader_icd *icd = ptr_instance->icds; 2099 2100 if (ptr_instance->total_gpu_count == 0) { 2101 loader_init_physical_device_info(ptr_instance); 2102 } 2103 2104 *pPhysicalDeviceCount = ptr_instance->total_gpu_count; 2105 if (!pPhysicalDevices) { 2106 return VK_SUCCESS; 2107 } 2108 2109 while (icd) { 2110 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount); 2111 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice)); 2112 index += icd->gpu_count; 2113 icd = icd->next; 2114 } 2115 2116 return VK_SUCCESS; 2117} 2118 2119VkResult loader_GetPhysicalDeviceProperties( 2120 VkPhysicalDevice gpu, 2121 VkPhysicalDeviceProperties* pProperties) 2122{ 2123 uint32_t gpu_index; 2124 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2125 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2126 2127 if (icd->GetPhysicalDeviceProperties) 2128 res = icd->GetPhysicalDeviceProperties(gpu, pProperties); 2129 2130 return res; 2131} 2132 2133VkResult loader_GetPhysicalDevicePerformance( 2134 VkPhysicalDevice gpu, 2135 VkPhysicalDevicePerformance* pPerformance) 2136{ 2137 uint32_t gpu_index; 2138 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2139 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2140 2141 if (icd->GetPhysicalDevicePerformance) 2142 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance); 2143 2144 return res; 2145} 2146 2147VkResult loader_GetPhysicalDeviceQueueCount( 2148 VkPhysicalDevice gpu, 2149 uint32_t* pCount) 2150{ 2151 uint32_t gpu_index; 2152 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2153 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2154 2155 if (icd->GetPhysicalDeviceQueueCount) 2156 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount); 2157 2158 return res; 2159} 2160 2161VkResult loader_GetPhysicalDeviceQueueProperties ( 2162 VkPhysicalDevice gpu, 2163 uint32_t count, 2164 VkPhysicalDeviceQueueProperties * pProperties) 2165{ 2166 uint32_t gpu_index; 2167 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2168 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2169 2170 if (icd->GetPhysicalDeviceQueueProperties) 2171 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties); 2172 2173 return res; 2174} 2175 2176VkResult loader_GetPhysicalDeviceMemoryProperties ( 2177 VkPhysicalDevice gpu, 2178 VkPhysicalDeviceMemoryProperties* pProperties) 2179{ 2180 uint32_t gpu_index; 2181 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2182 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2183 2184 if (icd->GetPhysicalDeviceMemoryProperties) 2185 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties); 2186 2187 return res; 2188} 2189 2190VkResult loader_GetPhysicalDeviceFeatures( 2191 VkPhysicalDevice physicalDevice, 2192 VkPhysicalDeviceFeatures* pFeatures) 2193{ 2194 uint32_t gpu_index; 2195 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2196 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2197 2198 if (icd->GetPhysicalDeviceFeatures) 2199 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures); 2200 2201 return res; 2202} 2203 2204VkResult loader_GetPhysicalDeviceFormatInfo( 2205 VkPhysicalDevice physicalDevice, 2206 VkFormat format, 2207 VkFormatProperties* pFormatInfo) 2208{ 2209 uint32_t gpu_index; 2210 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2211 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2212 2213 if (icd->GetPhysicalDeviceFormatInfo) 2214 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo); 2215 2216 return res; 2217} 2218 2219VkResult loader_GetPhysicalDeviceLimits( 2220 VkPhysicalDevice physicalDevice, 2221 VkPhysicalDeviceLimits* pLimits) 2222{ 2223 uint32_t gpu_index; 2224 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2225 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2226 2227 if (icd->GetPhysicalDeviceLimits) 2228 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits); 2229 2230 return res; 2231} 2232 2233VkResult loader_CreateDevice( 2234 VkPhysicalDevice gpu, 2235 const VkDeviceCreateInfo* pCreateInfo, 2236 VkDevice* pDevice) 2237{ 2238 uint32_t gpu_index; 2239 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2240 struct loader_device *dev; 2241 VkResult res; 2242 2243 if (!icd->CreateDevice) { 2244 return VK_ERROR_INITIALIZATION_FAILED; 2245 } 2246 2247 res = icd->CreateDevice(gpu, pCreateInfo, pDevice); 2248 if (res != VK_SUCCESS) { 2249 return res; 2250 } 2251 2252 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list); 2253 if (dev == NULL) { 2254 return VK_ERROR_OUT_OF_HOST_MEMORY; 2255 } 2256 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr; 2257 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr, 2258 icd->gpus[gpu_index], icd->gpus[gpu_index]); 2259 2260 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice; 2261 loader_init_dispatch(*pDevice, &dev->loader_dispatch); 2262 2263 dev->app_extension_count = pCreateInfo->extensionCount; 2264 dev->app_extension_props = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount); 2265 if (dev->app_extension_props == NULL && (dev->app_extension_count > 0)) { 2266 return VK_ERROR_OUT_OF_HOST_MEMORY; 2267 } 2268 2269 /* Make local copy of extension list */ 2270 if (dev->app_extension_count > 0 && dev->app_extension_props != NULL) { 2271 memcpy(dev->app_extension_props, pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount); 2272 } 2273 2274 /* 2275 * Put together the complete list of extensions to enable 2276 * This includes extensions requested via environment variables. 2277 */ 2278 loader_enable_device_layers(dev, &icd->device_extension_cache[gpu_index]); 2279 2280 /* 2281 * Load the libraries needed by the extensions on the 2282 * enabled extension list. This will build the device chain 2283 * terminating with the selected device. 2284 */ 2285 loader_activate_device_layers(gpu, *pDevice, dev, icd, 2286 dev->app_extension_count, 2287 dev->app_extension_props); 2288 2289 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice); 2290 2291 dev->loader_dispatch.CreateDevice = icd->CreateDevice; 2292 2293 return res; 2294} 2295 2296static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName) 2297{ 2298 if (instance == VK_NULL_HANDLE) 2299 return NULL; 2300 2301 void *addr; 2302 /* get entrypoint addresses that are global (in the loader)*/ 2303 addr = globalGetProcAddr(pName); 2304 if (addr) 2305 return addr; 2306 2307 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 2308 2309 /* return any extension global entrypoints */ 2310 addr = debug_report_instance_gpa(ptr_instance, pName); 2311 if (addr) { 2312 return addr; 2313 } 2314 2315 /* TODO Remove this once WSI has no loader special code */ 2316 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName); 2317 if (addr) { 2318 return addr; 2319 } 2320 2321 /* return the instance dispatch table entrypoint for extensions */ 2322 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance; 2323 if (disp_table == NULL) 2324 return NULL; 2325 2326 addr = loader_lookup_instance_dispatch_table(disp_table, pName); 2327 if (addr) 2328 return addr; 2329 2330 return NULL; 2331} 2332 2333LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName) 2334{ 2335 return loader_GetInstanceProcAddr(instance, pName); 2336} 2337 2338static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName) 2339{ 2340 if (device == VK_NULL_HANDLE) { 2341 return NULL; 2342 } 2343 2344 void *addr; 2345 2346 /* for entrypoints that loader must handle (ie non-dispatchable or create object) 2347 make sure the loader entrypoint is returned */ 2348 addr = loader_non_passthrough_gpa(pName); 2349 if (addr) { 2350 return addr; 2351 } 2352 2353 /* return any extension device entrypoints the loader knows about */ 2354 /* TODO once WSI has no loader special code remove this */ 2355 addr = wsi_lunarg_GetDeviceProcAddr(device, pName); 2356 if (addr) { 2357 return addr; 2358 } 2359 2360 /* return the dispatch table entrypoint for the fastest case */ 2361 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device; 2362 if (disp_table == NULL) 2363 return NULL; 2364 2365 addr = loader_lookup_device_dispatch_table(disp_table, pName); 2366 if (addr) 2367 return addr; 2368 else { 2369 if (disp_table->GetDeviceProcAddr == NULL) 2370 return NULL; 2371 return disp_table->GetDeviceProcAddr(device, pName); 2372 } 2373} 2374 2375LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName) 2376{ 2377 return loader_GetDeviceProcAddr(device, pName); 2378} 2379 2380LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionCount( 2381 uint32_t* pCount) 2382{ 2383 /* Scan/discover all ICD libraries in a single-threaded manner */ 2384 loader_platform_thread_once(&once_icd, loader_icd_scan); 2385 2386 /* get layer libraries in a single-threaded manner */ 2387 loader_platform_thread_once(&once_layer, loader_layer_scan); 2388 2389 /* merge any duplicate extensions */ 2390 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 2391 2392 loader_platform_thread_lock_mutex(&loader_lock); 2393 *pCount = loader.global_extensions.count; 2394 loader_platform_thread_unlock_mutex(&loader_lock); 2395 return VK_SUCCESS; 2396} 2397 2398LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties( 2399 uint32_t extensionIndex, 2400 VkExtensionProperties* pProperties) 2401{ 2402 2403 /* Scan/discover all ICD libraries in a single-threaded manner */ 2404 loader_platform_thread_once(&once_icd, loader_icd_scan); 2405 2406 /* get layer libraries in a single-threaded manner */ 2407 loader_platform_thread_once(&once_layer, loader_layer_scan); 2408 2409 /* merge any duplicate extensions */ 2410 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 2411 2412 if (extensionIndex >= loader.global_extensions.count) 2413 return VK_ERROR_INVALID_VALUE; 2414 2415 loader_platform_thread_lock_mutex(&loader_lock); 2416 memcpy(pProperties, 2417 &loader.global_extensions.list[extensionIndex], 2418 sizeof(VkExtensionProperties)); 2419 2420 loader_platform_thread_unlock_mutex(&loader_lock); 2421 return VK_SUCCESS; 2422} 2423 2424VkResult loader_GetPhysicalDeviceExtensionCount( 2425 VkPhysicalDevice gpu, 2426 uint32_t* pCount) 2427{ 2428 uint32_t gpu_index; 2429 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2430 *pCount = icd->device_extension_cache[gpu_index].count; 2431 2432 return VK_SUCCESS; 2433} 2434 2435VkResult loader_GetPhysicalDeviceExtensionProperties( 2436 VkPhysicalDevice gpu, 2437 uint32_t extensionIndex, 2438 VkExtensionProperties* pProperties) 2439{ 2440 uint32_t gpu_index; 2441 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2442 2443 if (extensionIndex >= icd->device_extension_cache[gpu_index].count) 2444 return VK_ERROR_INVALID_VALUE; 2445 2446 memcpy( pProperties, 2447 &icd->device_extension_cache[gpu_index].list[extensionIndex], 2448 sizeof(VkExtensionProperties)); 2449 2450 return VK_SUCCESS; 2451} 2452