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