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