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