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