loader.c revision 4e189562f7213725ba2557bf94b060c5d50f5c2a
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 "gpa_helper.h" 46#include "table_ops.h" 47#include "debug_report.h" 48#include "vk_icd.h" 49#include "cJSON.h" 50 51void loader_add_to_ext_list( 52 struct loader_extension_list *ext_list, 53 uint32_t prop_list_count, 54 const struct loader_extension_property *prop_list); 55 56static loader_platform_dl_handle loader_add_layer_lib( 57 const char *chain_type, 58 struct loader_layer_properties *layer_prop); 59 60static void loader_remove_layer_lib( 61 struct loader_instance *inst, 62 struct loader_layer_properties *layer_prop); 63 64struct loader_struct loader = {0}; 65 66static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName); 67static bool loader_init_ext_list(struct loader_extension_list *ext_info); 68 69enum loader_debug { 70 LOADER_INFO_BIT = 0x01, 71 LOADER_WARN_BIT = 0x02, 72 LOADER_PERF_BIT = 0x04, 73 LOADER_ERROR_BIT = 0x08, 74 LOADER_DEBUG_BIT = 0x10, 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 85// This table contains the loader's instance dispatch table, which contains 86// default functions if no instance layers are activated. This contains 87// pointers to "terminator functions". 88const VkLayerInstanceDispatchTable instance_disp = { 89 .GetInstanceProcAddr = loader_GetInstanceProcAddr, 90 .CreateInstance = loader_CreateInstance, 91 .DestroyInstance = loader_DestroyInstance, 92 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices, 93 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures, 94 .GetPhysicalDeviceFormatProperties = loader_GetPhysicalDeviceFormatProperties, 95 .GetPhysicalDeviceImageFormatProperties = loader_GetPhysicalDeviceImageFormatProperties, 96 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits, 97 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties, 98 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount, 99 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties, 100 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties, 101 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties, 102 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties, 103 .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties, 104 .GetPhysicalDeviceSurfaceSupportWSI = loader_GetPhysicalDeviceSurfaceSupportWSI, 105 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback, 106 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback, 107}; 108 109LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd); 110LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer); 111LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts); 112 113void* loader_heap_alloc( 114 struct loader_instance *instance, 115 size_t size, 116 VkSystemAllocType alloc_type) 117{ 118 if (instance && instance->alloc_callbacks.pfnAlloc) { 119 /* TODO: What should default alignment be? 1, 4, 8, other? */ 120 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type); 121 } 122 return malloc(size); 123} 124 125void* loader_aligned_heap_alloc( 126 struct loader_instance *instance, 127 size_t size, 128 size_t alignment, 129 VkSystemAllocType alloc_type) 130{ 131 if (!instance && instance->alloc_callbacks.pfnAlloc) { 132 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type); 133 } 134#if defined(_WIN32) 135 return _aligned_malloc(alignment, size); 136#else 137 return aligned_alloc(alignment, size); 138#endif 139} 140 141void loader_heap_free( 142 struct loader_instance *instance, 143 void *pMem) 144{ 145 if (!instance && instance->alloc_callbacks.pfnFree) { 146 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem); 147 } 148 free(pMem); 149} 150 151static void loader_log(VkFlags msg_type, int32_t msg_code, 152 const char *format, ...) 153{ 154 char msg[256]; 155 va_list ap; 156 int ret; 157 158 if (!(msg_type & g_loader_log_msgs)) { 159 return; 160 } 161 162 va_start(ap, format); 163 ret = vsnprintf(msg, sizeof(msg), format, ap); 164 if ((ret >= (int) sizeof(msg)) || ret < 0) { 165 msg[sizeof(msg)-1] = '\0'; 166 } 167 va_end(ap); 168 169#if defined(WIN32) 170 OutputDebugString(msg); 171 OutputDebugString("\n"); 172#endif 173 fputs(msg, stderr); 174 fputc('\n', stderr); 175} 176 177#if defined(WIN32) 178/** 179* Find the list of registry files (names within a key) in key "location". 180* 181* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location" 182* for a list or name/values which are added to a returned list (function return value). 183* The DWORD values within the key must be 0 or they are skipped. 184* Function return is a string with a ';' seperated list of filenames. 185* Function return is NULL if no valid name/value pairs are found in the key, 186* or the key is not found. 187* 188* \returns 189* A string list of filenames as pointer. 190* When done using the returned string list, pointer should be freed. 191*/ 192static char *loader_get_registry_files(const char *location) 193{ 194 LONG rtn_value; 195 HKEY hive, key; 196 DWORD access_flags = KEY_QUERY_VALUE; 197 char name[2048]; 198 char *out = NULL; 199 200 hive = DEFAULT_VK_REGISTRY_HIVE; 201 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key); 202 if (rtn_value != ERROR_SUCCESS) { 203 // We didn't find the key. Try the 32-bit hive (where we've seen the 204 // key end up on some people's systems): 205 access_flags |= KEY_WOW64_32KEY; 206 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key); 207 if (rtn_value != ERROR_SUCCESS) { 208 // We still couldn't find the key, so give up: 209 return NULL; 210 } 211 } 212 213 DWORD idx = 0; 214 DWORD name_size = sizeof(name); 215 DWORD value; 216 DWORD total_size = 4096; 217 DWORD value_size = sizeof(value); 218 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) { 219 if (value_size == sizeof(value) && value == 0) { 220 if (out == NULL) { 221 out = malloc(total_size); 222 out[0] = '\0'; 223 } 224 else if (strlen(out) + name_size + 1 > total_size) { 225 out = realloc(out, total_size * 2); 226 total_size *= 2; 227 } 228 if (out == NULL) { 229 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files"); 230 return NULL; 231 } 232 if (strlen(out) == 0) 233 snprintf(out, name_size + 1, "%s", name); 234 else 235 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name); 236 } 237 } 238 return out; 239} 240 241#endif // WIN32 242 243bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) 244{ 245 return strcmp(op1->extName, op2->extName) == 0 ? true : false; 246} 247 248/** 249 * Search the given ext_array for an extension 250 * matching the given vk_ext_prop 251 */ 252bool has_vk_extension_property_array( 253 const VkExtensionProperties *vk_ext_prop, 254 const uint32_t count, 255 const VkExtensionProperties *ext_array) 256{ 257 for (uint32_t i = 0; i < count; i++) { 258 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) 259 return true; 260 } 261 return false; 262} 263 264/** 265 * Search the given ext_list for an extension 266 * matching the given vk_ext_prop 267 */ 268bool has_vk_extension_property( 269 const VkExtensionProperties *vk_ext_prop, 270 const struct loader_extension_list *ext_list) 271{ 272 for (uint32_t i = 0; i < ext_list->count; i++) { 273 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop)) 274 return true; 275 } 276 return false; 277} 278 279static inline bool loader_is_layer_type_device(const enum layer_type type) { 280 if ((type & VK_LAYER_TYPE_DEVICE_EXPLICIT) || 281 (type & VK_LAYER_TYPE_DEVICE_IMPLICIT)) 282 return true; 283 return false; 284} 285 286/* 287 * Search the given layer list for a layer matching the given layer name 288 */ 289static struct loader_layer_properties *get_layer_property( 290 const char *name, 291 const struct loader_layer_list *layer_list) 292{ 293 for (uint32_t i = 0; i < layer_list->count; i++) { 294 const VkLayerProperties *item = &layer_list->list[i].info; 295 if (strcmp(name, item->layerName) == 0) 296 return &layer_list->list[i]; 297 } 298 return NULL; 299} 300 301static void loader_add_global_extensions( 302 const PFN_vkGetGlobalExtensionProperties fp_get_props, 303 const char *lib_name, 304 const loader_platform_dl_handle lib_handle, 305 const enum extension_origin origin, 306 struct loader_extension_list *ext_list) 307{ 308 uint32_t i, count; 309 struct loader_extension_property ext_props; 310 VkExtensionProperties *extension_properties; 311 VkResult res; 312 313 if (!fp_get_props) { 314 /* No GetGlobalExtensionProperties defined */ 315 return; 316 } 317 318 res = fp_get_props(NULL, &count, NULL); 319 if (res != VK_SUCCESS) { 320 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name); 321 return; 322 } 323 324 if (count == 0) { 325 /* No ExtensionProperties to report */ 326 return; 327 } 328 329 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties)); 330 331 res = fp_get_props(NULL, &count, extension_properties); 332 if (res != VK_SUCCESS) { 333 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name); 334 return; 335 } 336 337 for (i = 0; i < count; i++) { 338 memset(&ext_props, 0, sizeof(ext_props)); 339 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties)); 340 //TODO eventually get this from the layer config file 341 ext_props.origin = origin; 342 ext_props.lib_name = lib_name; 343 344 char spec_version[64]; 345 346 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", 347 VK_MAJOR(ext_props.info.specVersion), 348 VK_MINOR(ext_props.info.specVersion), 349 VK_PATCH(ext_props.info.specVersion)); 350 351 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 352 "Global Extension: %s (%s) version %s", 353 ext_props.info.extName, lib_name, spec_version); 354 loader_add_to_ext_list(ext_list, 1, &ext_props); 355 } 356 357 return; 358} 359 360static void loader_add_physical_device_extensions( 361 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props, 362 VkPhysicalDevice physical_device, 363 const enum extension_origin origin, 364 const char *lib_name, 365 struct loader_extension_list *ext_list) 366{ 367 uint32_t i, count; 368 VkResult res; 369 struct loader_extension_property ext_props; 370 VkExtensionProperties *extension_properties; 371 372 memset(&ext_props, 0, sizeof(ext_props)); 373 ext_props.origin = origin; 374 ext_props.lib_name = lib_name; 375 376 if (get_phys_dev_ext_props) { 377 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL); 378 if (res == VK_SUCCESS && count > 0) { 379 380 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties)); 381 382 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties); 383 for (i = 0; i < count; i++) { 384 char spec_version[64]; 385 386 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties)); 387 388 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", 389 VK_MAJOR(ext_props.info.specVersion), 390 VK_MINOR(ext_props.info.specVersion), 391 VK_PATCH(ext_props.info.specVersion)); 392 393 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 394 "PhysicalDevice Extension: %s (%s) version %s", 395 ext_props.info.extName, lib_name, spec_version); 396 loader_add_to_ext_list(ext_list, 1, &ext_props); 397 } 398 } else { 399 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name); 400 } 401 } 402 403 return; 404} 405 406static bool loader_init_ext_list(struct loader_extension_list *ext_info) 407{ 408 ext_info->capacity = 32 * sizeof(struct loader_extension_property); 409 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 410 ext_info->list = malloc(ext_info->capacity); 411 if (ext_info->list == NULL) { 412 return false; 413 } 414 memset(ext_info->list, 0, ext_info->capacity); 415 ext_info->count = 0; 416 return true; 417} 418 419void loader_destroy_ext_list(struct loader_extension_list *ext_info) 420{ 421 free(ext_info->list); 422 ext_info->count = 0; 423 ext_info->capacity = 0; 424} 425 426/** 427 * Search the given search_list for any layers in the props list. 428 * Add these to the output layer_list. Don't add duplicates to the output layer_list. 429 */ 430static VkResult loader_add_layer_names_to_list( 431 struct loader_layer_list *output_list, 432 uint32_t name_count, 433 const char * const *names, 434 const struct loader_layer_list *search_list) 435{ 436 struct loader_layer_properties *layer_prop; 437 VkResult err = VK_SUCCESS; 438 439 for (uint32_t i = 0; i < name_count; i++) { 440 const char *search_target = names[i]; 441 layer_prop = get_layer_property(search_target, search_list); 442 if (!layer_prop) { 443 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target); 444 err = VK_ERROR_INVALID_LAYER; 445 continue; 446 } 447 448 loader_add_to_layer_list(output_list, 1, layer_prop); 449 } 450 451 return err; 452} 453 454/* 455 * Append non-duplicate extension properties defined in props 456 * to the given ext_list. 457 */ 458void loader_add_to_ext_list( 459 struct loader_extension_list *ext_list, 460 uint32_t prop_list_count, 461 const struct loader_extension_property *props) 462{ 463 uint32_t i; 464 struct loader_extension_property *cur_ext; 465 466 if (ext_list->list == NULL || ext_list->capacity == 0) { 467 loader_init_ext_list(ext_list); 468 } 469 470 if (ext_list->list == NULL) 471 return; 472 473 for (i = 0; i < prop_list_count; i++) { 474 cur_ext = (struct loader_extension_property *) &props[i]; 475 476 // look for duplicates 477 if (has_vk_extension_property(&cur_ext->info, ext_list)) { 478 continue; 479 } 480 481 // add to list at end 482 // check for enough capacity 483 if (ext_list->count * sizeof(struct loader_extension_property) 484 >= ext_list->capacity) { 485 // double capacity 486 ext_list->capacity *= 2; 487 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 488 ext_list->list = realloc(ext_list->list, ext_list->capacity); 489 } 490 491 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property)); 492 ext_list->count++; 493 } 494} 495 496/* 497 * Manage lists of VkLayerProperties 498 */ 499static bool loader_init_layer_list(struct loader_layer_list *list) 500{ 501 list->capacity = 32 * sizeof(struct loader_layer_properties); 502 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 503 list->list = malloc(list->capacity); 504 if (list->list == NULL) { 505 return false; 506 } 507 memset(list->list, 0, list->capacity); 508 list->count = 0; 509 return true; 510} 511 512void loader_destroy_layer_list(struct loader_layer_list *layer_list) 513{ 514 free(layer_list->list); 515 layer_list->count = 0; 516 layer_list->capacity = 0; 517} 518 519/* 520 * Manage list of layer libraries (loader_lib_info) 521 */ 522static bool loader_init_layer_library_list(struct loader_layer_library_list *list) 523{ 524 list->capacity = 32 * sizeof(struct loader_lib_info); 525 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 526 list->list = malloc(list->capacity); 527 if (list->list == NULL) { 528 return false; 529 } 530 memset(list->list, 0, list->capacity); 531 list->count = 0; 532 return true; 533} 534 535void loader_destroy_layer_library_list(struct loader_layer_library_list *list) 536{ 537 for (uint32_t i = 0; i < list->count; i++) { 538 free(list->list[i].lib_name); 539 } 540 free(list->list); 541 list->count = 0; 542 list->capacity = 0; 543} 544 545void loader_add_to_layer_library_list( 546 struct loader_layer_library_list *list, 547 uint32_t item_count, 548 const struct loader_lib_info *new_items) 549{ 550 uint32_t i; 551 struct loader_lib_info *item; 552 553 if (list->list == NULL || list->capacity == 0) { 554 loader_init_layer_library_list(list); 555 } 556 557 if (list->list == NULL) 558 return; 559 560 for (i = 0; i < item_count; i++) { 561 item = (struct loader_lib_info *) &new_items[i]; 562 563 // look for duplicates 564 for (uint32_t j = 0; j < list->count; j++) { 565 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) { 566 continue; 567 } 568 } 569 570 // add to list at end 571 // check for enough capacity 572 if (list->count * sizeof(struct loader_lib_info) 573 >= list->capacity) { 574 // double capacity 575 list->capacity *= 2; 576 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 577 list->list = realloc(list->list, list->capacity); 578 } 579 580 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info)); 581 list->count++; 582 } 583} 584 585 586/* 587 * Search the given layer list for a list 588 * matching the given VkLayerProperties 589 */ 590bool has_vk_layer_property( 591 const VkLayerProperties *vk_layer_prop, 592 const struct loader_layer_list *list) 593{ 594 for (uint32_t i = 0; i < list->count; i++) { 595 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) 596 return true; 597 } 598 return false; 599} 600 601/* 602 * Search the given layer list for a layer 603 * matching the given name 604 */ 605bool has_layer_name( 606 const char *name, 607 const struct loader_layer_list *list) 608{ 609 for (uint32_t i = 0; i < list->count; i++) { 610 if (strcmp(name, list->list[i].info.layerName) == 0) 611 return true; 612 } 613 return false; 614} 615 616/* 617 * Append non-duplicate layer properties defined in prop_list 618 * to the given layer_info list 619 */ 620void loader_add_to_layer_list( 621 struct loader_layer_list *list, 622 uint32_t prop_list_count, 623 const struct loader_layer_properties *props) 624{ 625 uint32_t i; 626 struct loader_layer_properties *layer; 627 628 if (list->list == NULL || list->capacity == 0) { 629 loader_init_layer_list(list); 630 } 631 632 if (list->list == NULL) 633 return; 634 635 for (i = 0; i < prop_list_count; i++) { 636 layer = (struct loader_layer_properties *) &props[i]; 637 638 // look for duplicates 639 if (has_vk_layer_property(&layer->info, list)) { 640 continue; 641 } 642 643 // add to list at end 644 // check for enough capacity 645 if (list->count * sizeof(struct loader_layer_properties) 646 >= list->capacity) { 647 // double capacity 648 list->capacity *= 2; 649 list->list = realloc(list->list, list->capacity); 650 } 651 652 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties)); 653 list->count++; 654 } 655} 656 657/** 658 * Search the search_list for any layer with a name 659 * that matches the given name and a type that matches the given type 660 * Add all matching layers to the found_list 661 * Do not add if found loader_layer_properties is already 662 * on the found_list. 663 */ 664static void loader_find_layer_name_add_list( 665 const char *name, 666 const enum layer_type type, 667 const struct loader_layer_list *search_list, 668 struct loader_layer_list *found_list) 669{ 670 for (uint32_t i = 0; i < search_list->count; i++) { 671 struct loader_layer_properties *layer_prop = &search_list->list[i]; 672 if (0 == strcmp(layer_prop->info.layerName, name) && 673 (layer_prop->type & type)) { 674 /* Found a layer with the same name, add to found_list */ 675 loader_add_to_layer_list(found_list, 1, layer_prop); 676 } 677 } 678} 679 680static struct loader_extension_property *get_extension_property( 681 const char *name, 682 const struct loader_extension_list *list) 683{ 684 for (uint32_t i = 0; i < list->count; i++) { 685 const VkExtensionProperties *item = &list->list[i].info; 686 if (strcmp(name, item->extName) == 0) 687 return &list->list[i]; 688 } 689 return NULL; 690} 691 692/* 693 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT 694 * the extension must provide two entry points for the loader to use: 695 * - "trampoline" entry point - this is the address returned by GetProcAddr 696 * and will always do what's necessary to support a global call. 697 * - "terminator" function - this function will be put at the end of the 698 * instance chain and will contain the necessary logica to call / process 699 * the extension for the appropriate ICDs that are available. 700 * There is no generic mechanism for including these functions, the references 701 * must be placed into the appropriate loader entry points. 702 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests 703 * loader_coalesce_extensions(void) - add extension records to the list of global 704 * extension available to the app. 705 * instance_disp - add function pointer for terminator function to this array. 706 * The extension itself should be in a separate file that will be 707 * linked directly with the loader. 708 */ 709void loader_coalesce_extensions(void) 710{ 711 struct loader_scanned_icds *icd_list = loader.scanned_icd_list; 712 713 // traverse scanned icd list adding non-duplicate extensions to the list 714 while (icd_list != NULL) { 715 loader_add_to_ext_list(&loader.global_extensions, 716 icd_list->global_extension_list.count, 717 icd_list->global_extension_list.list); 718 icd_list = icd_list->next; 719 }; 720 721 // Traverse loader's extensions, adding non-duplicate extensions to the list 722 wsi_swapchain_add_instance_extensions(&loader.global_extensions); 723 debug_report_add_instance_extensions(&loader.global_extensions); 724} 725 726static struct loader_icd *loader_get_icd_and_device(const VkDevice device, 727 struct loader_device **found_dev) 728{ 729 *found_dev = NULL; 730 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 731 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 732 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next) 733 if (dev->device == device) { 734 *found_dev = dev; 735 return icd; 736 } 737 } 738 } 739 return NULL; 740} 741 742static void loader_destroy_logical_device(struct loader_device *dev) 743{ 744 free(dev->app_extension_props); 745 if (dev->activated_layer_list.count) 746 loader_destroy_layer_list(&dev->activated_layer_list); 747 free(dev); 748} 749 750static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list) 751{ 752 struct loader_device *new_dev; 753 754 new_dev = malloc(sizeof(struct loader_device)); 755 if (!new_dev) { 756 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device"); 757 return NULL; 758 } 759 760 memset(new_dev, 0, sizeof(struct loader_device)); 761 762 new_dev->next = *device_list; 763 new_dev->device = dev; 764 *device_list = new_dev; 765 return new_dev; 766} 767 768void loader_remove_logical_device(VkDevice device) 769{ 770 struct loader_device *found_dev, *dev, *prev_dev; 771 struct loader_icd *icd; 772 icd = loader_get_icd_and_device(device, &found_dev); 773 774 if (!icd || !found_dev) 775 return; 776 777 prev_dev = NULL; 778 dev = icd->logical_device_list; 779 while (dev && dev != found_dev) { 780 prev_dev = dev; 781 dev = dev->next; 782 } 783 784 if (prev_dev) 785 prev_dev->next = found_dev->next; 786 else 787 icd->logical_device_list = found_dev->next; 788 loader_destroy_logical_device(found_dev); 789} 790 791 792static void loader_icd_destroy( 793 struct loader_instance *ptr_inst, 794 struct loader_icd *icd) 795{ 796 ptr_inst->total_icd_count--; 797 free(icd->gpus); 798 for (struct loader_device *dev = icd->logical_device_list; dev; ) { 799 struct loader_device *next_dev = dev->next; 800 loader_destroy_logical_device(dev); 801 dev = next_dev; 802 } 803 804 free(icd); 805} 806 807static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned) 808{ 809 struct loader_icd *icd; 810 811 icd = malloc(sizeof(*icd)); 812 if (!icd) 813 return NULL; 814 815 memset(icd, 0, sizeof(*icd)); 816 817 icd->scanned_icds = scanned; 818 819 return icd; 820} 821 822static struct loader_icd *loader_icd_add( 823 struct loader_instance *ptr_inst, 824 const struct loader_scanned_icds *scanned) 825{ 826 struct loader_icd *icd; 827 828 icd = loader_icd_create(scanned); 829 if (!icd) 830 return NULL; 831 832 /* prepend to the list */ 833 icd->next = ptr_inst->icds; 834 ptr_inst->icds = icd; 835 ptr_inst->total_icd_count++; 836 837 return icd; 838} 839 840static void loader_scanned_icd_add(const char *filename) 841{ 842 loader_platform_dl_handle handle; 843 PFN_vkCreateInstance fp_create_inst; 844 PFN_vkGetGlobalExtensionProperties fp_get_global_ext_props; 845 PFN_vkGetInstanceProcAddr fp_get_proc_addr; 846 struct loader_scanned_icds *new_node; 847 848 // Used to call: dlopen(filename, RTLD_LAZY); 849 handle = loader_platform_open_library(filename); 850 if (!handle) { 851 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename)); 852 return; 853 } 854 855#define LOOKUP_LD(func_ptr, func) do { \ 856 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \ 857 if (!func_ptr) { \ 858 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \ 859 return; \ 860 } \ 861} while (0) 862 863 LOOKUP_LD(fp_get_proc_addr, GetInstanceProcAddr); 864 LOOKUP_LD(fp_create_inst, CreateInstance); 865 LOOKUP_LD(fp_get_global_ext_props, GetGlobalExtensionProperties); 866 867#undef LOOKUP_LD 868 869 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds) 870 + strlen(filename) + 1); 871 if (!new_node) { 872 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd"); 873 return; 874 } 875 876 new_node->handle = handle; 877 new_node->GetInstanceProcAddr = fp_get_proc_addr; 878 new_node->CreateInstance = fp_create_inst; 879 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props; 880 loader_init_ext_list(&new_node->global_extension_list); 881 loader_init_ext_list(&new_node->device_extension_list); 882 new_node->next = loader.scanned_icd_list; 883 884 new_node->lib_name = (char *) (new_node + 1); 885 if (!new_node->lib_name) { 886 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd"); 887 return; 888 } 889 strcpy(new_node->lib_name, filename); 890 891 loader.scanned_icd_list = new_node; 892 893 loader_add_global_extensions( 894 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props, 895 new_node->lib_name, 896 handle, 897 VK_EXTENSION_ORIGIN_ICD, 898 &new_node->global_extension_list); 899} 900 901static struct loader_extension_list *loader_global_extensions(const char *pLayerName) 902{ 903 if (pLayerName == NULL || (strlen(pLayerName) == 0)) { 904 return &loader.global_extensions; 905 } 906 907 /* Find and return global extension list for given layer */ 908 for (uint32_t i = 0; i < loader.scanned_instance_layers.count; i++) { 909 struct loader_layer_properties *props = &loader.scanned_instance_layers.list[i]; 910 if (strcmp(props->info.layerName, pLayerName) == 0) { 911 return &props->instance_extension_list; 912 } 913 } 914 915 return NULL; 916} 917 918 919static void loader_physical_device_extensions( 920 struct loader_icd *icd, 921 uint32_t gpu_idx, 922 const char *layer_name, 923 uint32_t *count, 924 struct loader_extension_list **list) 925{ 926 *count = 0; 927 if (layer_name == NULL || (strlen(layer_name) == 0)) { 928 *count = icd->device_extension_cache[gpu_idx].count; 929 *list = &icd->device_extension_cache[gpu_idx]; 930 return; 931 } 932 for (uint32_t i = 0; i < loader.scanned_device_layers.count; i++) { 933 struct loader_layer_properties *props = &(loader.scanned_device_layers.list[i]); 934 if ((strcmp(layer_name, props->info.layerName) == 0)) { 935 *count = props->device_extension_list.count; 936 *list = &props->device_extension_list; 937 break; 938 } 939 } 940} 941 942static bool loader_icd_init_entrys(struct loader_icd *icd, 943 VkInstance inst, 944 const PFN_vkGetInstanceProcAddr fp_gipa) 945{ 946 /* initialize entrypoint function pointers */ 947 948 #define LOOKUP_GIPA(func, required) do { \ 949 icd->func = (PFN_vk ##func) fp_gipa(inst, "vk" #func); \ 950 if (!icd->func && required) { \ 951 loader_log(VK_DBG_REPORT_WARN_BIT, 0, \ 952 loader_platform_get_proc_address_error("vk" #func)); \ 953 return false; \ 954 } \ 955 } while (0) 956 957 LOOKUP_GIPA(GetDeviceProcAddr, true); 958 LOOKUP_GIPA(DestroyInstance, true); 959 LOOKUP_GIPA(EnumeratePhysicalDevices, true); 960 LOOKUP_GIPA(GetPhysicalDeviceFeatures, true); 961 LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true); 962 LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true); 963 LOOKUP_GIPA(GetPhysicalDeviceLimits, true); 964 LOOKUP_GIPA(CreateDevice, true); 965 LOOKUP_GIPA(GetPhysicalDeviceProperties, true); 966 LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true); 967 LOOKUP_GIPA(GetPhysicalDeviceQueueCount, true); 968 LOOKUP_GIPA(GetPhysicalDeviceQueueProperties, true); 969 LOOKUP_GIPA(GetPhysicalDeviceExtensionProperties, true); 970 LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true); 971 LOOKUP_GIPA(DbgCreateMsgCallback, false); 972 LOOKUP_GIPA(DbgDestroyMsgCallback, false); 973 LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportWSI, false); 974 975#undef LOOKUP_GIPA 976 977 return true; 978} 979 980static void loader_debug_init(void) 981{ 982 const char *env; 983 984 if (g_loader_debug > 0) 985 return; 986 987 g_loader_debug = 0; 988 989 /* parse comma-separated debug options */ 990 env = getenv("LOADER_DEBUG"); 991 while (env) { 992 const char *p = strchr(env, ','); 993 size_t len; 994 995 if (p) 996 len = p - env; 997 else 998 len = strlen(env); 999 1000 if (len > 0) { 1001 if (strncmp(env, "warn", len) == 0) { 1002 g_loader_debug |= LOADER_WARN_BIT; 1003 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT; 1004 } else if (strncmp(env, "info", len) == 0) { 1005 g_loader_debug |= LOADER_INFO_BIT; 1006 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT; 1007 } else if (strncmp(env, "perf", len) == 0) { 1008 g_loader_debug |= LOADER_PERF_BIT; 1009 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT; 1010 } else if (strncmp(env, "error", len) == 0) { 1011 g_loader_debug |= LOADER_ERROR_BIT; 1012 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT; 1013 } else if (strncmp(env, "debug", len) == 0) { 1014 g_loader_debug |= LOADER_DEBUG_BIT; 1015 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT; 1016 } 1017 } 1018 1019 if (!p) 1020 break; 1021 1022 env = p + 1; 1023 } 1024} 1025 1026struct loader_manifest_files { 1027 uint32_t count; 1028 char **filename_list; 1029}; 1030 1031/** 1032 * Get next file or dirname given a string list or registry key path 1033 * 1034 * \returns 1035 * A pointer to first char in the next path. 1036 * The next path (or NULL) in the list is returned in next_path. 1037 * Note: input string is modified in some cases. PASS IN A COPY! 1038 */ 1039static char *loader_get_next_path(char *path) 1040{ 1041 uint32_t len; 1042 char *next; 1043 1044 if (path == NULL) 1045 return NULL; 1046 next = strchr(path, PATH_SEPERATOR); 1047 if (next == NULL) { 1048 len = (uint32_t) strlen(path); 1049 next = path + len; 1050 } 1051 else { 1052 *next = '\0'; 1053 next++; 1054 } 1055 1056 return next; 1057} 1058 1059/** 1060 * Given a path which is absolute or relative. Expand the path if relative otherwise 1061 * leave the path unmodified if absolute. The path which is relative from is 1062 * given in rel_base and should include trailing directory seperator '/' 1063 * 1064 * \returns 1065 * A string in out_fullpath of the full absolute path 1066 * Side effect is that dir string maybe modified. 1067 */ 1068static void loader_expand_path(const char *path, 1069 const char *rel_base, 1070 size_t out_size, 1071 char *out_fullpath) 1072{ 1073 if (loader_platform_is_path_absolute(path)) { 1074 strncpy(out_fullpath, path, out_size); 1075 out_fullpath[out_size - 1] = '\0'; 1076 } 1077 else { 1078 // convert relative to absolute path based on rel_base 1079 size_t len = strlen(path); 1080 strncpy(out_fullpath, rel_base, out_size); 1081 out_fullpath[out_size - 1] = '\0'; 1082 assert(out_size >= strlen(out_fullpath) + len + 1); 1083 strncat(out_fullpath, path, len); 1084 } 1085} 1086 1087/** 1088 * Given a filename (file) and a list of paths (dir), try to find an existing 1089 * file in the paths. If filename already is a path then no 1090 * searching in the given paths. 1091 * 1092 * \returns 1093 * A string in out_fullpath of either the full path or file. 1094 * Side effect is that dir string maybe modified. 1095 */ 1096static void loader_get_fullpath(const char *file, 1097 char *dir, 1098 size_t out_size, 1099 char *out_fullpath) 1100{ 1101 char *next_dir; 1102 if (strchr(file,DIRECTORY_SYMBOL) == NULL) { 1103 //find file exists with prepending given path 1104 while (*dir) { 1105 next_dir = loader_get_next_path(dir); 1106 snprintf(out_fullpath, out_size, "%s%c%s", 1107 dir, DIRECTORY_SYMBOL, file); 1108 if (loader_platform_file_exists(out_fullpath)) { 1109 return; 1110 } 1111 dir = next_dir; 1112 } 1113 } 1114 snprintf(out_fullpath, out_size, "%s", file); 1115} 1116 1117/** 1118 * Read a JSON file into a buffer. 1119 * 1120 * \returns 1121 * A pointer to a cJSON object representing the JSON parse tree. 1122 * This returned buffer should be freed by caller. 1123 */ 1124static cJSON *loader_get_json(const char *filename) 1125{ 1126 FILE *file; 1127 char *json_buf; 1128 cJSON *json; 1129 uint64_t len; 1130 file = fopen(filename,"rb"); 1131 fseek(file, 0, SEEK_END); 1132 len = ftell(file); 1133 fseek(file, 0, SEEK_SET); 1134 json_buf = (char*) loader_stack_alloc(len+1); 1135 if (json_buf == NULL) { 1136 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file"); 1137 fclose(file); 1138 return NULL; 1139 } 1140 if (fread(json_buf, sizeof(char), len, file) != len) { 1141 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file"); 1142 fclose(file); 1143 return NULL; 1144 } 1145 fclose(file); 1146 json_buf[len] = '\0'; 1147 1148 //parse text from file 1149 json = cJSON_Parse(json_buf); 1150 if (json == NULL) 1151 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename); 1152 return json; 1153} 1154 1155/** 1156 * Given a cJSON struct (json) of the top level JSON object from layer manifest 1157 * file, add entry to the layer_list. 1158 * Fill out the layer_properties in this list entry from the input cHJSON object. 1159 * 1160 * \returns 1161 * void 1162 * layer_list has a new entry and initialized accordingly. 1163 * If the json input object does not have all the required fields no entry 1164 * is added to the list. 1165 */ 1166static void loader_add_layer_properties(struct loader_layer_list *layer_instance_list, 1167 struct loader_layer_list *layer_device_list, 1168 cJSON *json, 1169 bool is_implicit, 1170 char *filename) 1171{ 1172 /* Fields in layer manifest file that are required: 1173 * (required) “file_format_version” 1174 * following are required in the "layer" object: 1175 * (required) "name" 1176 * (required) "type" 1177 * (required) “library_path” 1178 * (required) “abi_versions” 1179 * (required) “implementation_version” 1180 * (required) “description” 1181 * (required for implicit layers) “disable_environment” 1182 * 1183 * First get all required items and if any missing abort 1184 */ 1185 1186 struct loader_layer_list *layer_list; 1187 cJSON *item, *layer_node, *ext_item; 1188 char *temp; 1189 char *name, *type, *library_path, *abi_versions; 1190 char *implementation_version, *description; 1191 cJSON *disable_environment; 1192 int i; 1193 struct loader_extension_property ext_prop; 1194 item = cJSON_GetObjectItem(json, "file_format_version"); 1195 if (item == NULL) { 1196 return; 1197 } 1198 char *file_vers = cJSON_PrintUnformatted(item); 1199 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s", 1200 filename, file_vers); 1201 if (strcmp(file_vers, "\"0.9.0\"") != 0) 1202 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors"); 1203 free(file_vers); 1204 1205 //TODO handle multiple layer nodes in the file 1206 //TODO handle scanned libraries not one per layer property 1207 layer_node = cJSON_GetObjectItem(json, "layer"); 1208 if (layer_node == NULL) { 1209 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping"); 1210 return; 1211 } 1212#define GET_JSON_OBJECT(node, var) { \ 1213 var = cJSON_GetObjectItem(node, #var); \ 1214 if (var == NULL) \ 1215 return; \ 1216 } 1217#define GET_JSON_ITEM(node, var) { \ 1218 item = cJSON_GetObjectItem(node, #var); \ 1219 if (item == NULL) \ 1220 return; \ 1221 temp = cJSON_Print(item); \ 1222 temp[strlen(temp) - 1] = '\0'; \ 1223 var = malloc(strlen(temp) + 1); \ 1224 strcpy(var, &temp[1]); \ 1225 free(temp); \ 1226 } 1227 GET_JSON_ITEM(layer_node, name) 1228 GET_JSON_ITEM(layer_node, type) 1229 GET_JSON_ITEM(layer_node, library_path) 1230 GET_JSON_ITEM(layer_node, abi_versions) 1231 GET_JSON_ITEM(layer_node, implementation_version) 1232 GET_JSON_ITEM(layer_node, description) 1233 if (is_implicit) { 1234 GET_JSON_OBJECT(layer_node, disable_environment) 1235 } 1236#undef GET_JSON_ITEM 1237#undef GET_JSON_OBJECT 1238 1239 //TODO move layer_XXXX_list capacity check into this spot so know what type it is 1240 assert((layer_instance_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_instance_list->capacity); 1241 assert((layer_device_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_device_list->capacity); 1242 1243 // add list entry 1244 struct loader_layer_properties *props; 1245 if (!strcmp(type, "DEVICE")) { 1246 layer_list = layer_device_list; 1247 props = &(layer_list->list[layer_list->count]); 1248 props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT; 1249 } 1250 if (!strcmp(type, "INSTANCE")) { 1251 layer_list = layer_instance_list; 1252 props = &(layer_list->list[layer_list->count]); 1253 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT; 1254 layer_list = layer_instance_list; 1255 } 1256 if (!strcmp(type, "GLOBAL")) { 1257 layer_list = layer_instance_list; 1258 props = &(layer_list->list[layer_list->count]); 1259 props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT; 1260 } 1261 free(type); 1262 1263 strncpy(props->info.layerName, name, sizeof(props->info.layerName)); 1264 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0'; 1265 free(name); 1266 1267 char *fullpath = malloc(2048); 1268 char *rel_base; 1269 if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) { 1270 // a filename which is assumed in the system directory 1271 char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1); 1272 strcpy(def_path, DEFAULT_VK_LAYERS_PATH); 1273 loader_get_fullpath(library_path, def_path, 2048, fullpath); 1274 } 1275 else { 1276 // a relative or absolute path 1277 char *name_copy = loader_stack_alloc(strlen(filename) + 2); 1278 size_t len; 1279 strcpy(name_copy, filename); 1280 rel_base = loader_platform_dirname(name_copy); 1281 len = strlen(rel_base); 1282 rel_base[len] = DIRECTORY_SYMBOL; 1283 rel_base[len + 1] = '\0'; 1284 loader_expand_path(library_path, rel_base, 2048, fullpath); 1285 } 1286 props->lib_info.lib_name = fullpath; 1287 free(library_path); 1288 //TODO merge the info with the versions and convert string to int 1289 props->abi_version = abi_versions; 1290 props->impl_version = implementation_version; 1291 strncpy((char *) props->info.description, description, sizeof(props->info.description)); 1292 props->info.description[sizeof(props->info.description) - 1] = '\0'; 1293 free(description); 1294 if (is_implicit) { 1295 props->disable_env_var.name = disable_environment->child->string; 1296 props->disable_env_var.value = disable_environment->child->valuestring; 1297 } 1298 layer_list->count++; 1299 1300 /** 1301 * Now get all optional items and objects and put in list: 1302 * functions 1303 * instance_extensions 1304 * device_extensions 1305 * enable_environment (implicit layers only) 1306 */ 1307#define GET_JSON_OBJECT(node, var) { \ 1308 var = cJSON_GetObjectItem(node, #var); \ 1309 } 1310#define GET_JSON_ITEM(node, var) { \ 1311 item = cJSON_GetObjectItem(node, #var); \ 1312 if (item != NULL) \ 1313 temp = cJSON_Print(item); \ 1314 temp[strlen(temp) - 1] = '\0'; \ 1315 var = malloc(strlen(temp) + 1); \ 1316 strcpy(var, &temp[1]); \ 1317 free(temp); \ 1318 } 1319 1320 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment; 1321 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version; 1322 GET_JSON_OBJECT(layer_node, functions) 1323 if (functions != NULL) { 1324 GET_JSON_ITEM(functions, vkGetInstanceProcAddr) 1325 GET_JSON_ITEM(functions, vkGetDeviceProcAddr) 1326 props->functions.str_gipa = vkGetInstanceProcAddr; 1327 props->functions.str_gdpa = vkGetDeviceProcAddr; 1328 } 1329 GET_JSON_OBJECT(layer_node, instance_extensions) 1330 if (instance_extensions != NULL) { 1331 int count = cJSON_GetArraySize(instance_extensions); 1332 for (i = 0; i < count; i++) { 1333 ext_item = cJSON_GetArrayItem(instance_extensions, i); 1334 GET_JSON_ITEM(ext_item, name) 1335 GET_JSON_ITEM(ext_item, version) 1336 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER; 1337 ext_prop.lib_name = library_path; 1338 strcpy(ext_prop.info.extName, name); 1339 //TODO convert from string to int ext_prop.info.version = version; 1340 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop); 1341 } 1342 } 1343 GET_JSON_OBJECT(layer_node, device_extensions) 1344 if (device_extensions != NULL) { 1345 int count = cJSON_GetArraySize(device_extensions); 1346 for (i = 0; i < count; i++) { 1347 ext_item = cJSON_GetArrayItem(device_extensions, i); 1348 GET_JSON_ITEM(ext_item, name); 1349 GET_JSON_ITEM(ext_item, version); 1350 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER; 1351 ext_prop.lib_name = library_path; 1352 strcpy(ext_prop.info.extName, name); 1353 //TODO convert from string to int ext_prop.info.version = version; 1354 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop); 1355 } 1356 } 1357 if (is_implicit) { 1358 GET_JSON_OBJECT(layer_node, enable_environment) 1359 props->enable_env_var.name = enable_environment->child->string; 1360 props->enable_env_var.value = enable_environment->child->valuestring; 1361 } 1362#undef GET_JSON_ITEM 1363#undef GET_JSON_OBJECT 1364 1365 // for global layers need to add them to both device and instance list 1366 if (props->type & (VK_LAYER_TYPE_GLOBAL_IMPLICIT | VK_LAYER_TYPE_GLOBAL_EXPLICIT)) { 1367 //copy into device layer list 1368 memcpy(&(layer_device_list->list[layer_device_list->count++]), props, sizeof(*props)); 1369 } 1370 1371} 1372 1373/** 1374 * Find the Vulkan library manifest files. 1375 * 1376 * This function scans the location or env_override directories/files 1377 * for a list of JSON manifest files. If env_override is non-NULL 1378 * and has a valid value. Then the location is ignored. Otherwise 1379 * location is used to look for manifest files. The location 1380 * is interpreted as Registry path on Windows and a directory path(s) 1381 * on Linux. 1382 * 1383 * \returns 1384 * A string list of manifest files to be opened in out_files param. 1385 * List has a pointer to string for each manifest filename. 1386 * When done using the list in out_files, pointers should be freed. 1387 * Location or override string lists can be either files or directories as follows: 1388 * | location | override 1389 * -------------------------------- 1390 * Win ICD | files | files 1391 * Win Layer | files | dirs 1392 * Linux ICD | dirs | files 1393 * Linux Layer| dirs | dirs 1394 */ 1395static void loader_get_manifest_files(const char *env_override, 1396 bool is_layer, 1397 const char *location, 1398 struct loader_manifest_files *out_files) 1399{ 1400 char *override = NULL; 1401 char *loc; 1402 char *file, *next_file, *name; 1403 size_t alloced_count = 64; 1404 char full_path[2048]; 1405 DIR *sysdir = NULL; 1406 bool list_is_dirs = false; 1407 struct dirent *dent; 1408 1409 out_files->count = 0; 1410 out_files->filename_list = NULL; 1411 1412 if (env_override != NULL && (override = getenv(env_override))) { 1413#if defined(__linux__) 1414 if (geteuid() != getuid()) { 1415 /* Don't allow setuid apps to use the env var: */ 1416 override = NULL; 1417 } 1418#endif 1419 } 1420 1421 if (location == NULL) { 1422 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1423 "Can't get manifest files with NULL location, env_override=%s", 1424 env_override); 1425 return; 1426 } 1427 1428#if defined(__linux__) 1429 list_is_dirs = (override == NULL || is_layer) ? true : false; 1430#else //WIN32 1431 list_is_dirs = (is_layer && override != NULL) ? true : false; 1432#endif 1433 // Make a copy of the input we are using so it is not modified 1434 // Also handle getting the location(s) from registry on Windows 1435 if (override == NULL) { 1436#if defined (_WIN32) 1437 loc = loader_get_registry_files(location); 1438 if (loc == NULL) { 1439 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files"); 1440 return; 1441 } 1442#else 1443 loc = alloca(strlen(location) + 1); 1444 if (loc == NULL) { 1445 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1446 return; 1447 } 1448 strcpy(loc, location); 1449#endif 1450 } 1451 else { 1452 loc = loader_stack_alloc(strlen(override) + 1); 1453 if (loc == NULL) { 1454 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1455 return; 1456 } 1457 strcpy(loc, override); 1458 } 1459 1460 file = loc; 1461 while (*file) { 1462 next_file = loader_get_next_path(file); 1463 if (list_is_dirs) { 1464 sysdir = opendir(file); 1465 name = NULL; 1466 if (sysdir) { 1467 dent = readdir(sysdir); 1468 if (dent == NULL) 1469 break; 1470 name = &(dent->d_name[0]); 1471 loader_get_fullpath(name, file, sizeof(full_path), full_path); 1472 name = full_path; 1473 } 1474 } 1475 else { 1476#if defined(__linux__) 1477 // only Linux has relative paths 1478 char *dir; 1479 // make a copy of location so it isn't modified 1480 dir = alloca(strlen(location) + 1); 1481 if (dir == NULL) { 1482 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1483 return; 1484 } 1485 strcpy(dir, location); 1486 1487 loader_get_fullpath(file, dir, sizeof(full_path), full_path); 1488 1489 name = full_path; 1490#else // WIN32 1491 name = file; 1492#endif 1493 } 1494 while (name) { 1495 /* Look for files ending with ".json" suffix */ 1496 uint32_t nlen = (uint32_t) strlen(name); 1497 const char *suf = name + nlen - 5; 1498 if ((nlen > 5) && !strncmp(suf, ".json", 5)) { 1499 if (out_files->count == 0) { 1500 out_files->filename_list = malloc(alloced_count * sizeof(char *)); 1501 } 1502 else if (out_files->count == alloced_count) { 1503 out_files->filename_list = realloc(out_files->filename_list, 1504 alloced_count * sizeof(char *) * 2); 1505 alloced_count *= 2; 1506 } 1507 if (out_files->filename_list == NULL) { 1508 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list"); 1509 return; 1510 } 1511 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1); 1512 if (out_files->filename_list[out_files->count] == NULL) { 1513 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1514 return; 1515 } 1516 strcpy(out_files->filename_list[out_files->count], name); 1517 out_files->count++; 1518 } else if (!list_is_dirs) { 1519 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name); 1520 } 1521 if (list_is_dirs) { 1522 dent = readdir(sysdir); 1523 if (dent == NULL) 1524 break; 1525 name = &(dent->d_name[0]); 1526 loader_get_fullpath(name, file, sizeof(full_path), full_path); 1527 name = full_path; 1528 } 1529 else { 1530 break; 1531 } 1532 } 1533 if (sysdir) 1534 closedir(sysdir); 1535 file = next_file; 1536 } 1537 return; 1538} 1539 1540/** 1541 * Try to find the Vulkan ICD driver(s). 1542 * 1543 * This function scans the default system loader path(s) or path 1544 * specified by the \c VK_ICD_FILENAMES environment variable in 1545 * order to find loadable VK ICDs manifest files. From these 1546 * manifest files it finds the ICD libraries. 1547 * 1548 * \returns 1549 * void 1550 */ 1551void loader_icd_scan(void) 1552{ 1553 char *file_str; 1554 struct loader_manifest_files manifest_files; 1555 1556 1557 // convenient place to initialize a mutex 1558 loader_platform_thread_create_mutex(&loader_lock); 1559 1560 // convenient place to initialize logging 1561 loader_debug_init(); 1562 1563 // Get a list of manifest files for ICDs 1564 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO, 1565 &manifest_files); 1566 if (manifest_files.count == 0) 1567 return; 1568 for (uint32_t i = 0; i < manifest_files.count; i++) { 1569 file_str = manifest_files.filename_list[i]; 1570 if (file_str == NULL) 1571 continue; 1572 1573 cJSON *json; 1574 json = loader_get_json(file_str); 1575 cJSON *item; 1576 item = cJSON_GetObjectItem(json, "file_format_version"); 1577 if (item == NULL) 1578 return; 1579 char *file_vers = cJSON_Print(item); 1580 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s", 1581 file_str, file_vers); 1582 if (strcmp(file_vers, "\"1.0.0\"") != 0) 1583 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors"); 1584 free(file_vers); 1585 item = cJSON_GetObjectItem(json, "ICD"); 1586 if (item != NULL) { 1587 item = cJSON_GetObjectItem(item, "library_path"); 1588 if (item != NULL) { 1589 char *icd_filename = cJSON_PrintUnformatted(item); 1590 char *icd_file = icd_filename; 1591 if (icd_filename != NULL) { 1592 char def_dir[] = DEFAULT_VK_DRIVERS_PATH; 1593 char *dir = def_dir; 1594 // strip off extra quotes 1595 if (icd_filename[strlen(icd_filename) - 1] == '"') 1596 icd_filename[strlen(icd_filename) - 1] = '\0'; 1597 if (icd_filename[0] == '"') 1598 icd_filename++; 1599#if defined(__linux__) 1600 char full_path[2048]; 1601 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path); 1602 loader_scanned_icd_add(full_path); 1603#else // WIN32 1604 loader_scanned_icd_add(icd_filename); 1605#endif 1606 free(icd_file); 1607 } 1608 } 1609 else 1610 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str); 1611 } 1612 else 1613 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str); 1614 1615 free(file_str); 1616 cJSON_Delete(json); 1617 } 1618 free(manifest_files.filename_list); 1619 1620} 1621 1622 1623void loader_layer_scan(void) 1624{ 1625 char *file_str; 1626 struct loader_manifest_files manifest_files; 1627 cJSON *json; 1628 uint32_t i; 1629 1630 // Get a list of manifest files for layers 1631 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO, 1632 &manifest_files); 1633 if (manifest_files.count == 0) 1634 return; 1635 1636#if 0 1637 /** 1638 * We need a list of the layer libraries, not just a list of 1639 * the layer properties (a layer library could expose more than 1640 * one layer property). This list of scanned layers would be 1641 * used to check for global and physicaldevice layer properties. 1642 */ 1643 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) { 1644 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1645 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__); 1646 return; 1647 } 1648#endif 1649 1650 // TODO use global_layer add and delete functions instead 1651 if (loader.scanned_instance_layers.capacity == 0) { 1652 loader.scanned_instance_layers.list = malloc(sizeof(struct loader_layer_properties) * 64); 1653 if (loader.scanned_instance_layers.list == NULL) { 1654 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list"); 1655 return; 1656 } 1657 memset(loader.scanned_instance_layers.list, 0, sizeof(struct loader_layer_properties) * 64); 1658 loader.scanned_instance_layers.capacity = sizeof(struct loader_layer_properties) * 64; 1659 } 1660 else { 1661 /* cleanup any previously scanned libraries */ 1662 //TODO make sure everything is cleaned up properly 1663 for (i = 0; i < loader.scanned_instance_layers.count; i++) { 1664 if (loader.scanned_instance_layers.list[i].lib_info.lib_name != NULL) 1665 free(loader.scanned_instance_layers.list[i].lib_info.lib_name); 1666 loader_destroy_ext_list(&loader.scanned_instance_layers.list[i].instance_extension_list); 1667 loader_destroy_ext_list(&loader.scanned_instance_layers.list[i].device_extension_list); 1668 loader.scanned_instance_layers.list[i].lib_info.lib_name = NULL; 1669 } 1670 loader.scanned_instance_layers.count = 0; 1671 } 1672 if (loader.scanned_device_layers.capacity == 0) { 1673 loader.scanned_device_layers.list = malloc(sizeof(struct loader_layer_properties) * 64); 1674 if (loader.scanned_device_layers.list == NULL) { 1675 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list"); 1676 return; 1677 } 1678 memset(loader.scanned_device_layers.list, 0, sizeof(struct loader_layer_properties) * 64); 1679 loader.scanned_device_layers.capacity = sizeof(struct loader_layer_properties) * 64; 1680 } 1681 else { 1682 /* cleanup any previously scanned libraries */ 1683 //TODO make sure everything is cleaned up properly 1684 for (i = 0; i < loader.scanned_device_layers.count; i++) { 1685 if (loader.scanned_device_layers.list[i].lib_info.lib_name != NULL) 1686 free(loader.scanned_device_layers.list[i].lib_info.lib_name); 1687 loader_destroy_ext_list(&loader.scanned_device_layers.list[i].instance_extension_list); 1688 loader_destroy_ext_list(&loader.scanned_device_layers.list[i].device_extension_list); 1689 loader.scanned_device_layers.list[i].lib_info.lib_name = NULL; 1690 } 1691 loader.scanned_device_layers.count = 0; 1692 } 1693 1694 1695 for (i = 0; i < manifest_files.count; i++) { 1696 file_str = manifest_files.filename_list[i]; 1697 if (file_str == NULL) 1698 continue; 1699 1700 // parse file into JSON struct 1701 json = loader_get_json(file_str); 1702 if (!json) { 1703 continue; 1704 } 1705 // ensure enough room to add an entry 1706 if ((loader.scanned_instance_layers.count + 1) * sizeof (struct loader_layer_properties) 1707 > loader.scanned_instance_layers.capacity) { 1708 loader.scanned_instance_layers.list = realloc(loader.scanned_instance_layers.list, 1709 loader.scanned_instance_layers.capacity * 2); 1710 if (loader.scanned_instance_layers.list == NULL) { 1711 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1712 "realloc failed for scanned layers"); 1713 break; 1714 } 1715 loader.scanned_instance_layers.capacity *= 2; 1716 } 1717 // ensure enough room to add an entry 1718 if ((loader.scanned_device_layers.count + 1) * sizeof (struct loader_layer_properties) 1719 > loader.scanned_device_layers.capacity) { 1720 loader.scanned_device_layers.list = realloc(loader.scanned_device_layers.list, 1721 loader.scanned_device_layers.capacity * 2); 1722 if (loader.scanned_device_layers.list == NULL) { 1723 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1724 "realloc failed for scanned layers"); 1725 break; 1726 } 1727 loader.scanned_device_layers.capacity *= 2; 1728 } 1729 //TODO pass in implicit versus explicit bool 1730 //TODO error if device layers expose instance_extensions 1731 //TODO error if instance layers expose device extensions 1732 loader_add_layer_properties(&loader.scanned_instance_layers, 1733 &loader.scanned_device_layers, 1734 json, 1735 false, 1736 file_str); 1737 1738 1739 free(file_str); 1740 cJSON_Delete(json); 1741 } 1742 free(manifest_files.filename_list); 1743 1744} 1745 1746static PFN_vkVoidFunction VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName) 1747{ 1748 // inst is not wrapped 1749 if (inst == VK_NULL_HANDLE) { 1750 return NULL; 1751 } 1752 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst; 1753 void *addr; 1754 1755 if (!strcmp(pName, "vkGetInstanceProcAddr")) 1756 return (void *) loader_gpa_instance_internal; 1757 1758 if (disp_table == NULL) 1759 return NULL; 1760 1761 addr = loader_lookup_instance_dispatch_table(disp_table, pName); 1762 if (addr) { 1763 return addr; 1764 } 1765 1766 if (disp_table->GetInstanceProcAddr == NULL) { 1767 return NULL; 1768 } 1769 return disp_table->GetInstanceProcAddr(inst, pName); 1770} 1771 1772struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index) 1773{ 1774 1775 *gpu_index = 0; 1776 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 1777 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 1778 for (uint32_t i = 0; i < icd->gpu_count; i++) 1779 if (icd->gpus[i] == gpu) { 1780 *gpu_index = i; 1781 return icd; 1782 } 1783 } 1784 } 1785 return NULL; 1786} 1787 1788static loader_platform_dl_handle loader_add_layer_lib( 1789 const char *chain_type, 1790 struct loader_layer_properties *layer_prop) 1791{ 1792 struct loader_lib_info *new_layer_lib_list, *my_lib; 1793 1794 /* 1795 * TODO: We can now track this information in the 1796 * scanned_layer_libraries list. 1797 */ 1798 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) { 1799 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) { 1800 /* Have already loaded this library, just increment ref count */ 1801 loader.loaded_layer_lib_list[i].ref_count++; 1802 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1803 "%s Chain: Increment layer reference count for layer library %s", 1804 chain_type, layer_prop->lib_info.lib_name); 1805 return loader.loaded_layer_lib_list[i].lib_handle; 1806 } 1807 } 1808 1809 /* Haven't seen this library so load it */ 1810 new_layer_lib_list = realloc(loader.loaded_layer_lib_list, 1811 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info)); 1812 if (!new_layer_lib_list) { 1813 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed"); 1814 return NULL; 1815 } 1816 1817 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count]; 1818 1819 /* NOTE: We require that the layer property be immutable */ 1820 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name; 1821 my_lib->ref_count = 0; 1822 my_lib->lib_handle = NULL; 1823 1824 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) { 1825 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1826 loader_platform_open_library_error(my_lib->lib_name)); 1827 return NULL; 1828 } else { 1829 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1830 "Chain: %s: Loading layer library %s", 1831 chain_type, layer_prop->lib_info.lib_name); 1832 } 1833 loader.loaded_layer_lib_count++; 1834 loader.loaded_layer_lib_list = new_layer_lib_list; 1835 my_lib->ref_count++; 1836 1837 return my_lib->lib_handle; 1838} 1839 1840static void loader_remove_layer_lib( 1841 struct loader_instance *inst, 1842 struct loader_layer_properties *layer_prop) 1843{ 1844 uint32_t idx; 1845 struct loader_lib_info *new_layer_lib_list, *my_lib = NULL; 1846 1847 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) { 1848 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) { 1849 /* found matching library */ 1850 idx = i; 1851 my_lib = &loader.loaded_layer_lib_list[i]; 1852 break; 1853 } 1854 } 1855 1856 if (my_lib) { 1857 my_lib->ref_count--; 1858 if (my_lib->ref_count > 0) { 1859 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1860 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name); 1861 return; 1862 } 1863 } 1864 loader_platform_close_library(my_lib->lib_handle); 1865 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1866 "Unloading layer library %s", layer_prop->lib_info.lib_name); 1867 1868 /* Need to remove unused library from list */ 1869 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info)); 1870 if (!new_layer_lib_list) { 1871 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed"); 1872 return; 1873 } 1874 1875 if (idx > 0) { 1876 /* Copy records before idx */ 1877 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0], 1878 sizeof(struct loader_lib_info) * idx); 1879 } 1880 if (idx < (loader.loaded_layer_lib_count - 1)) { 1881 /* Copy records after idx */ 1882 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1], 1883 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1)); 1884 } 1885 1886 free(loader.loaded_layer_lib_list); 1887 loader.loaded_layer_lib_count--; 1888 loader.loaded_layer_lib_list = new_layer_lib_list; 1889} 1890 1891 1892/** 1893 * Go through the search_list and find any layers which match type. If layer 1894 * type match is found in then add it to ext_list. 1895 */ 1896//TODO need to handle implict layer enable env var and disable env var 1897static void loader_add_layer_implicit( 1898 const enum layer_type type, 1899 struct loader_layer_list *list, 1900 struct loader_layer_list *search_list) 1901{ 1902 uint32_t i; 1903 for (i = 0; i < search_list->count; i++) { 1904 const struct loader_layer_properties *prop = &search_list->list[i]; 1905 if (prop->type & type) { 1906 /* Found an layer with the same type, add to layer_list */ 1907 loader_add_to_layer_list(list, 1, prop); 1908 } 1909 } 1910 1911} 1912 1913/** 1914 * Get the layer name(s) from the env_name environment variable. If layer 1915 * is found in search_list then add it to layer_list. But only add it to 1916 * layer_list if type matches. 1917 */ 1918static void loader_add_layer_env( 1919 const enum layer_type type, 1920 const char *env_name, 1921 struct loader_layer_list *layer_list, 1922 const struct loader_layer_list *search_list) 1923{ 1924 char *layerEnv; 1925 char *next, *name; 1926 1927 layerEnv = getenv(env_name); 1928 if (layerEnv == NULL) { 1929 return; 1930 } 1931 name = loader_stack_alloc(strlen(layerEnv) + 1); 1932 if (name == NULL) { 1933 return; 1934 } 1935 strcpy(name, layerEnv); 1936 1937 while (name && *name ) { 1938 next = loader_get_next_path(name); 1939 loader_find_layer_name_add_list(name, type, search_list, layer_list); 1940 name = next; 1941 } 1942 1943 return; 1944} 1945 1946void loader_deactivate_instance_layers(struct loader_instance *instance) 1947{ 1948 if (!instance->activated_layer_list.count) { 1949 return; 1950 } 1951 1952 /* Create instance chain of enabled layers */ 1953 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) { 1954 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i]; 1955 1956 loader_remove_layer_lib(instance, layer_prop); 1957 } 1958 loader_destroy_layer_list(&instance->activated_layer_list); 1959} 1960 1961VkResult loader_enable_instance_layers( 1962 struct loader_instance *inst, 1963 const VkInstanceCreateInfo *pCreateInfo) 1964{ 1965 VkResult err; 1966 1967 if (inst == NULL) 1968 return VK_ERROR_UNKNOWN; 1969 1970 if (!loader_init_layer_list(&inst->activated_layer_list)) { 1971 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list"); 1972 return VK_ERROR_OUT_OF_HOST_MEMORY; 1973 } 1974 1975 /* Add any implicit layers first */ 1976 loader_add_layer_implicit( 1977 VK_LAYER_TYPE_INSTANCE_IMPLICIT, 1978 &inst->activated_layer_list, 1979 &loader.scanned_instance_layers); 1980 1981 /* Add any layers specified via environment variable next */ 1982 loader_add_layer_env( 1983 VK_LAYER_TYPE_INSTANCE_EXPLICIT, 1984 "VK_INSTANCE_LAYERS", 1985 &inst->activated_layer_list, 1986 &loader.scanned_instance_layers); 1987 1988 /* Add layers specified by the application */ 1989 err = loader_add_layer_names_to_list( 1990 &inst->activated_layer_list, 1991 pCreateInfo->layerCount, 1992 pCreateInfo->ppEnabledLayerNames, 1993 &loader.scanned_instance_layers); 1994 1995 return err; 1996} 1997 1998uint32_t loader_activate_instance_layers(struct loader_instance *inst) 1999{ 2000 uint32_t layer_idx; 2001 VkBaseLayerObject *wrappedInstance; 2002 2003 if (inst == NULL) { 2004 return 0; 2005 } 2006 2007 // NOTE inst is unwrapped at this point in time 2008 void* baseObj = (void*) inst; 2009 void* nextObj = (void*) inst; 2010 VkBaseLayerObject *nextInstObj; 2011 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal; 2012 2013 if (!inst->activated_layer_list.count) { 2014 return 0; 2015 } 2016 2017 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject) 2018 * inst->activated_layer_list.count); 2019 if (!wrappedInstance) { 2020 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer"); 2021 return 0; 2022 } 2023 2024 /* Create instance chain of enabled layers */ 2025 layer_idx = inst->activated_layer_list.count - 1; 2026 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) { 2027 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i]; 2028 loader_platform_dl_handle lib_handle; 2029 2030 /* 2031 * Note: An extension's Get*ProcAddr should not return a function pointer for 2032 * any extension entry points until the extension has been enabled. 2033 * To do this requires a different behavior from Get*ProcAddr functions implemented 2034 * in layers. 2035 * The very first call to a layer will be it's Get*ProcAddr function requesting 2036 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table 2037 * with the wrapped object given (either Instance or Device) and return the layer's 2038 * Get*ProcAddr function. The layer should also use this opportunity to record the 2039 * baseObject so that it can find the correct local dispatch table on future calls. 2040 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice 2041 * will not use a wrapped object and must look up their local dispatch table from 2042 * the given baseObject. 2043 */ 2044 nextInstObj = (wrappedInstance + layer_idx); 2045 nextInstObj->pGPA = (PFN_vkGPA) nextGPA; 2046 nextInstObj->baseObject = baseObj; 2047 nextInstObj->nextObject = nextObj; 2048 nextObj = (void*) nextInstObj; 2049 2050 char funcStr[256]; 2051 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName); 2052 lib_handle = loader_add_layer_lib("instance", layer_prop); 2053 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 2054 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr"); 2055 if (!nextGPA) { 2056 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name); 2057 2058 /* TODO: Should we return nextObj, nextGPA to previous? */ 2059 continue; 2060 } 2061 2062 loader_log(VK_DBG_REPORT_INFO_BIT, 0, 2063 "Insert instance layer %s (%s)", 2064 layer_prop->info.layerName, 2065 layer_prop->lib_info.lib_name); 2066 2067 layer_idx--; 2068 } 2069 2070 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj); 2071 2072 return inst->activated_layer_list.count; 2073} 2074 2075void loader_activate_instance_layer_extensions(struct loader_instance *inst) 2076{ 2077 2078 loader_init_instance_extension_dispatch_table(inst->disp, 2079 inst->disp->GetInstanceProcAddr, 2080 (VkInstance) inst); 2081} 2082 2083static VkResult loader_enable_device_layers( 2084 struct loader_icd *icd, 2085 struct loader_device *dev, 2086 const VkDeviceCreateInfo *pCreateInfo) 2087{ 2088 VkResult err; 2089 2090 if (dev == NULL) 2091 return VK_ERROR_UNKNOWN; 2092 2093 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) { 2094 loader_init_layer_list(&dev->activated_layer_list); 2095 } 2096 2097 if (dev->activated_layer_list.list == NULL) { 2098 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list"); 2099 return VK_ERROR_OUT_OF_HOST_MEMORY; 2100 } 2101 2102 /* Add any implicit layers first */ 2103 loader_add_layer_implicit( 2104 VK_LAYER_TYPE_DEVICE_IMPLICIT, 2105 &dev->activated_layer_list, 2106 &loader.scanned_device_layers); 2107 2108 /* Add any layers specified via environment variable next */ 2109 loader_add_layer_env( 2110 VK_LAYER_TYPE_DEVICE_EXPLICIT, 2111 "VK_DEVICE_LAYERS", 2112 &dev->activated_layer_list, 2113 &loader.scanned_device_layers); 2114 2115 /* Add layers specified by the application */ 2116 err = loader_add_layer_names_to_list( 2117 &dev->activated_layer_list, 2118 pCreateInfo->layerCount, 2119 pCreateInfo->ppEnabledLayerNames, 2120 &loader.scanned_device_layers); 2121 2122 return err; 2123} 2124 2125/* 2126 * This function terminates the device chain fro CreateDevice. 2127 * CreateDevice is a special case and so the loader call's 2128 * the ICD's CreateDevice before creating the chain. Since 2129 * we can't call CreateDevice twice we must terminate the 2130 * device chain with something else. 2131 */ 2132static VkResult VKAPI scratch_vkCreateDevice( 2133 VkPhysicalDevice gpu, 2134 const VkDeviceCreateInfo *pCreateInfo, 2135 VkDevice *pDevice) 2136{ 2137 return VK_SUCCESS; 2138} 2139 2140static PFN_vkVoidFunction VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name) 2141{ 2142 if (!strcmp(name, "vkGetDeviceProcAddr")) 2143 return (PFN_vkVoidFunction) loader_GetDeviceChainProcAddr; 2144 if (!strcmp(name, "vkCreateDevice")) 2145 return (PFN_vkVoidFunction) scratch_vkCreateDevice; 2146 2147 struct loader_device *found_dev; 2148 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev); 2149 return icd->GetDeviceProcAddr(device, name); 2150} 2151 2152static uint32_t loader_activate_device_layers( 2153 struct loader_icd *icd, 2154 struct loader_device *dev, 2155 VkDevice device) 2156{ 2157 if (!icd) 2158 return 0; 2159 2160 if (!dev) { 2161 return 0; 2162 } 2163 2164 /* activate any layer libraries */ 2165 void* nextObj = (void*) device; 2166 void* baseObj = nextObj; 2167 VkBaseLayerObject *nextGpuObj; 2168 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr; 2169 VkBaseLayerObject *wrappedGpus; 2170 2171 if (!dev->activated_layer_list.count) 2172 return 0; 2173 2174 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count); 2175 if (!wrappedGpus) { 2176 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer"); 2177 return 0; 2178 } 2179 2180 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) { 2181 2182 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i]; 2183 loader_platform_dl_handle lib_handle; 2184 2185 nextGpuObj = (wrappedGpus + i); 2186 nextGpuObj->pGPA = (PFN_vkGPA)nextGPA; 2187 nextGpuObj->baseObject = baseObj; 2188 nextGpuObj->nextObject = nextObj; 2189 nextObj = (void*) nextGpuObj; 2190 2191 char funcStr[256]; 2192 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName); 2193 lib_handle = loader_add_layer_lib("device", layer_prop); 2194 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 2195 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr"); 2196 if (!nextGPA) { 2197 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName); 2198 continue; 2199 } 2200 2201 loader_log(VK_DBG_REPORT_INFO_BIT, 0, 2202 "Insert device layer library %s (%s)", 2203 layer_prop->info.layerName, 2204 layer_prop->lib_info.lib_name); 2205 2206 } 2207 2208 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA, 2209 (VkDevice) nextObj, (VkDevice) baseObj); 2210 free(wrappedGpus); 2211 2212 return dev->activated_layer_list.count; 2213} 2214 2215VkResult loader_validate_layers( 2216 const uint32_t layer_count, 2217 const char * const *ppEnabledLayerNames, 2218 struct loader_layer_list *list) 2219{ 2220 struct loader_layer_properties *prop; 2221 2222 for (uint32_t i = 0; i < layer_count; i++) { 2223 prop = get_layer_property(ppEnabledLayerNames[i], 2224 list); 2225 if (!prop) { 2226 return VK_ERROR_INVALID_LAYER; 2227 } 2228 } 2229 2230 return VK_SUCCESS; 2231} 2232 2233VkResult loader_validate_instance_extensions( 2234 const VkInstanceCreateInfo *pCreateInfo) 2235{ 2236 struct loader_extension_property *extension_prop; 2237 struct loader_layer_properties *layer_prop; 2238 2239 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2240 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], 2241 &loader.global_extensions); 2242 2243 if (extension_prop) { 2244 continue; 2245 } 2246 2247 extension_prop = NULL; 2248 2249 /* Not in global list, search layer extension lists */ 2250 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) { 2251 layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i], 2252 &loader.scanned_instance_layers); 2253 2254 if (!layer_prop) { 2255 /* Should NOT get here, loader_validate_layers 2256 * should have already filtered this case out. 2257 */ 2258 continue; 2259 } 2260 2261 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], 2262 &layer_prop->instance_extension_list); 2263 if (extension_prop) { 2264 /* Found the extension in one of the layers enabled by the app. */ 2265 break; 2266 } 2267 } 2268 2269 if (!extension_prop) { 2270 /* Didn't find extension name in any of the global layers, error out */ 2271 return VK_ERROR_INVALID_EXTENSION; 2272 } 2273 } 2274 return VK_SUCCESS; 2275} 2276 2277VkResult loader_validate_device_extensions( 2278 struct loader_icd *icd, 2279 uint32_t gpu_index, 2280 const VkDeviceCreateInfo *pCreateInfo) 2281{ 2282 struct loader_extension_property *extension_prop; 2283 struct loader_layer_properties *layer_prop; 2284 2285 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2286 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i]; 2287 extension_prop = get_extension_property(extension_name, 2288 &icd->device_extension_cache[gpu_index]); 2289 2290 if (extension_prop) { 2291 continue; 2292 } 2293 2294 /* Not in global list, search layer extension lists */ 2295 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) { 2296 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j]; 2297 layer_prop = get_layer_property(layer_name, 2298 &loader.scanned_device_layers); 2299 2300 if (!layer_prop) { 2301 /* Should NOT get here, loader_validate_instance_layers 2302 * should have already filtered this case out. 2303 */ 2304 continue; 2305 } 2306 2307 extension_prop = get_extension_property(extension_name, 2308 &layer_prop->device_extension_list); 2309 if (extension_prop) { 2310 /* Found the extension in one of the layers enabled by the app. */ 2311 break; 2312 } 2313 } 2314 2315 if (!extension_prop) { 2316 /* Didn't find extension name in any of the device layers, error out */ 2317 return VK_ERROR_INVALID_EXTENSION; 2318 } 2319 } 2320 return VK_SUCCESS; 2321} 2322 2323VkResult VKAPI loader_CreateInstance( 2324 const VkInstanceCreateInfo* pCreateInfo, 2325 VkInstance* pInstance) 2326{ 2327 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance; 2328 struct loader_scanned_icds *scanned_icds; 2329 struct loader_icd *icd; 2330 struct loader_extension_property *prop; 2331 char **filtered_extension_names = NULL; 2332 VkInstanceCreateInfo icd_create_info; 2333 VkResult res = VK_SUCCESS; 2334 bool success; 2335 2336 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 2337 icd_create_info.layerCount = 0; 2338 icd_create_info.ppEnabledLayerNames = NULL; 2339 icd_create_info.pAllocCb = pCreateInfo->pAllocCb; 2340 icd_create_info.pAppInfo = pCreateInfo->pAppInfo; 2341 icd_create_info.pNext = pCreateInfo->pNext; 2342 2343 /* 2344 * NOTE: Need to filter the extensions to only those 2345 * supported by the ICD. 2346 * No ICD will advertise support for layers. An ICD 2347 * library could support a layer, but it would be 2348 * independent of the actual ICD, just in the same library. 2349 */ 2350 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *)); 2351 if (!filtered_extension_names) { 2352 return VK_ERROR_OUT_OF_HOST_MEMORY; 2353 } 2354 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names; 2355 2356 scanned_icds = loader.scanned_icd_list; 2357 while (scanned_icds) { 2358 icd = loader_icd_add(ptr_instance, scanned_icds); 2359 if (icd) { 2360 icd_create_info.extensionCount = 0; 2361 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2362 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], 2363 &scanned_icds->global_extension_list); 2364 if (prop) { 2365 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i]; 2366 icd_create_info.extensionCount++; 2367 } 2368 } 2369 2370 res = scanned_icds->CreateInstance(&icd_create_info, 2371 &(icd->instance)); 2372 success = loader_icd_init_entrys( 2373 icd, 2374 icd->instance, 2375 scanned_icds->GetInstanceProcAddr); 2376 2377 if (res != VK_SUCCESS || !success) 2378 { 2379 ptr_instance->icds = ptr_instance->icds->next; 2380 loader_icd_destroy(ptr_instance, icd); 2381 icd->instance = VK_NULL_HANDLE; 2382 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 2383 "ICD ignored: failed to CreateInstance and find entrypoints with ICD"); 2384 } 2385 } 2386 scanned_icds = scanned_icds->next; 2387 } 2388 2389 /* 2390 * If no ICDs were added to instance list and res is unchanged 2391 * from it's initial value, the loader was unable to find 2392 * a suitable ICD. 2393 */ 2394 if (ptr_instance->icds == NULL) { 2395 if (res == VK_SUCCESS) { 2396 return VK_ERROR_INCOMPATIBLE_DRIVER; 2397 } else { 2398 return res; 2399 } 2400 } 2401 2402 return VK_SUCCESS; 2403} 2404 2405VkResult VKAPI loader_DestroyInstance( 2406 VkInstance instance) 2407{ 2408 struct loader_instance *ptr_instance = loader_instance(instance); 2409 struct loader_icd *icds = ptr_instance->icds; 2410 struct loader_icd *next_icd; 2411 VkResult res; 2412 2413 // Remove this instance from the list of instances: 2414 struct loader_instance *prev = NULL; 2415 struct loader_instance *next = loader.instances; 2416 while (next != NULL) { 2417 if (next == ptr_instance) { 2418 // Remove this instance from the list: 2419 if (prev) 2420 prev->next = next->next; 2421 else 2422 loader.instances = next->next; 2423 break; 2424 } 2425 prev = next; 2426 next = next->next; 2427 } 2428 if (next == NULL) { 2429 // This must be an invalid instance handle or empty list 2430 return VK_ERROR_INVALID_HANDLE; 2431 } 2432 2433 while (icds) { 2434 if (icds->instance) { 2435 res = icds->DestroyInstance(icds->instance); 2436 if (res != VK_SUCCESS) 2437 loader_log(VK_DBG_REPORT_WARN_BIT, 0, 2438 "ICD ignored: failed to DestroyInstance on device"); 2439 } 2440 next_icd = icds->next; 2441 icds->instance = VK_NULL_HANDLE; 2442 loader_icd_destroy(ptr_instance, icds); 2443 2444 icds = next_icd; 2445 } 2446 2447 2448 return VK_SUCCESS; 2449} 2450 2451VkResult loader_init_physical_device_info( 2452 struct loader_instance *ptr_instance) 2453{ 2454 struct loader_icd *icd; 2455 uint32_t n, count = 0; 2456 VkResult res = VK_ERROR_UNKNOWN; 2457 2458 icd = ptr_instance->icds; 2459 while (icd) { 2460 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL); 2461 if (res != VK_SUCCESS) 2462 return res; 2463 icd->gpu_count = n; 2464 count += n; 2465 icd = icd->next; 2466 } 2467 2468 ptr_instance->total_gpu_count = count; 2469 2470 icd = ptr_instance->icds; 2471 while (icd) { 2472 2473 n = icd->gpu_count; 2474 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice)); 2475 if (!icd->gpus) { 2476 /* TODO: Add cleanup code here */ 2477 return VK_ERROR_OUT_OF_HOST_MEMORY; 2478 } 2479 res = icd->EnumeratePhysicalDevices( 2480 icd->instance, 2481 &n, 2482 icd->gpus); 2483 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) { 2484 2485 for (unsigned int i = 0; i < n; i++) { 2486 2487 loader_init_dispatch(icd->gpus[i], ptr_instance->disp); 2488 2489 if (!loader_init_ext_list(&icd->device_extension_cache[i])) { 2490 /* TODO: Add cleanup code here */ 2491 res = VK_ERROR_OUT_OF_HOST_MEMORY; 2492 } 2493 if (res == VK_SUCCESS) { 2494 2495 loader_add_physical_device_extensions( 2496 icd->GetPhysicalDeviceExtensionProperties, 2497 icd->gpus[0], 2498 VK_EXTENSION_ORIGIN_ICD, 2499 icd->scanned_icds->lib_name, 2500 &icd->device_extension_cache[i]); 2501 2502 } 2503 2504 if (res != VK_SUCCESS) { 2505 /* clean up any extension lists previously created before this request failed */ 2506 for (uint32_t j = 0; j < i; j++) { 2507 loader_destroy_ext_list(&icd->device_extension_cache[i]); 2508 } 2509 2510 return res; 2511 } 2512 } 2513 2514 count += n; 2515 } 2516 2517 icd = icd->next; 2518 } 2519 2520 return VK_SUCCESS; 2521} 2522 2523VkResult VKAPI loader_EnumeratePhysicalDevices( 2524 VkInstance instance, 2525 uint32_t* pPhysicalDeviceCount, 2526 VkPhysicalDevice* pPhysicalDevices) 2527{ 2528 uint32_t index = 0; 2529 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 2530 struct loader_icd *icd = ptr_instance->icds; 2531 2532 if (ptr_instance->total_gpu_count == 0) { 2533 loader_init_physical_device_info(ptr_instance); 2534 } 2535 2536 *pPhysicalDeviceCount = ptr_instance->total_gpu_count; 2537 if (!pPhysicalDevices) { 2538 return VK_SUCCESS; 2539 } 2540 2541 while (icd) { 2542 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount); 2543 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice)); 2544 index += icd->gpu_count; 2545 icd = icd->next; 2546 } 2547 2548 return VK_SUCCESS; 2549} 2550 2551VkResult VKAPI loader_GetPhysicalDeviceProperties( 2552 VkPhysicalDevice gpu, 2553 VkPhysicalDeviceProperties* pProperties) 2554{ 2555 uint32_t gpu_index; 2556 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2557 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2558 2559 if (icd->GetPhysicalDeviceProperties) 2560 res = icd->GetPhysicalDeviceProperties(gpu, pProperties); 2561 2562 return res; 2563} 2564 2565VkResult VKAPI loader_GetPhysicalDeviceQueueCount( 2566 VkPhysicalDevice gpu, 2567 uint32_t* pCount) 2568{ 2569 uint32_t gpu_index; 2570 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2571 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2572 2573 if (icd->GetPhysicalDeviceQueueCount) 2574 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount); 2575 2576 return res; 2577} 2578 2579VkResult VKAPI loader_GetPhysicalDeviceQueueProperties ( 2580 VkPhysicalDevice gpu, 2581 uint32_t count, 2582 VkPhysicalDeviceQueueProperties * pProperties) 2583{ 2584 uint32_t gpu_index; 2585 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2586 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2587 2588 if (icd->GetPhysicalDeviceQueueProperties) 2589 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties); 2590 2591 return res; 2592} 2593 2594VkResult VKAPI loader_GetPhysicalDeviceMemoryProperties ( 2595 VkPhysicalDevice gpu, 2596 VkPhysicalDeviceMemoryProperties* pProperties) 2597{ 2598 uint32_t gpu_index; 2599 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2600 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2601 2602 if (icd->GetPhysicalDeviceMemoryProperties) 2603 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties); 2604 2605 return res; 2606} 2607 2608VkResult VKAPI loader_GetPhysicalDeviceFeatures( 2609 VkPhysicalDevice physicalDevice, 2610 VkPhysicalDeviceFeatures* pFeatures) 2611{ 2612 uint32_t gpu_index; 2613 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2614 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2615 2616 if (icd->GetPhysicalDeviceFeatures) 2617 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures); 2618 2619 return res; 2620} 2621 2622VkResult VKAPI loader_GetPhysicalDeviceFormatProperties( 2623 VkPhysicalDevice physicalDevice, 2624 VkFormat format, 2625 VkFormatProperties* pFormatInfo) 2626{ 2627 uint32_t gpu_index; 2628 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2629 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2630 2631 if (icd->GetPhysicalDeviceFormatProperties) 2632 res = icd->GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatInfo); 2633 2634 return res; 2635} 2636 2637VkResult VKAPI loader_GetPhysicalDeviceImageFormatProperties( 2638 VkPhysicalDevice physicalDevice, 2639 VkFormat format, 2640 VkImageType type, 2641 VkImageTiling tiling, 2642 VkImageUsageFlags usage, 2643 VkImageFormatProperties* pImageFormatProperties) 2644{ 2645 uint32_t gpu_index; 2646 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2647 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2648 2649 if (icd->GetPhysicalDeviceImageFormatProperties) 2650 res = icd->GetPhysicalDeviceImageFormatProperties(physicalDevice, format, 2651 type, tiling, usage, pImageFormatProperties); 2652 2653 return res; 2654} 2655 2656VkResult VKAPI loader_GetPhysicalDeviceLimits( 2657 VkPhysicalDevice physicalDevice, 2658 VkPhysicalDeviceLimits* pLimits) 2659{ 2660 uint32_t gpu_index; 2661 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2662 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2663 2664 if (icd->GetPhysicalDeviceLimits) 2665 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits); 2666 2667 return res; 2668} 2669 2670VkResult VKAPI loader_GetPhysicalDeviceSparseImageFormatProperties( 2671 VkPhysicalDevice physicalDevice, 2672 VkFormat format, 2673 VkImageType type, 2674 uint32_t samples, 2675 VkImageUsageFlags usage, 2676 VkImageTiling tiling, 2677 uint32_t* pNumProperties, 2678 VkSparseImageFormatProperties* pProperties) 2679{ 2680 uint32_t gpu_index; 2681 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2682 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2683 2684 if (icd->GetPhysicalDeviceSparseImageFormatProperties) 2685 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties); 2686 2687 return res; 2688} 2689 2690VkResult VKAPI loader_CreateDevice( 2691 VkPhysicalDevice gpu, 2692 const VkDeviceCreateInfo* pCreateInfo, 2693 VkDevice* pDevice) 2694{ 2695 uint32_t gpu_index; 2696 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2697 struct loader_device *dev; 2698 VkDeviceCreateInfo device_create_info; 2699 char **filtered_extension_names = NULL; 2700 VkResult res; 2701 2702 if (!icd->CreateDevice) { 2703 return VK_ERROR_INITIALIZATION_FAILED; 2704 } 2705 2706 res = loader_validate_layers(pCreateInfo->layerCount, 2707 pCreateInfo->ppEnabledLayerNames, 2708 &loader.scanned_device_layers); 2709 if (res != VK_SUCCESS) { 2710 return res; 2711 } 2712 2713 res = loader_validate_device_extensions(icd, gpu_index, pCreateInfo); 2714 if (res != VK_SUCCESS) { 2715 return res; 2716 } 2717 2718 /* 2719 * NOTE: Need to filter the extensions to only those 2720 * supported by the ICD. 2721 * No ICD will advertise support for layers. An ICD 2722 * library could support a layer, but it would be 2723 * independent of the actual ICD, just in the same library. 2724 */ 2725 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *)); 2726 if (!filtered_extension_names) { 2727 return VK_ERROR_OUT_OF_HOST_MEMORY; 2728 } 2729 2730 /* Copy user's data */ 2731 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo)); 2732 2733 /* ICD's do not use layers */ 2734 device_create_info.layerCount = 0; 2735 device_create_info.ppEnabledLayerNames = NULL; 2736 2737 device_create_info.extensionCount = 0; 2738 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names; 2739 2740 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2741 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i]; 2742 struct loader_extension_property *prop = get_extension_property(extension_name, 2743 &icd->device_extension_cache[gpu_index]); 2744 if (prop) { 2745 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name; 2746 device_create_info.extensionCount++; 2747 } 2748 } 2749 2750 res = icd->CreateDevice(gpu, pCreateInfo, pDevice); 2751 if (res != VK_SUCCESS) { 2752 return res; 2753 } 2754 2755 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list); 2756 if (dev == NULL) { 2757 return VK_ERROR_OUT_OF_HOST_MEMORY; 2758 } 2759 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr; 2760 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr, 2761 *pDevice, *pDevice); 2762 2763 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice; 2764 loader_init_dispatch(*pDevice, &dev->loader_dispatch); 2765 2766 /* 2767 * Put together the complete list of extensions to enable 2768 * This includes extensions requested via environment variables. 2769 */ 2770 loader_enable_device_layers(icd, dev, pCreateInfo); 2771 2772 /* 2773 * Load the libraries and build the device chain 2774 * terminating with the selected device. 2775 */ 2776 loader_activate_device_layers(icd, dev, *pDevice); 2777 2778 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice); 2779 2780 dev->loader_dispatch.CreateDevice = icd->CreateDevice; 2781 2782 return res; 2783} 2784 2785static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName) 2786{ 2787 if (instance == VK_NULL_HANDLE) 2788 return NULL; 2789 2790 void *addr; 2791 /* get entrypoint addresses that are global (in the loader)*/ 2792 addr = globalGetProcAddr(pName); 2793 if (addr) 2794 return addr; 2795 2796 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 2797 2798 /* return any extension global entrypoints */ 2799 addr = debug_report_instance_gpa(ptr_instance, pName); 2800 if (addr) { 2801 return addr; 2802 } 2803 2804 addr = wsi_swapchain_GetInstanceProcAddr(ptr_instance, pName); 2805 if (addr) { 2806 return addr; 2807 } 2808 2809 /* return the instance dispatch table entrypoint for extensions */ 2810 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance; 2811 if (disp_table == NULL) 2812 return NULL; 2813 2814 addr = loader_lookup_instance_dispatch_table(disp_table, pName); 2815 if (addr) 2816 return addr; 2817 2818 return NULL; 2819} 2820 2821LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName) 2822{ 2823 return loader_GetInstanceProcAddr(instance, pName); 2824} 2825 2826static PFN_vkVoidFunction VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName) 2827{ 2828 if (device == VK_NULL_HANDLE) { 2829 return NULL; 2830 } 2831 2832 void *addr; 2833 2834 /* for entrypoints that loader must handle (ie non-dispatchable or create object) 2835 make sure the loader entrypoint is returned */ 2836 addr = loader_non_passthrough_gpa(pName); 2837 if (addr) { 2838 return addr; 2839 } 2840 2841 /* return the dispatch table entrypoint for the fastest case */ 2842 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device; 2843 if (disp_table == NULL) 2844 return NULL; 2845 2846 addr = loader_lookup_device_dispatch_table(disp_table, pName); 2847 if (addr) 2848 return addr; 2849 else { 2850 if (disp_table->GetDeviceProcAddr == NULL) 2851 return NULL; 2852 return disp_table->GetDeviceProcAddr(device, pName); 2853 } 2854} 2855 2856LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName) 2857{ 2858 return loader_GetDeviceProcAddr(device, pName); 2859} 2860 2861LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties( 2862 const char* pLayerName, 2863 uint32_t* pCount, 2864 VkExtensionProperties* pProperties) 2865{ 2866 struct loader_extension_list *global_extension_list; 2867 2868 /* Scan/discover all ICD libraries in a single-threaded manner */ 2869 loader_platform_thread_once(&once_icd, loader_icd_scan); 2870 2871 /* get layer libraries in a single-threaded manner */ 2872 loader_platform_thread_once(&once_layer, loader_layer_scan); 2873 2874 /* merge any duplicate extensions */ 2875 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 2876 2877 uint32_t copy_size; 2878 2879 if (pCount == NULL) { 2880 return VK_ERROR_INVALID_POINTER; 2881 } 2882 2883 loader_platform_thread_lock_mutex(&loader_lock); 2884 2885 global_extension_list = loader_global_extensions(pLayerName); 2886 if (global_extension_list == NULL) { 2887 loader_platform_thread_unlock_mutex(&loader_lock); 2888 return VK_ERROR_INVALID_LAYER; 2889 } 2890 2891 if (pProperties == NULL) { 2892 *pCount = global_extension_list->count; 2893 loader_platform_thread_unlock_mutex(&loader_lock); 2894 return VK_SUCCESS; 2895 } 2896 2897 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count; 2898 for (uint32_t i = 0; i < copy_size; i++) { 2899 memcpy(&pProperties[i], 2900 &global_extension_list->list[i].info, 2901 sizeof(VkExtensionProperties)); 2902 } 2903 *pCount = copy_size; 2904 2905 loader_platform_thread_unlock_mutex(&loader_lock); 2906 2907 if (copy_size < global_extension_list->count) { 2908 return VK_INCOMPLETE; 2909 } 2910 2911 return VK_SUCCESS; 2912} 2913 2914LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties( 2915 uint32_t* pCount, 2916 VkLayerProperties* pProperties) 2917{ 2918 2919 /* Scan/discover all ICD libraries in a single-threaded manner */ 2920 loader_platform_thread_once(&once_icd, loader_icd_scan); 2921 2922 /* get layer libraries in a single-threaded manner */ 2923 loader_platform_thread_once(&once_layer, loader_layer_scan); 2924 2925 /* merge any duplicate extensions */ 2926 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 2927 2928 uint32_t copy_size; 2929 2930 if (pCount == NULL) { 2931 return VK_ERROR_INVALID_POINTER; 2932 } 2933 2934 /* TODO: do we still need to lock */ 2935 loader_platform_thread_lock_mutex(&loader_lock); 2936 2937 struct loader_layer_list *layer_list; 2938 layer_list = &loader.scanned_instance_layers; 2939 2940 if (pProperties == NULL) { 2941 *pCount = layer_list->count; 2942 loader_platform_thread_unlock_mutex(&loader_lock); 2943 return VK_SUCCESS; 2944 } 2945 2946 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count; 2947 for (uint32_t i = 0; i < copy_size; i++) { 2948 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties)); 2949 } 2950 *pCount = copy_size; 2951 2952 loader_platform_thread_unlock_mutex(&loader_lock); 2953 2954 if (copy_size < layer_list->count) { 2955 return VK_INCOMPLETE; 2956 } 2957 2958 return VK_SUCCESS; 2959} 2960 2961VkResult VKAPI loader_GetPhysicalDeviceExtensionProperties( 2962 VkPhysicalDevice gpu, 2963 const char* pLayerName, 2964 uint32_t* pCount, 2965 VkExtensionProperties* pProperties) 2966{ 2967 uint32_t gpu_index; 2968 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2969 uint32_t copy_size; 2970 2971 if (pCount == NULL) { 2972 return VK_ERROR_INVALID_POINTER; 2973 } 2974 2975 uint32_t count; 2976 struct loader_extension_list *list; 2977 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list); 2978 2979 if (pProperties == NULL) { 2980 *pCount = count; 2981 return VK_SUCCESS; 2982 } 2983 2984 copy_size = *pCount < count ? *pCount : count; 2985 for (uint32_t i = 0; i < copy_size; i++) { 2986 memcpy(&pProperties[i], 2987 &list->list[i].info, 2988 sizeof(VkExtensionProperties)); 2989 } 2990 *pCount = copy_size; 2991 2992 if (copy_size < count) { 2993 return VK_INCOMPLETE; 2994 } 2995 2996 return VK_SUCCESS; 2997} 2998 2999VkResult VKAPI loader_GetPhysicalDeviceLayerProperties( 3000 VkPhysicalDevice gpu, 3001 uint32_t* pCount, 3002 VkLayerProperties* pProperties) 3003{ 3004 uint32_t copy_size; 3005 3006 if (pCount == NULL) { 3007 return VK_ERROR_INVALID_POINTER; 3008 } 3009 3010 uint32_t count = loader.scanned_device_layers.count; 3011 struct loader_layer_list *layer_list = &loader.scanned_device_layers; 3012 3013 if (pProperties == NULL) { 3014 *pCount = count; 3015 return VK_SUCCESS; 3016 } 3017 3018 copy_size = *pCount < count ? *pCount : count; 3019 for (uint32_t i = 0; i < copy_size; i++) { 3020 memcpy(&pProperties[i], 3021 &layer_list->list[i].info, 3022 sizeof(VkLayerProperties)); 3023 } 3024 *pCount = copy_size; 3025 3026 if (copy_size < count) { 3027 return VK_INCOMPLETE; 3028 } 3029 3030 return VK_SUCCESS; 3031} 3032