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