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