15db71995Sopenharmony_ci/* 25db71995Sopenharmony_ci * 35db71995Sopenharmony_ci * Copyright (c) 2014-2023 The Khronos Group Inc. 45db71995Sopenharmony_ci * Copyright (c) 2014-2023 Valve Corporation 55db71995Sopenharmony_ci * Copyright (c) 2014-2023 LunarG, Inc. 65db71995Sopenharmony_ci * Copyright (C) 2015 Google Inc. 75db71995Sopenharmony_ci * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 85db71995Sopenharmony_ci * Copyright (c) 2023-2023 RasterGrid Kft. 95db71995Sopenharmony_ci * 105db71995Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 115db71995Sopenharmony_ci * you may not use this file except in compliance with the License. 125db71995Sopenharmony_ci * You may obtain a copy of the License at 135db71995Sopenharmony_ci * 145db71995Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 155db71995Sopenharmony_ci * 165db71995Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 175db71995Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 185db71995Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 195db71995Sopenharmony_ci * See the License for the specific language governing permissions and 205db71995Sopenharmony_ci * limitations under the License. 215db71995Sopenharmony_ci 225db71995Sopenharmony_ci * 235db71995Sopenharmony_ci * Author: Jon Ashburn <jon@lunarg.com> 245db71995Sopenharmony_ci * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 255db71995Sopenharmony_ci * Author: Mark Young <marky@lunarg.com> 265db71995Sopenharmony_ci * Author: Lenny Komow <lenny@lunarg.com> 275db71995Sopenharmony_ci * Author: Charles Giessen <charles@lunarg.com> 285db71995Sopenharmony_ci * 295db71995Sopenharmony_ci */ 305db71995Sopenharmony_ci 315db71995Sopenharmony_ci#include "loader.h" 325db71995Sopenharmony_ci 335db71995Sopenharmony_ci#include <ctype.h> 345db71995Sopenharmony_ci#include <inttypes.h> 355db71995Sopenharmony_ci#include <stdio.h> 365db71995Sopenharmony_ci#include <stdlib.h> 375db71995Sopenharmony_ci#include <stdarg.h> 385db71995Sopenharmony_ci#include <stdbool.h> 395db71995Sopenharmony_ci#include <string.h> 405db71995Sopenharmony_ci#include <stddef.h> 415db71995Sopenharmony_ci 425db71995Sopenharmony_ci#if defined(__APPLE__) 435db71995Sopenharmony_ci#include <CoreFoundation/CoreFoundation.h> 445db71995Sopenharmony_ci#include <sys/param.h> 455db71995Sopenharmony_ci#endif 465db71995Sopenharmony_ci 475db71995Sopenharmony_ci#include <sys/types.h> 485db71995Sopenharmony_ci#if defined(_WIN32) 495db71995Sopenharmony_ci#include "dirent_on_windows.h" 505db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 515db71995Sopenharmony_ci#include <dirent.h> 525db71995Sopenharmony_ci#else 535db71995Sopenharmony_ci#warning dirent.h not available on this platform 545db71995Sopenharmony_ci#endif // _WIN32 555db71995Sopenharmony_ci 565db71995Sopenharmony_ci#include "allocation.h" 575db71995Sopenharmony_ci#include "cJSON.h" 585db71995Sopenharmony_ci#include "debug_utils.h" 595db71995Sopenharmony_ci#include "loader_environment.h" 605db71995Sopenharmony_ci#include "gpa_helper.h" 615db71995Sopenharmony_ci#include "log.h" 625db71995Sopenharmony_ci#include "unknown_function_handling.h" 635db71995Sopenharmony_ci#include "vk_loader_platform.h" 645db71995Sopenharmony_ci#include "wsi.h" 655db71995Sopenharmony_ci 665db71995Sopenharmony_ci#if defined(WIN32) 675db71995Sopenharmony_ci#include "loader_windows.h" 685db71995Sopenharmony_ci#endif 695db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 705db71995Sopenharmony_ci// This header is currently only used when sorting Linux devices, so don't include it otherwise. 715db71995Sopenharmony_ci#include "loader_linux.h" 725db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 735db71995Sopenharmony_ci 745db71995Sopenharmony_ci// Generated file containing all the extension data 755db71995Sopenharmony_ci#include "vk_loader_extensions.c" 765db71995Sopenharmony_ci 775db71995Sopenharmony_cistruct loader_struct loader = {0}; 785db71995Sopenharmony_ci 795db71995Sopenharmony_cistruct activated_layer_info { 805db71995Sopenharmony_ci char *name; 815db71995Sopenharmony_ci char *manifest; 825db71995Sopenharmony_ci char *library; 835db71995Sopenharmony_ci bool is_implicit; 845db71995Sopenharmony_ci char *disable_env; 855db71995Sopenharmony_ci}; 865db71995Sopenharmony_ci 875db71995Sopenharmony_ci// thread safety lock for accessing global data structures such as "loader" 885db71995Sopenharmony_ci// all entrypoints on the instance chain need to be locked except GPA 895db71995Sopenharmony_ci// additionally CreateDevice and DestroyDevice needs to be locked 905db71995Sopenharmony_ciloader_platform_thread_mutex loader_lock; 915db71995Sopenharmony_ciloader_platform_thread_mutex loader_preload_icd_lock; 925db71995Sopenharmony_ciloader_platform_thread_mutex loader_global_instance_list_lock; 935db71995Sopenharmony_ci 945db71995Sopenharmony_ci// A list of ICDs that gets initialized when the loader does its global initialization. This list should never be used by anything 955db71995Sopenharmony_ci// other than EnumerateInstanceExtensionProperties(), vkDestroyInstance, and loader_release(). This list does not change 965db71995Sopenharmony_ci// functionality, but the fact that the libraries already been loaded causes any call that needs to load ICD libraries to speed up 975db71995Sopenharmony_ci// significantly. This can have a huge impact when making repeated calls to vkEnumerateInstanceExtensionProperties and 985db71995Sopenharmony_ci// vkCreateInstance. 995db71995Sopenharmony_cistruct loader_icd_tramp_list scanned_icds; 1005db71995Sopenharmony_ci 1015db71995Sopenharmony_ci// controls whether loader_platform_close_library() closes the libraries or not - controlled by an environment 1025db71995Sopenharmony_ci// variables - this is just the definition of the variable, usage is in vk_loader_platform.h 1035db71995Sopenharmony_cibool loader_disable_dynamic_library_unloading; 1045db71995Sopenharmony_ci 1055db71995Sopenharmony_ciLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init); 1065db71995Sopenharmony_ci 1075db71995Sopenharmony_ci// Creates loader_api_version struct that contains the major and minor fields, setting patch to 0 1085db71995Sopenharmony_ciloader_api_version loader_make_version(uint32_t version) { 1095db71995Sopenharmony_ci loader_api_version out_version; 1105db71995Sopenharmony_ci out_version.major = VK_API_VERSION_MAJOR(version); 1115db71995Sopenharmony_ci out_version.minor = VK_API_VERSION_MINOR(version); 1125db71995Sopenharmony_ci out_version.patch = 0; 1135db71995Sopenharmony_ci return out_version; 1145db71995Sopenharmony_ci} 1155db71995Sopenharmony_ci 1165db71995Sopenharmony_ci// Creates loader_api_version struct containing the major, minor, and patch fields 1175db71995Sopenharmony_ciloader_api_version loader_make_full_version(uint32_t version) { 1185db71995Sopenharmony_ci loader_api_version out_version; 1195db71995Sopenharmony_ci out_version.major = VK_API_VERSION_MAJOR(version); 1205db71995Sopenharmony_ci out_version.minor = VK_API_VERSION_MINOR(version); 1215db71995Sopenharmony_ci out_version.patch = VK_API_VERSION_PATCH(version); 1225db71995Sopenharmony_ci return out_version; 1235db71995Sopenharmony_ci} 1245db71995Sopenharmony_ci 1255db71995Sopenharmony_ciloader_api_version loader_combine_version(uint32_t major, uint32_t minor, uint32_t patch) { 1265db71995Sopenharmony_ci loader_api_version out_version; 1275db71995Sopenharmony_ci out_version.major = (uint16_t)major; 1285db71995Sopenharmony_ci out_version.minor = (uint16_t)minor; 1295db71995Sopenharmony_ci out_version.patch = (uint16_t)patch; 1305db71995Sopenharmony_ci return out_version; 1315db71995Sopenharmony_ci} 1325db71995Sopenharmony_ci 1335db71995Sopenharmony_ci// Helper macros for determining if a version is valid or not 1345db71995Sopenharmony_cibool loader_check_version_meets_required(loader_api_version required, loader_api_version version) { 1355db71995Sopenharmony_ci // major version is satisfied 1365db71995Sopenharmony_ci return (version.major > required.major) || 1375db71995Sopenharmony_ci // major version is equal, minor version is patch version is greater to minimum minor 1385db71995Sopenharmony_ci (version.major == required.major && version.minor > required.minor) || 1395db71995Sopenharmony_ci // major and minor version are equal, patch version is greater or equal to minimum patch 1405db71995Sopenharmony_ci (version.major == required.major && version.minor == required.minor && version.patch >= required.patch); 1415db71995Sopenharmony_ci} 1425db71995Sopenharmony_ci 1435db71995Sopenharmony_ci// Wrapper around opendir so that the dirent_on_windows gets the instance it needs 1445db71995Sopenharmony_ci// while linux opendir & readdir does not 1455db71995Sopenharmony_ciDIR *loader_opendir(const struct loader_instance *instance, const char *name) { 1465db71995Sopenharmony_ci#if defined(_WIN32) 1475db71995Sopenharmony_ci return opendir(instance ? &instance->alloc_callbacks : NULL, name); 1485db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 1495db71995Sopenharmony_ci (void)instance; 1505db71995Sopenharmony_ci return opendir(name); 1515db71995Sopenharmony_ci#else 1525db71995Sopenharmony_ci#warning dirent.h - opendir not available on this platform 1535db71995Sopenharmony_ci#endif // _WIN32 1545db71995Sopenharmony_ci} 1555db71995Sopenharmony_ciint loader_closedir(const struct loader_instance *instance, DIR *dir) { 1565db71995Sopenharmony_ci#if defined(_WIN32) 1575db71995Sopenharmony_ci return closedir(instance ? &instance->alloc_callbacks : NULL, dir); 1585db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 1595db71995Sopenharmony_ci (void)instance; 1605db71995Sopenharmony_ci return closedir(dir); 1615db71995Sopenharmony_ci#else 1625db71995Sopenharmony_ci#warning dirent.h - closedir not available on this platform 1635db71995Sopenharmony_ci#endif // _WIN32 1645db71995Sopenharmony_ci} 1655db71995Sopenharmony_ci 1665db71995Sopenharmony_cibool is_json(const char *path, size_t len) { 1675db71995Sopenharmony_ci if (len < 5) { 1685db71995Sopenharmony_ci return false; 1695db71995Sopenharmony_ci } 1705db71995Sopenharmony_ci return !strncmp(path, ".json", 5); 1715db71995Sopenharmony_ci} 1725db71995Sopenharmony_ci 1735db71995Sopenharmony_ci// Handle error from to library loading 1745db71995Sopenharmony_civoid loader_handle_load_library_error(const struct loader_instance *inst, const char *filename, 1755db71995Sopenharmony_ci enum loader_layer_library_status *lib_status) { 1765db71995Sopenharmony_ci const char *error_message = loader_platform_open_library_error(filename); 1775db71995Sopenharmony_ci // If the error is due to incompatible architecture (eg 32 bit vs 64 bit), report it with INFO level 1785db71995Sopenharmony_ci // Discussed in Github issue 262 & 644 1795db71995Sopenharmony_ci // "wrong ELF class" is a linux error, " with error 193" is a windows error 1805db71995Sopenharmony_ci VkFlags err_flag = VULKAN_LOADER_ERROR_BIT; 1815db71995Sopenharmony_ci if (strstr(error_message, "wrong ELF class:") != NULL || strstr(error_message, " with error 193") != NULL) { 1825db71995Sopenharmony_ci err_flag = VULKAN_LOADER_INFO_BIT; 1835db71995Sopenharmony_ci if (NULL != lib_status) { 1845db71995Sopenharmony_ci *lib_status = LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE; 1855db71995Sopenharmony_ci } 1865db71995Sopenharmony_ci } 1875db71995Sopenharmony_ci // Check if the error is due to lack of memory 1885db71995Sopenharmony_ci // "with error 8" is the windows error code for OOM cases, aka ERROR_NOT_ENOUGH_MEMORY 1895db71995Sopenharmony_ci // Linux doesn't have such a nice error message - only if there are reported issues should this be called 1905db71995Sopenharmony_ci else if (strstr(error_message, " with error 8") != NULL) { 1915db71995Sopenharmony_ci if (NULL != lib_status) { 1925db71995Sopenharmony_ci *lib_status = LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY; 1935db71995Sopenharmony_ci } 1945db71995Sopenharmony_ci } else if (NULL != lib_status) { 1955db71995Sopenharmony_ci *lib_status = LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD; 1965db71995Sopenharmony_ci } 1975db71995Sopenharmony_ci loader_log(inst, err_flag, 0, error_message); 1985db71995Sopenharmony_ci} 1995db71995Sopenharmony_ci 2005db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance, void *object) { 2015db71995Sopenharmony_ci struct loader_instance *inst = loader_get_instance(instance); 2025db71995Sopenharmony_ci if (!inst) { 2035db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkSetInstanceDispatch: Can not retrieve Instance dispatch table."); 2045db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 2055db71995Sopenharmony_ci } 2065db71995Sopenharmony_ci loader_set_dispatch(object, inst->disp); 2075db71995Sopenharmony_ci return VK_SUCCESS; 2085db71995Sopenharmony_ci} 2095db71995Sopenharmony_ci 2105db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object) { 2115db71995Sopenharmony_ci struct loader_device *dev; 2125db71995Sopenharmony_ci struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL); 2135db71995Sopenharmony_ci 2145db71995Sopenharmony_ci if (NULL == icd_term || NULL == dev) { 2155db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 2165db71995Sopenharmony_ci } 2175db71995Sopenharmony_ci loader_set_dispatch(object, &dev->loader_dispatch); 2185db71995Sopenharmony_ci return VK_SUCCESS; 2195db71995Sopenharmony_ci} 2205db71995Sopenharmony_ci 2215db71995Sopenharmony_civoid loader_free_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *layer_properties) { 2225db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->manifest_file_name); 2235db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->lib_name); 2245db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->functions.str_gipa); 2255db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->functions.str_gdpa); 2265db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->functions.str_negotiate_interface); 2275db71995Sopenharmony_ci loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_properties->instance_extension_list); 2285db71995Sopenharmony_ci if (layer_properties->device_extension_list.capacity > 0 && NULL != layer_properties->device_extension_list.list) { 2295db71995Sopenharmony_ci for (uint32_t i = 0; i < layer_properties->device_extension_list.count; i++) { 2305db71995Sopenharmony_ci free_string_list(inst, &layer_properties->device_extension_list.list[i].entrypoints); 2315db71995Sopenharmony_ci } 2325db71995Sopenharmony_ci } 2335db71995Sopenharmony_ci loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_properties->device_extension_list); 2345db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->disable_env_var.name); 2355db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->disable_env_var.value); 2365db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->enable_env_var.name); 2375db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->enable_env_var.value); 2385db71995Sopenharmony_ci free_string_list(inst, &layer_properties->component_layer_names); 2395db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->pre_instance_functions.enumerate_instance_extension_properties); 2405db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->pre_instance_functions.enumerate_instance_layer_properties); 2415db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_properties->pre_instance_functions.enumerate_instance_version); 2425db71995Sopenharmony_ci free_string_list(inst, &layer_properties->override_paths); 2435db71995Sopenharmony_ci free_string_list(inst, &layer_properties->blacklist_layer_names); 2445db71995Sopenharmony_ci free_string_list(inst, &layer_properties->app_key_paths); 2455db71995Sopenharmony_ci 2465db71995Sopenharmony_ci // Make sure to clear out the removed layer, in case new layers are added in the previous location 2475db71995Sopenharmony_ci memset(layer_properties, 0, sizeof(struct loader_layer_properties)); 2485db71995Sopenharmony_ci} 2495db71995Sopenharmony_ci 2505db71995Sopenharmony_ciVkResult loader_init_library_list(struct loader_layer_list *instance_layers, loader_platform_dl_handle **libs) { 2515db71995Sopenharmony_ci if (instance_layers->count > 0) { 2525db71995Sopenharmony_ci *libs = loader_calloc(NULL, sizeof(loader_platform_dl_handle) * instance_layers->count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 2535db71995Sopenharmony_ci if (*libs == NULL) { 2545db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 2555db71995Sopenharmony_ci } 2565db71995Sopenharmony_ci } 2575db71995Sopenharmony_ci return VK_SUCCESS; 2585db71995Sopenharmony_ci} 2595db71995Sopenharmony_ci 2605db71995Sopenharmony_ciVkResult loader_copy_to_new_str(const struct loader_instance *inst, const char *source_str, char **dest_str) { 2615db71995Sopenharmony_ci assert(source_str && dest_str); 2625db71995Sopenharmony_ci size_t str_len = strlen(source_str) + 1; 2635db71995Sopenharmony_ci *dest_str = loader_instance_heap_calloc(inst, str_len, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2645db71995Sopenharmony_ci if (NULL == *dest_str) return VK_ERROR_OUT_OF_HOST_MEMORY; 2655db71995Sopenharmony_ci loader_strncpy(*dest_str, str_len, source_str, str_len); 2665db71995Sopenharmony_ci (*dest_str)[str_len - 1] = 0; 2675db71995Sopenharmony_ci return VK_SUCCESS; 2685db71995Sopenharmony_ci} 2695db71995Sopenharmony_ci 2705db71995Sopenharmony_ciVkResult create_string_list(const struct loader_instance *inst, uint32_t allocated_count, struct loader_string_list *string_list) { 2715db71995Sopenharmony_ci assert(string_list); 2725db71995Sopenharmony_ci string_list->list = loader_instance_heap_calloc(inst, sizeof(char *) * allocated_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2735db71995Sopenharmony_ci if (NULL == string_list->list) { 2745db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 2755db71995Sopenharmony_ci } 2765db71995Sopenharmony_ci string_list->allocated_count = allocated_count; 2775db71995Sopenharmony_ci string_list->count = 0; 2785db71995Sopenharmony_ci return VK_SUCCESS; 2795db71995Sopenharmony_ci} 2805db71995Sopenharmony_ci 2815db71995Sopenharmony_ciVkResult append_str_to_string_list(const struct loader_instance *inst, struct loader_string_list *string_list, char *str) { 2825db71995Sopenharmony_ci assert(string_list && str); 2835db71995Sopenharmony_ci if (string_list->allocated_count == 0) { 2845db71995Sopenharmony_ci string_list->allocated_count = 32; 2855db71995Sopenharmony_ci string_list->list = 2865db71995Sopenharmony_ci loader_instance_heap_calloc(inst, sizeof(char *) * string_list->allocated_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2875db71995Sopenharmony_ci if (NULL == string_list->list) { 2885db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 2895db71995Sopenharmony_ci } 2905db71995Sopenharmony_ci } else if (string_list->count + 1 > string_list->allocated_count) { 2915db71995Sopenharmony_ci uint32_t new_allocated_count = string_list->allocated_count * 2; 2925db71995Sopenharmony_ci string_list->list = loader_instance_heap_realloc(inst, string_list->list, sizeof(char *) * string_list->allocated_count, 2935db71995Sopenharmony_ci sizeof(char *) * new_allocated_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2945db71995Sopenharmony_ci if (NULL == string_list->list) { 2955db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 2965db71995Sopenharmony_ci } 2975db71995Sopenharmony_ci // Null out the new space 2985db71995Sopenharmony_ci memset(string_list->list + string_list->allocated_count, 0, string_list->allocated_count); 2995db71995Sopenharmony_ci string_list->allocated_count *= 2; 3005db71995Sopenharmony_ci } 3015db71995Sopenharmony_ci string_list->list[string_list->count++] = str; 3025db71995Sopenharmony_ci return VK_SUCCESS; 3035db71995Sopenharmony_ci} 3045db71995Sopenharmony_ci 3055db71995Sopenharmony_ciVkResult copy_str_to_string_list(const struct loader_instance *inst, struct loader_string_list *string_list, const char *str, 3065db71995Sopenharmony_ci size_t str_len) { 3075db71995Sopenharmony_ci assert(string_list && str); 3085db71995Sopenharmony_ci char *new_str = loader_instance_heap_calloc(inst, sizeof(char *) * str_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 3095db71995Sopenharmony_ci if (NULL == new_str) { 3105db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 3115db71995Sopenharmony_ci } 3125db71995Sopenharmony_ci loader_strncpy(new_str, sizeof(char *) * str_len + 1, str, str_len); 3135db71995Sopenharmony_ci new_str[str_len] = '\0'; 3145db71995Sopenharmony_ci VkResult res = append_str_to_string_list(inst, string_list, new_str); 3155db71995Sopenharmony_ci if (res != VK_SUCCESS) { 3165db71995Sopenharmony_ci // Cleanup new_str if the append failed - as append_str_to_string_list takes ownership but not if the function fails 3175db71995Sopenharmony_ci loader_instance_heap_free(inst, new_str); 3185db71995Sopenharmony_ci } 3195db71995Sopenharmony_ci return res; 3205db71995Sopenharmony_ci} 3215db71995Sopenharmony_ci 3225db71995Sopenharmony_civoid free_string_list(const struct loader_instance *inst, struct loader_string_list *string_list) { 3235db71995Sopenharmony_ci assert(string_list); 3245db71995Sopenharmony_ci if (string_list->list) { 3255db71995Sopenharmony_ci for (uint32_t i = 0; i < string_list->count; i++) { 3265db71995Sopenharmony_ci loader_instance_heap_free(inst, string_list->list[i]); 3275db71995Sopenharmony_ci string_list->list[i] = NULL; 3285db71995Sopenharmony_ci } 3295db71995Sopenharmony_ci loader_instance_heap_free(inst, string_list->list); 3305db71995Sopenharmony_ci } 3315db71995Sopenharmony_ci memset(string_list, 0, sizeof(struct loader_string_list)); 3325db71995Sopenharmony_ci} 3335db71995Sopenharmony_ci 3345db71995Sopenharmony_ci// Given string of three part form "maj.min.pat" convert to a vulkan version number. 3355db71995Sopenharmony_ci// Also can understand four part form "variant.major.minor.patch" if provided. 3365db71995Sopenharmony_ciuint32_t loader_parse_version_string(char *vers_str) { 3375db71995Sopenharmony_ci uint32_t variant = 0, major = 0, minor = 0, patch = 0; 3385db71995Sopenharmony_ci char *vers_tok; 3395db71995Sopenharmony_ci char *context = NULL; 3405db71995Sopenharmony_ci if (!vers_str) { 3415db71995Sopenharmony_ci return 0; 3425db71995Sopenharmony_ci } 3435db71995Sopenharmony_ci 3445db71995Sopenharmony_ci vers_tok = thread_safe_strtok(vers_str, ".\"\n\r", &context); 3455db71995Sopenharmony_ci if (NULL != vers_tok) { 3465db71995Sopenharmony_ci major = (uint16_t)atoi(vers_tok); 3475db71995Sopenharmony_ci vers_tok = thread_safe_strtok(NULL, ".\"\n\r", &context); 3485db71995Sopenharmony_ci if (NULL != vers_tok) { 3495db71995Sopenharmony_ci minor = (uint16_t)atoi(vers_tok); 3505db71995Sopenharmony_ci vers_tok = thread_safe_strtok(NULL, ".\"\n\r", &context); 3515db71995Sopenharmony_ci if (NULL != vers_tok) { 3525db71995Sopenharmony_ci patch = (uint16_t)atoi(vers_tok); 3535db71995Sopenharmony_ci vers_tok = thread_safe_strtok(NULL, ".\"\n\r", &context); 3545db71995Sopenharmony_ci // check that we are using a 4 part version string 3555db71995Sopenharmony_ci if (NULL != vers_tok) { 3565db71995Sopenharmony_ci // if we are, move the values over into the correct place 3575db71995Sopenharmony_ci variant = major; 3585db71995Sopenharmony_ci major = minor; 3595db71995Sopenharmony_ci minor = patch; 3605db71995Sopenharmony_ci patch = (uint16_t)atoi(vers_tok); 3615db71995Sopenharmony_ci } 3625db71995Sopenharmony_ci } 3635db71995Sopenharmony_ci } 3645db71995Sopenharmony_ci } 3655db71995Sopenharmony_ci 3665db71995Sopenharmony_ci return VK_MAKE_API_VERSION(variant, major, minor, patch); 3675db71995Sopenharmony_ci} 3685db71995Sopenharmony_ci 3695db71995Sopenharmony_cibool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) { 3705db71995Sopenharmony_ci return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false; 3715db71995Sopenharmony_ci} 3725db71995Sopenharmony_ci 3735db71995Sopenharmony_ci// Search the given ext_array for an extension matching the given vk_ext_prop 3745db71995Sopenharmony_cibool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count, 3755db71995Sopenharmony_ci const VkExtensionProperties *ext_array) { 3765db71995Sopenharmony_ci for (uint32_t i = 0; i < count; i++) { 3775db71995Sopenharmony_ci if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) return true; 3785db71995Sopenharmony_ci } 3795db71995Sopenharmony_ci return false; 3805db71995Sopenharmony_ci} 3815db71995Sopenharmony_ci 3825db71995Sopenharmony_ci// Search the given ext_list for an extension matching the given vk_ext_prop 3835db71995Sopenharmony_cibool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list) { 3845db71995Sopenharmony_ci for (uint32_t i = 0; i < ext_list->count; i++) { 3855db71995Sopenharmony_ci if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop)) return true; 3865db71995Sopenharmony_ci } 3875db71995Sopenharmony_ci return false; 3885db71995Sopenharmony_ci} 3895db71995Sopenharmony_ci 3905db71995Sopenharmony_ci// Search the given ext_list for a device extension matching the given ext_prop 3915db71995Sopenharmony_cibool has_vk_dev_ext_property(const VkExtensionProperties *ext_prop, const struct loader_device_extension_list *ext_list) { 3925db71995Sopenharmony_ci for (uint32_t i = 0; i < ext_list->count; i++) { 3935db71995Sopenharmony_ci if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop)) return true; 3945db71995Sopenharmony_ci } 3955db71995Sopenharmony_ci return false; 3965db71995Sopenharmony_ci} 3975db71995Sopenharmony_ci 3985db71995Sopenharmony_ciVkResult loader_append_layer_property(const struct loader_instance *inst, struct loader_layer_list *layer_list, 3995db71995Sopenharmony_ci struct loader_layer_properties *layer_property) { 4005db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 4015db71995Sopenharmony_ci if (layer_list->capacity == 0) { 4025db71995Sopenharmony_ci res = loader_init_generic_list(inst, (struct loader_generic_list *)layer_list, sizeof(struct loader_layer_properties)); 4035db71995Sopenharmony_ci if (VK_SUCCESS != res) { 4045db71995Sopenharmony_ci goto out; 4055db71995Sopenharmony_ci } 4065db71995Sopenharmony_ci } 4075db71995Sopenharmony_ci 4085db71995Sopenharmony_ci // Ensure enough room to add an entry 4095db71995Sopenharmony_ci if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) > layer_list->capacity) { 4105db71995Sopenharmony_ci void *new_ptr = loader_instance_heap_realloc(inst, layer_list->list, layer_list->capacity, layer_list->capacity * 2, 4115db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 4125db71995Sopenharmony_ci if (NULL == new_ptr) { 4135db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_append_layer_property: realloc failed for layer list"); 4145db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 4155db71995Sopenharmony_ci goto out; 4165db71995Sopenharmony_ci } 4175db71995Sopenharmony_ci layer_list->list = new_ptr; 4185db71995Sopenharmony_ci memset((uint8_t *)layer_list->list + layer_list->capacity, 0, layer_list->capacity); 4195db71995Sopenharmony_ci layer_list->capacity *= 2; 4205db71995Sopenharmony_ci } 4215db71995Sopenharmony_ci memcpy(&layer_list->list[layer_list->count], layer_property, sizeof(struct loader_layer_properties)); 4225db71995Sopenharmony_ci layer_list->count++; 4235db71995Sopenharmony_ci memset(layer_property, 0, sizeof(struct loader_layer_properties)); 4245db71995Sopenharmony_ciout: 4255db71995Sopenharmony_ci if (res != VK_SUCCESS) { 4265db71995Sopenharmony_ci loader_free_layer_properties(inst, layer_property); 4275db71995Sopenharmony_ci } 4285db71995Sopenharmony_ci return res; 4295db71995Sopenharmony_ci} 4305db71995Sopenharmony_ci 4315db71995Sopenharmony_ci// Search the given layer list for a layer property matching the given layer name 4325db71995Sopenharmony_cistruct loader_layer_properties *loader_find_layer_property(const char *name, const struct loader_layer_list *layer_list) { 4335db71995Sopenharmony_ci for (uint32_t i = 0; i < layer_list->count; i++) { 4345db71995Sopenharmony_ci const VkLayerProperties *item = &layer_list->list[i].info; 4355db71995Sopenharmony_ci if (strcmp(name, item->layerName) == 0) return &layer_list->list[i]; 4365db71995Sopenharmony_ci } 4375db71995Sopenharmony_ci return NULL; 4385db71995Sopenharmony_ci} 4395db71995Sopenharmony_ci 4405db71995Sopenharmony_cistruct loader_layer_properties *loader_find_pointer_layer_property(const char *name, 4415db71995Sopenharmony_ci const struct loader_pointer_layer_list *layer_list) { 4425db71995Sopenharmony_ci for (uint32_t i = 0; i < layer_list->count; i++) { 4435db71995Sopenharmony_ci const VkLayerProperties *item = &layer_list->list[i]->info; 4445db71995Sopenharmony_ci if (strcmp(name, item->layerName) == 0) return layer_list->list[i]; 4455db71995Sopenharmony_ci } 4465db71995Sopenharmony_ci return NULL; 4475db71995Sopenharmony_ci} 4485db71995Sopenharmony_ci 4495db71995Sopenharmony_ci// Search the given layer list for a layer matching the given layer name 4505db71995Sopenharmony_cibool loader_find_layer_name_in_list(const char *name, const struct loader_pointer_layer_list *layer_list) { 4515db71995Sopenharmony_ci if (NULL == layer_list) { 4525db71995Sopenharmony_ci return false; 4535db71995Sopenharmony_ci } 4545db71995Sopenharmony_ci if (NULL != loader_find_pointer_layer_property(name, layer_list)) { 4555db71995Sopenharmony_ci return true; 4565db71995Sopenharmony_ci } 4575db71995Sopenharmony_ci return false; 4585db71995Sopenharmony_ci} 4595db71995Sopenharmony_ci 4605db71995Sopenharmony_ci// Search the given meta-layer's component list for a layer matching the given layer name 4615db71995Sopenharmony_cibool loader_find_layer_name_in_meta_layer(const struct loader_instance *inst, const char *layer_name, 4625db71995Sopenharmony_ci struct loader_layer_list *layer_list, struct loader_layer_properties *meta_layer_props) { 4635db71995Sopenharmony_ci for (uint32_t comp_layer = 0; comp_layer < meta_layer_props->component_layer_names.count; comp_layer++) { 4645db71995Sopenharmony_ci if (!strcmp(meta_layer_props->component_layer_names.list[comp_layer], layer_name)) { 4655db71995Sopenharmony_ci return true; 4665db71995Sopenharmony_ci } 4675db71995Sopenharmony_ci struct loader_layer_properties *comp_layer_props = 4685db71995Sopenharmony_ci loader_find_layer_property(meta_layer_props->component_layer_names.list[comp_layer], layer_list); 4695db71995Sopenharmony_ci if (comp_layer_props->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { 4705db71995Sopenharmony_ci return loader_find_layer_name_in_meta_layer(inst, layer_name, layer_list, comp_layer_props); 4715db71995Sopenharmony_ci } 4725db71995Sopenharmony_ci } 4735db71995Sopenharmony_ci return false; 4745db71995Sopenharmony_ci} 4755db71995Sopenharmony_ci 4765db71995Sopenharmony_ci// Search the override layer's blacklist for a layer matching the given layer name 4775db71995Sopenharmony_cibool loader_find_layer_name_in_blacklist(const char *layer_name, struct loader_layer_properties *meta_layer_props) { 4785db71995Sopenharmony_ci for (uint32_t black_layer = 0; black_layer < meta_layer_props->blacklist_layer_names.count; ++black_layer) { 4795db71995Sopenharmony_ci if (!strcmp(meta_layer_props->blacklist_layer_names.list[black_layer], layer_name)) { 4805db71995Sopenharmony_ci return true; 4815db71995Sopenharmony_ci } 4825db71995Sopenharmony_ci } 4835db71995Sopenharmony_ci return false; 4845db71995Sopenharmony_ci} 4855db71995Sopenharmony_ci 4865db71995Sopenharmony_ci// Remove all layer properties entries from the list 4875db71995Sopenharmony_civoid loader_delete_layer_list_and_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list) { 4885db71995Sopenharmony_ci uint32_t i; 4895db71995Sopenharmony_ci if (!layer_list) return; 4905db71995Sopenharmony_ci 4915db71995Sopenharmony_ci for (i = 0; i < layer_list->count; i++) { 4925db71995Sopenharmony_ci if (layer_list->list[i].lib_handle) { 4935db71995Sopenharmony_ci loader_platform_close_library(layer_list->list[i].lib_handle); 4945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Unloading layer library %s", 4955db71995Sopenharmony_ci layer_list->list[i].lib_name); 4965db71995Sopenharmony_ci layer_list->list[i].lib_handle = NULL; 4975db71995Sopenharmony_ci } 4985db71995Sopenharmony_ci loader_free_layer_properties(inst, &(layer_list->list[i])); 4995db71995Sopenharmony_ci } 5005db71995Sopenharmony_ci layer_list->count = 0; 5015db71995Sopenharmony_ci 5025db71995Sopenharmony_ci if (layer_list->capacity > 0) { 5035db71995Sopenharmony_ci layer_list->capacity = 0; 5045db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_list->list); 5055db71995Sopenharmony_ci } 5065db71995Sopenharmony_ci memset(layer_list, 0, sizeof(struct loader_layer_list)); 5075db71995Sopenharmony_ci} 5085db71995Sopenharmony_ci 5095db71995Sopenharmony_civoid loader_remove_layer_in_list(const struct loader_instance *inst, struct loader_layer_list *layer_list, 5105db71995Sopenharmony_ci uint32_t layer_to_remove) { 5115db71995Sopenharmony_ci if (layer_list == NULL || layer_to_remove >= layer_list->count) { 5125db71995Sopenharmony_ci return; 5135db71995Sopenharmony_ci } 5145db71995Sopenharmony_ci loader_free_layer_properties(inst, &(layer_list->list[layer_to_remove])); 5155db71995Sopenharmony_ci 5165db71995Sopenharmony_ci // Remove the current invalid meta-layer from the layer list. Use memmove since we are 5175db71995Sopenharmony_ci // overlapping the source and destination addresses. 5185db71995Sopenharmony_ci memmove(&layer_list->list[layer_to_remove], &layer_list->list[layer_to_remove + 1], 5195db71995Sopenharmony_ci sizeof(struct loader_layer_properties) * (layer_list->count - 1 - layer_to_remove)); 5205db71995Sopenharmony_ci 5215db71995Sopenharmony_ci // Decrement the count (because we now have one less) and decrement the loop index since we need to 5225db71995Sopenharmony_ci // re-check this index. 5235db71995Sopenharmony_ci layer_list->count--; 5245db71995Sopenharmony_ci} 5255db71995Sopenharmony_ci 5265db71995Sopenharmony_ci// Remove all layers in the layer list that are blacklisted by the override layer. 5275db71995Sopenharmony_ci// NOTE: This should only be called if an override layer is found and not expired. 5285db71995Sopenharmony_civoid loader_remove_layers_in_blacklist(const struct loader_instance *inst, struct loader_layer_list *layer_list) { 5295db71995Sopenharmony_ci struct loader_layer_properties *override_prop = loader_find_layer_property(VK_OVERRIDE_LAYER_NAME, layer_list); 5305db71995Sopenharmony_ci if (NULL == override_prop) { 5315db71995Sopenharmony_ci return; 5325db71995Sopenharmony_ci } 5335db71995Sopenharmony_ci 5345db71995Sopenharmony_ci for (int32_t j = 0; j < (int32_t)(layer_list->count); j++) { 5355db71995Sopenharmony_ci struct loader_layer_properties cur_layer_prop = layer_list->list[j]; 5365db71995Sopenharmony_ci const char *cur_layer_name = &cur_layer_prop.info.layerName[0]; 5375db71995Sopenharmony_ci 5385db71995Sopenharmony_ci // Skip the override layer itself. 5395db71995Sopenharmony_ci if (!strcmp(VK_OVERRIDE_LAYER_NAME, cur_layer_name)) { 5405db71995Sopenharmony_ci continue; 5415db71995Sopenharmony_ci } 5425db71995Sopenharmony_ci 5435db71995Sopenharmony_ci // If found in the override layer's blacklist, remove it 5445db71995Sopenharmony_ci if (loader_find_layer_name_in_blacklist(cur_layer_name, override_prop)) { 5455db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, 5465db71995Sopenharmony_ci "loader_remove_layers_in_blacklist: Override layer is active and layer %s is in the blacklist inside of it. " 5475db71995Sopenharmony_ci "Removing that layer from current layer list.", 5485db71995Sopenharmony_ci cur_layer_name); 5495db71995Sopenharmony_ci loader_remove_layer_in_list(inst, layer_list, j); 5505db71995Sopenharmony_ci j--; 5515db71995Sopenharmony_ci 5525db71995Sopenharmony_ci // Re-do the query for the override layer 5535db71995Sopenharmony_ci override_prop = loader_find_layer_property(VK_OVERRIDE_LAYER_NAME, layer_list); 5545db71995Sopenharmony_ci } 5555db71995Sopenharmony_ci } 5565db71995Sopenharmony_ci} 5575db71995Sopenharmony_ci 5585db71995Sopenharmony_ci// Remove all layers in the layer list that are not found inside any implicit meta-layers. 5595db71995Sopenharmony_civoid loader_remove_layers_not_in_implicit_meta_layers(const struct loader_instance *inst, struct loader_layer_list *layer_list) { 5605db71995Sopenharmony_ci int32_t i; 5615db71995Sopenharmony_ci int32_t j; 5625db71995Sopenharmony_ci int32_t layer_count = (int32_t)(layer_list->count); 5635db71995Sopenharmony_ci 5645db71995Sopenharmony_ci for (i = 0; i < layer_count; i++) { 5655db71995Sopenharmony_ci layer_list->list[i].keep = false; 5665db71995Sopenharmony_ci } 5675db71995Sopenharmony_ci 5685db71995Sopenharmony_ci for (i = 0; i < layer_count; i++) { 5695db71995Sopenharmony_ci struct loader_layer_properties *cur_layer_prop = &layer_list->list[i]; 5705db71995Sopenharmony_ci 5715db71995Sopenharmony_ci if (0 == (cur_layer_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) { 5725db71995Sopenharmony_ci cur_layer_prop->keep = true; 5735db71995Sopenharmony_ci continue; 5745db71995Sopenharmony_ci } 5755db71995Sopenharmony_ci for (j = 0; j < layer_count; j++) { 5765db71995Sopenharmony_ci struct loader_layer_properties *layer_to_check = &layer_list->list[j]; 5775db71995Sopenharmony_ci 5785db71995Sopenharmony_ci if (i == j) { 5795db71995Sopenharmony_ci continue; 5805db71995Sopenharmony_ci } 5815db71995Sopenharmony_ci 5825db71995Sopenharmony_ci if (layer_to_check->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { 5835db71995Sopenharmony_ci // For all layers found in this meta layer, we want to keep them as well. 5845db71995Sopenharmony_ci if (loader_find_layer_name_in_meta_layer(inst, cur_layer_prop->info.layerName, layer_list, layer_to_check)) { 5855db71995Sopenharmony_ci cur_layer_prop->keep = true; 5865db71995Sopenharmony_ci } 5875db71995Sopenharmony_ci } 5885db71995Sopenharmony_ci } 5895db71995Sopenharmony_ci } 5905db71995Sopenharmony_ci 5915db71995Sopenharmony_ci // Remove any layers we don't want to keep (Don't use layer_count here as we need it to be 5925db71995Sopenharmony_ci // dynamically updated if we delete a layer property in the list). 5935db71995Sopenharmony_ci for (i = 0; i < (int32_t)(layer_list->count); i++) { 5945db71995Sopenharmony_ci struct loader_layer_properties *cur_layer_prop = &layer_list->list[i]; 5955db71995Sopenharmony_ci if (!cur_layer_prop->keep) { 5965db71995Sopenharmony_ci loader_log( 5975db71995Sopenharmony_ci inst, VULKAN_LOADER_DEBUG_BIT, 0, 5985db71995Sopenharmony_ci "loader_remove_layers_not_in_implicit_meta_layers : Implicit meta-layers are active, and layer %s is not list " 5995db71995Sopenharmony_ci "inside of any. So removing layer from current layer list.", 6005db71995Sopenharmony_ci cur_layer_prop->info.layerName); 6015db71995Sopenharmony_ci loader_remove_layer_in_list(inst, layer_list, i); 6025db71995Sopenharmony_ci i--; 6035db71995Sopenharmony_ci } 6045db71995Sopenharmony_ci } 6055db71995Sopenharmony_ci} 6065db71995Sopenharmony_ci 6075db71995Sopenharmony_ciVkResult loader_add_instance_extensions(const struct loader_instance *inst, 6085db71995Sopenharmony_ci const PFN_vkEnumerateInstanceExtensionProperties fp_get_props, const char *lib_name, 6095db71995Sopenharmony_ci struct loader_extension_list *ext_list) { 6105db71995Sopenharmony_ci uint32_t i, count = 0; 6115db71995Sopenharmony_ci VkExtensionProperties *ext_props; 6125db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 6135db71995Sopenharmony_ci 6145db71995Sopenharmony_ci if (!fp_get_props) { 6155db71995Sopenharmony_ci // No EnumerateInstanceExtensionProperties defined 6165db71995Sopenharmony_ci goto out; 6175db71995Sopenharmony_ci } 6185db71995Sopenharmony_ci 6195db71995Sopenharmony_ci // Make sure we never call ourself by accident, this should never happen outside of error paths 6205db71995Sopenharmony_ci if (fp_get_props == vkEnumerateInstanceExtensionProperties) { 6215db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 6225db71995Sopenharmony_ci "loader_add_instance_extensions: %s's vkEnumerateInstanceExtensionProperties points to the loader, this would " 6235db71995Sopenharmony_ci "lead to infinite recursion.", 6245db71995Sopenharmony_ci lib_name); 6255db71995Sopenharmony_ci goto out; 6265db71995Sopenharmony_ci } 6275db71995Sopenharmony_ci 6285db71995Sopenharmony_ci res = fp_get_props(NULL, &count, NULL); 6295db71995Sopenharmony_ci if (res != VK_SUCCESS) { 6305db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 6315db71995Sopenharmony_ci "loader_add_instance_extensions: Error getting Instance extension count from %s", lib_name); 6325db71995Sopenharmony_ci goto out; 6335db71995Sopenharmony_ci } 6345db71995Sopenharmony_ci 6355db71995Sopenharmony_ci if (count == 0) { 6365db71995Sopenharmony_ci // No ExtensionProperties to report 6375db71995Sopenharmony_ci goto out; 6385db71995Sopenharmony_ci } 6395db71995Sopenharmony_ci 6405db71995Sopenharmony_ci ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties)); 6415db71995Sopenharmony_ci if (NULL == ext_props) { 6425db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 6435db71995Sopenharmony_ci goto out; 6445db71995Sopenharmony_ci } 6455db71995Sopenharmony_ci 6465db71995Sopenharmony_ci res = fp_get_props(NULL, &count, ext_props); 6475db71995Sopenharmony_ci if (res != VK_SUCCESS) { 6485db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_add_instance_extensions: Error getting Instance extensions from %s", 6495db71995Sopenharmony_ci lib_name); 6505db71995Sopenharmony_ci goto out; 6515db71995Sopenharmony_ci } 6525db71995Sopenharmony_ci 6535db71995Sopenharmony_ci for (i = 0; i < count; i++) { 6545db71995Sopenharmony_ci bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]); 6555db71995Sopenharmony_ci if (!ext_unsupported) { 6565db71995Sopenharmony_ci res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]); 6575db71995Sopenharmony_ci if (res != VK_SUCCESS) { 6585db71995Sopenharmony_ci goto out; 6595db71995Sopenharmony_ci } 6605db71995Sopenharmony_ci } 6615db71995Sopenharmony_ci } 6625db71995Sopenharmony_ci 6635db71995Sopenharmony_ciout: 6645db71995Sopenharmony_ci return res; 6655db71995Sopenharmony_ci} 6665db71995Sopenharmony_ci 6675db71995Sopenharmony_ciVkResult loader_add_device_extensions(const struct loader_instance *inst, 6685db71995Sopenharmony_ci PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties, 6695db71995Sopenharmony_ci VkPhysicalDevice physical_device, const char *lib_name, 6705db71995Sopenharmony_ci struct loader_extension_list *ext_list) { 6715db71995Sopenharmony_ci uint32_t i = 0, count = 0; 6725db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 6735db71995Sopenharmony_ci VkExtensionProperties *ext_props = NULL; 6745db71995Sopenharmony_ci 6755db71995Sopenharmony_ci res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL); 6765db71995Sopenharmony_ci if (res != VK_SUCCESS) { 6775db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 6785db71995Sopenharmony_ci "loader_add_device_extensions: Error getting physical device extension info count from library %s", lib_name); 6795db71995Sopenharmony_ci return res; 6805db71995Sopenharmony_ci } 6815db71995Sopenharmony_ci if (count > 0) { 6825db71995Sopenharmony_ci ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties)); 6835db71995Sopenharmony_ci if (!ext_props) { 6845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 6855db71995Sopenharmony_ci "loader_add_device_extensions: Failed to allocate space for device extension properties from library %s.", 6865db71995Sopenharmony_ci lib_name); 6875db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 6885db71995Sopenharmony_ci } 6895db71995Sopenharmony_ci res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props); 6905db71995Sopenharmony_ci if (res != VK_SUCCESS) { 6915db71995Sopenharmony_ci return res; 6925db71995Sopenharmony_ci } 6935db71995Sopenharmony_ci for (i = 0; i < count; i++) { 6945db71995Sopenharmony_ci res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]); 6955db71995Sopenharmony_ci if (res != VK_SUCCESS) { 6965db71995Sopenharmony_ci return res; 6975db71995Sopenharmony_ci } 6985db71995Sopenharmony_ci } 6995db71995Sopenharmony_ci } 7005db71995Sopenharmony_ci 7015db71995Sopenharmony_ci return VK_SUCCESS; 7025db71995Sopenharmony_ci} 7035db71995Sopenharmony_ci 7045db71995Sopenharmony_ciVkResult loader_init_generic_list(const struct loader_instance *inst, struct loader_generic_list *list_info, size_t element_size) { 7055db71995Sopenharmony_ci size_t capacity = 32 * element_size; 7065db71995Sopenharmony_ci list_info->count = 0; 7075db71995Sopenharmony_ci list_info->capacity = 0; 7085db71995Sopenharmony_ci list_info->list = loader_instance_heap_calloc(inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 7095db71995Sopenharmony_ci if (list_info->list == NULL) { 7105db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_init_generic_list: Failed to allocate space for generic list"); 7115db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 7125db71995Sopenharmony_ci } 7135db71995Sopenharmony_ci list_info->capacity = capacity; 7145db71995Sopenharmony_ci return VK_SUCCESS; 7155db71995Sopenharmony_ci} 7165db71995Sopenharmony_ci 7175db71995Sopenharmony_civoid loader_destroy_generic_list(const struct loader_instance *inst, struct loader_generic_list *list) { 7185db71995Sopenharmony_ci loader_instance_heap_free(inst, list->list); 7195db71995Sopenharmony_ci memset(list, 0, sizeof(struct loader_generic_list)); 7205db71995Sopenharmony_ci} 7215db71995Sopenharmony_ci 7225db71995Sopenharmony_ci// Append non-duplicate extension properties defined in props to the given ext_list. 7235db71995Sopenharmony_ci// Return - Vk_SUCCESS on success 7245db71995Sopenharmony_ciVkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list, 7255db71995Sopenharmony_ci uint32_t prop_list_count, const VkExtensionProperties *props) { 7265db71995Sopenharmony_ci if (ext_list->list == NULL || ext_list->capacity == 0) { 7275db71995Sopenharmony_ci VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties)); 7285db71995Sopenharmony_ci if (VK_SUCCESS != res) { 7295db71995Sopenharmony_ci return res; 7305db71995Sopenharmony_ci } 7315db71995Sopenharmony_ci } 7325db71995Sopenharmony_ci 7335db71995Sopenharmony_ci for (uint32_t i = 0; i < prop_list_count; i++) { 7345db71995Sopenharmony_ci const VkExtensionProperties *cur_ext = &props[i]; 7355db71995Sopenharmony_ci 7365db71995Sopenharmony_ci // look for duplicates 7375db71995Sopenharmony_ci if (has_vk_extension_property(cur_ext, ext_list)) { 7385db71995Sopenharmony_ci continue; 7395db71995Sopenharmony_ci } 7405db71995Sopenharmony_ci 7415db71995Sopenharmony_ci // add to list at end 7425db71995Sopenharmony_ci // check for enough capacity 7435db71995Sopenharmony_ci if (ext_list->count * sizeof(VkExtensionProperties) >= ext_list->capacity) { 7445db71995Sopenharmony_ci void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2, 7455db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 7465db71995Sopenharmony_ci if (new_ptr == NULL) { 7475db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 7485db71995Sopenharmony_ci "loader_add_to_ext_list: Failed to reallocate space for extension list"); 7495db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 7505db71995Sopenharmony_ci } 7515db71995Sopenharmony_ci ext_list->list = new_ptr; 7525db71995Sopenharmony_ci 7535db71995Sopenharmony_ci // double capacity 7545db71995Sopenharmony_ci ext_list->capacity *= 2; 7555db71995Sopenharmony_ci } 7565db71995Sopenharmony_ci 7575db71995Sopenharmony_ci memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties)); 7585db71995Sopenharmony_ci ext_list->count++; 7595db71995Sopenharmony_ci } 7605db71995Sopenharmony_ci return VK_SUCCESS; 7615db71995Sopenharmony_ci} 7625db71995Sopenharmony_ci 7635db71995Sopenharmony_ci// Append one extension property defined in props with entrypoints defined in entries to the given 7645db71995Sopenharmony_ci// ext_list. Do not append if a duplicate. 7655db71995Sopenharmony_ci// If this is a duplicate, this function free's the passed in entries - as in it takes ownership over that list (if it is not 7665db71995Sopenharmony_ci// NULL) Return - Vk_SUCCESS on success 7675db71995Sopenharmony_ciVkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list, 7685db71995Sopenharmony_ci const VkExtensionProperties *props, struct loader_string_list *entrys) { 7695db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 7705db71995Sopenharmony_ci bool should_free_entrys = true; 7715db71995Sopenharmony_ci if (ext_list->list == NULL || ext_list->capacity == 0) { 7725db71995Sopenharmony_ci res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(struct loader_dev_ext_props)); 7735db71995Sopenharmony_ci if (VK_SUCCESS != res) { 7745db71995Sopenharmony_ci goto out; 7755db71995Sopenharmony_ci } 7765db71995Sopenharmony_ci } 7775db71995Sopenharmony_ci 7785db71995Sopenharmony_ci // look for duplicates 7795db71995Sopenharmony_ci if (has_vk_dev_ext_property(props, ext_list)) { 7805db71995Sopenharmony_ci goto out; 7815db71995Sopenharmony_ci } 7825db71995Sopenharmony_ci 7835db71995Sopenharmony_ci uint32_t idx = ext_list->count; 7845db71995Sopenharmony_ci // add to list at end 7855db71995Sopenharmony_ci // check for enough capacity 7865db71995Sopenharmony_ci if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) { 7875db71995Sopenharmony_ci void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2, 7885db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 7895db71995Sopenharmony_ci 7905db71995Sopenharmony_ci if (NULL == new_ptr) { 7915db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 7925db71995Sopenharmony_ci "loader_add_to_dev_ext_list: Failed to reallocate space for device extension list"); 7935db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 7945db71995Sopenharmony_ci goto out; 7955db71995Sopenharmony_ci } 7965db71995Sopenharmony_ci ext_list->list = new_ptr; 7975db71995Sopenharmony_ci 7985db71995Sopenharmony_ci // double capacity 7995db71995Sopenharmony_ci ext_list->capacity *= 2; 8005db71995Sopenharmony_ci } 8015db71995Sopenharmony_ci 8025db71995Sopenharmony_ci memcpy(&ext_list->list[idx].props, props, sizeof(*props)); 8035db71995Sopenharmony_ci if (entrys) { 8045db71995Sopenharmony_ci ext_list->list[idx].entrypoints = *entrys; 8055db71995Sopenharmony_ci should_free_entrys = false; 8065db71995Sopenharmony_ci } 8075db71995Sopenharmony_ci ext_list->count++; 8085db71995Sopenharmony_ciout: 8095db71995Sopenharmony_ci if (NULL != entrys && should_free_entrys) { 8105db71995Sopenharmony_ci free_string_list(inst, entrys); 8115db71995Sopenharmony_ci } 8125db71995Sopenharmony_ci return res; 8135db71995Sopenharmony_ci} 8145db71995Sopenharmony_ci 8155db71995Sopenharmony_ci// Create storage for pointers to loader_layer_properties 8165db71995Sopenharmony_cibool loader_init_pointer_layer_list(const struct loader_instance *inst, struct loader_pointer_layer_list *list) { 8175db71995Sopenharmony_ci list->capacity = 32 * sizeof(void *); 8185db71995Sopenharmony_ci list->list = loader_instance_heap_calloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 8195db71995Sopenharmony_ci if (list->list == NULL) { 8205db71995Sopenharmony_ci return false; 8215db71995Sopenharmony_ci } 8225db71995Sopenharmony_ci list->count = 0; 8235db71995Sopenharmony_ci return true; 8245db71995Sopenharmony_ci} 8255db71995Sopenharmony_ci 8265db71995Sopenharmony_ci// Search the given array of layer names for an entry matching the given VkLayerProperties 8275db71995Sopenharmony_cibool loader_names_array_has_layer_property(const VkLayerProperties *vk_layer_prop, uint32_t layer_info_count, 8285db71995Sopenharmony_ci struct activated_layer_info *layer_info) { 8295db71995Sopenharmony_ci for (uint32_t i = 0; i < layer_info_count; i++) { 8305db71995Sopenharmony_ci if (strcmp(vk_layer_prop->layerName, layer_info[i].name) == 0) { 8315db71995Sopenharmony_ci return true; 8325db71995Sopenharmony_ci } 8335db71995Sopenharmony_ci } 8345db71995Sopenharmony_ci return false; 8355db71995Sopenharmony_ci} 8365db71995Sopenharmony_ci 8375db71995Sopenharmony_civoid loader_destroy_pointer_layer_list(const struct loader_instance *inst, struct loader_pointer_layer_list *layer_list) { 8385db71995Sopenharmony_ci loader_instance_heap_free(inst, layer_list->list); 8395db71995Sopenharmony_ci memset(layer_list, 0, sizeof(struct loader_pointer_layer_list)); 8405db71995Sopenharmony_ci} 8415db71995Sopenharmony_ci 8425db71995Sopenharmony_ci// Append layer properties defined in prop_list to the given layer_info list 8435db71995Sopenharmony_ciVkResult loader_add_layer_properties_to_list(const struct loader_instance *inst, struct loader_pointer_layer_list *list, 8445db71995Sopenharmony_ci struct loader_layer_properties *props) { 8455db71995Sopenharmony_ci if (list->list == NULL || list->capacity == 0) { 8465db71995Sopenharmony_ci if (!loader_init_pointer_layer_list(inst, list)) { 8475db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 8485db71995Sopenharmony_ci } 8495db71995Sopenharmony_ci } 8505db71995Sopenharmony_ci 8515db71995Sopenharmony_ci // Check for enough capacity 8525db71995Sopenharmony_ci if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) { 8535db71995Sopenharmony_ci size_t new_capacity = list->capacity * 2; 8545db71995Sopenharmony_ci void *new_ptr = 8555db71995Sopenharmony_ci loader_instance_heap_realloc(inst, list->list, list->capacity, new_capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 8565db71995Sopenharmony_ci if (NULL == new_ptr) { 8575db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 8585db71995Sopenharmony_ci "loader_add_layer_properties_to_list: Realloc failed for when attempting to add new layer"); 8595db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 8605db71995Sopenharmony_ci } 8615db71995Sopenharmony_ci list->list = new_ptr; 8625db71995Sopenharmony_ci list->capacity = new_capacity; 8635db71995Sopenharmony_ci } 8645db71995Sopenharmony_ci list->list[list->count++] = props; 8655db71995Sopenharmony_ci 8665db71995Sopenharmony_ci return VK_SUCCESS; 8675db71995Sopenharmony_ci} 8685db71995Sopenharmony_ci 8695db71995Sopenharmony_ci// Determine if the provided explicit layer should be available by querying the appropriate environmental variables. 8705db71995Sopenharmony_cibool loader_layer_is_available(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters, 8715db71995Sopenharmony_ci const struct loader_layer_properties *prop) { 8725db71995Sopenharmony_ci bool available = true; 8735db71995Sopenharmony_ci bool is_implicit = (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)); 8745db71995Sopenharmony_ci bool disabled_by_type = 8755db71995Sopenharmony_ci (is_implicit) ? (filters->disable_filter.disable_all_implicit) : (filters->disable_filter.disable_all_explicit); 8765db71995Sopenharmony_ci if ((filters->disable_filter.disable_all || disabled_by_type || 8775db71995Sopenharmony_ci check_name_matches_filter_environment_var(prop->info.layerName, &filters->disable_filter.additional_filters)) && 8785db71995Sopenharmony_ci !check_name_matches_filter_environment_var(prop->info.layerName, &filters->allow_filter)) { 8795db71995Sopenharmony_ci available = false; 8805db71995Sopenharmony_ci } 8815db71995Sopenharmony_ci if (check_name_matches_filter_environment_var(prop->info.layerName, &filters->enable_filter)) { 8825db71995Sopenharmony_ci available = true; 8835db71995Sopenharmony_ci } else if (!available) { 8845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 8855db71995Sopenharmony_ci "Layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", prop->info.layerName, 8865db71995Sopenharmony_ci VK_LAYERS_DISABLE_ENV_VAR); 8875db71995Sopenharmony_ci } 8885db71995Sopenharmony_ci 8895db71995Sopenharmony_ci return available; 8905db71995Sopenharmony_ci} 8915db71995Sopenharmony_ci 8925db71995Sopenharmony_ci// Search the given search_list for any layers in the props list. Add these to the 8935db71995Sopenharmony_ci// output layer_list. 8945db71995Sopenharmony_ciVkResult loader_add_layer_names_to_list(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters, 8955db71995Sopenharmony_ci struct loader_pointer_layer_list *output_list, 8965db71995Sopenharmony_ci struct loader_pointer_layer_list *expanded_output_list, uint32_t name_count, 8975db71995Sopenharmony_ci const char *const *names, const struct loader_layer_list *source_list) { 8985db71995Sopenharmony_ci VkResult err = VK_SUCCESS; 8995db71995Sopenharmony_ci 9005db71995Sopenharmony_ci for (uint32_t i = 0; i < name_count; i++) { 9015db71995Sopenharmony_ci const char *source_name = names[i]; 9025db71995Sopenharmony_ci 9035db71995Sopenharmony_ci struct loader_layer_properties *layer_prop = loader_find_layer_property(source_name, source_list); 9045db71995Sopenharmony_ci if (NULL == layer_prop) { 9055db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, 9065db71995Sopenharmony_ci "loader_add_layer_names_to_list: Unable to find layer \"%s\"", source_name); 9075db71995Sopenharmony_ci err = VK_ERROR_LAYER_NOT_PRESENT; 9085db71995Sopenharmony_ci continue; 9095db71995Sopenharmony_ci } 9105db71995Sopenharmony_ci 9115db71995Sopenharmony_ci // Make sure the layer isn't already in the output_list, skip adding it if it is. 9125db71995Sopenharmony_ci if (loader_find_layer_name_in_list(source_name, output_list)) { 9135db71995Sopenharmony_ci continue; 9145db71995Sopenharmony_ci } 9155db71995Sopenharmony_ci 9165db71995Sopenharmony_ci if (!loader_layer_is_available(inst, filters, layer_prop)) { 9175db71995Sopenharmony_ci continue; 9185db71995Sopenharmony_ci } 9195db71995Sopenharmony_ci 9205db71995Sopenharmony_ci // If not a meta-layer, simply add it. 9215db71995Sopenharmony_ci if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { 9225db71995Sopenharmony_ci err = loader_add_layer_properties_to_list(inst, output_list, layer_prop); 9235db71995Sopenharmony_ci if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err; 9245db71995Sopenharmony_ci err = loader_add_layer_properties_to_list(inst, expanded_output_list, layer_prop); 9255db71995Sopenharmony_ci if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err; 9265db71995Sopenharmony_ci } else { 9275db71995Sopenharmony_ci err = loader_add_meta_layer(inst, filters, layer_prop, output_list, expanded_output_list, source_list, NULL); 9285db71995Sopenharmony_ci if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err; 9295db71995Sopenharmony_ci } 9305db71995Sopenharmony_ci } 9315db71995Sopenharmony_ci 9325db71995Sopenharmony_ci return err; 9335db71995Sopenharmony_ci} 9345db71995Sopenharmony_ci 9355db71995Sopenharmony_ci// Determine if the provided implicit layer should be enabled by querying the appropriate environmental variables. 9365db71995Sopenharmony_ci// For an implicit layer, at least a disable environment variable is required. 9375db71995Sopenharmony_cibool loader_implicit_layer_is_enabled(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters, 9385db71995Sopenharmony_ci const struct loader_layer_properties *prop) { 9395db71995Sopenharmony_ci bool enable = false; 9405db71995Sopenharmony_ci bool forced_disabled = false; 9415db71995Sopenharmony_ci bool forced_enabled = false; 9425db71995Sopenharmony_ci 9435db71995Sopenharmony_ci if ((filters->disable_filter.disable_all || filters->disable_filter.disable_all_implicit || 9445db71995Sopenharmony_ci check_name_matches_filter_environment_var(prop->info.layerName, &filters->disable_filter.additional_filters)) && 9455db71995Sopenharmony_ci !check_name_matches_filter_environment_var(prop->info.layerName, &filters->allow_filter)) { 9465db71995Sopenharmony_ci forced_disabled = true; 9475db71995Sopenharmony_ci } 9485db71995Sopenharmony_ci if (check_name_matches_filter_environment_var(prop->info.layerName, &filters->enable_filter)) { 9495db71995Sopenharmony_ci forced_enabled = true; 9505db71995Sopenharmony_ci } 9515db71995Sopenharmony_ci 9525db71995Sopenharmony_ci // If no enable_environment variable is specified, this implicit layer is always be enabled by default. 9535db71995Sopenharmony_ci if (NULL == prop->enable_env_var.name) { 9545db71995Sopenharmony_ci enable = true; 9555db71995Sopenharmony_ci } else { 9565db71995Sopenharmony_ci char *env_value = loader_getenv(prop->enable_env_var.name, inst); 9575db71995Sopenharmony_ci if (env_value && !strcmp(prop->enable_env_var.value, env_value)) { 9585db71995Sopenharmony_ci enable = true; 9595db71995Sopenharmony_ci } 9605db71995Sopenharmony_ci 9615db71995Sopenharmony_ci // Otherwise, only enable this layer if the enable environment variable is defined 9625db71995Sopenharmony_ci loader_free_getenv(env_value, inst); 9635db71995Sopenharmony_ci } 9645db71995Sopenharmony_ci 9655db71995Sopenharmony_ci if (forced_enabled) { 9665db71995Sopenharmony_ci // Only report a message that we've forced on a layer if it wouldn't have been enabled 9675db71995Sopenharmony_ci // normally. 9685db71995Sopenharmony_ci if (!enable) { 9695db71995Sopenharmony_ci enable = true; 9705db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 9715db71995Sopenharmony_ci "Implicit layer \"%s\" forced enabled due to env var \'%s\'.", prop->info.layerName, 9725db71995Sopenharmony_ci VK_LAYERS_ENABLE_ENV_VAR); 9735db71995Sopenharmony_ci } 9745db71995Sopenharmony_ci } else if (enable && forced_disabled) { 9755db71995Sopenharmony_ci enable = false; 9765db71995Sopenharmony_ci // Report a message that we've forced off a layer if it would have been enabled normally. 9775db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 9785db71995Sopenharmony_ci "Implicit layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", prop->info.layerName, 9795db71995Sopenharmony_ci VK_LAYERS_DISABLE_ENV_VAR); 9805db71995Sopenharmony_ci return enable; 9815db71995Sopenharmony_ci } 9825db71995Sopenharmony_ci 9835db71995Sopenharmony_ci // The disable_environment has priority over everything else. If it is defined, the layer is always 9845db71995Sopenharmony_ci // disabled. 9855db71995Sopenharmony_ci if (NULL != prop->disable_env_var.name) { 9865db71995Sopenharmony_ci char *env_value = loader_getenv(prop->disable_env_var.name, inst); 9875db71995Sopenharmony_ci if (NULL != env_value) { 9885db71995Sopenharmony_ci enable = false; 9895db71995Sopenharmony_ci } 9905db71995Sopenharmony_ci loader_free_getenv(env_value, inst); 9915db71995Sopenharmony_ci } else if ((prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER) == 0) { 9925db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 9935db71995Sopenharmony_ci "Implicit layer \"%s\" missing disabled environment variable!", prop->info.layerName, VK_LAYERS_DISABLE_ENV_VAR); 9945db71995Sopenharmony_ci } 9955db71995Sopenharmony_ci 9965db71995Sopenharmony_ci // Enable this layer if it is included in the override layer 9975db71995Sopenharmony_ci if (inst != NULL && inst->override_layer_present) { 9985db71995Sopenharmony_ci struct loader_layer_properties *override = NULL; 9995db71995Sopenharmony_ci for (uint32_t i = 0; i < inst->instance_layer_list.count; ++i) { 10005db71995Sopenharmony_ci if (strcmp(inst->instance_layer_list.list[i].info.layerName, VK_OVERRIDE_LAYER_NAME) == 0) { 10015db71995Sopenharmony_ci override = &inst->instance_layer_list.list[i]; 10025db71995Sopenharmony_ci break; 10035db71995Sopenharmony_ci } 10045db71995Sopenharmony_ci } 10055db71995Sopenharmony_ci if (override != NULL) { 10065db71995Sopenharmony_ci for (uint32_t i = 0; i < override->component_layer_names.count; ++i) { 10075db71995Sopenharmony_ci if (strcmp(override->component_layer_names.list[i], prop->info.layerName) == 0) { 10085db71995Sopenharmony_ci enable = true; 10095db71995Sopenharmony_ci break; 10105db71995Sopenharmony_ci } 10115db71995Sopenharmony_ci } 10125db71995Sopenharmony_ci } 10135db71995Sopenharmony_ci } 10145db71995Sopenharmony_ci 10155db71995Sopenharmony_ci return enable; 10165db71995Sopenharmony_ci} 10175db71995Sopenharmony_ci 10185db71995Sopenharmony_ci// Check the individual implicit layer for the enable/disable environment variable settings. Only add it after 10195db71995Sopenharmony_ci// every check has passed indicating it should be used, including making sure a layer of the same name hasn't already been 10205db71995Sopenharmony_ci// added. 10215db71995Sopenharmony_ciVkResult loader_add_implicit_layer(const struct loader_instance *inst, struct loader_layer_properties *prop, 10225db71995Sopenharmony_ci const struct loader_envvar_all_filters *filters, struct loader_pointer_layer_list *target_list, 10235db71995Sopenharmony_ci struct loader_pointer_layer_list *expanded_target_list, 10245db71995Sopenharmony_ci const struct loader_layer_list *source_list) { 10255db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 10265db71995Sopenharmony_ci if (loader_implicit_layer_is_enabled(inst, filters, prop)) { 10275db71995Sopenharmony_ci if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { 10285db71995Sopenharmony_ci // Make sure the layer isn't already in the output_list, skip adding it if it is. 10295db71995Sopenharmony_ci if (loader_find_layer_name_in_list(&prop->info.layerName[0], target_list)) { 10305db71995Sopenharmony_ci return result; 10315db71995Sopenharmony_ci } 10325db71995Sopenharmony_ci 10335db71995Sopenharmony_ci result = loader_add_layer_properties_to_list(inst, target_list, prop); 10345db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 10355db71995Sopenharmony_ci if (NULL != expanded_target_list) { 10365db71995Sopenharmony_ci result = loader_add_layer_properties_to_list(inst, expanded_target_list, prop); 10375db71995Sopenharmony_ci } 10385db71995Sopenharmony_ci } else { 10395db71995Sopenharmony_ci result = loader_add_meta_layer(inst, filters, prop, target_list, expanded_target_list, source_list, NULL); 10405db71995Sopenharmony_ci } 10415db71995Sopenharmony_ci } 10425db71995Sopenharmony_ci return result; 10435db71995Sopenharmony_ci} 10445db71995Sopenharmony_ci 10455db71995Sopenharmony_ci// Add the component layers of a meta-layer to the active list of layers 10465db71995Sopenharmony_ciVkResult loader_add_meta_layer(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters, 10475db71995Sopenharmony_ci struct loader_layer_properties *prop, struct loader_pointer_layer_list *target_list, 10485db71995Sopenharmony_ci struct loader_pointer_layer_list *expanded_target_list, const struct loader_layer_list *source_list, 10495db71995Sopenharmony_ci bool *out_found_all_component_layers) { 10505db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 10515db71995Sopenharmony_ci bool found_all_component_layers = true; 10525db71995Sopenharmony_ci 10535db71995Sopenharmony_ci // We need to add all the individual component layers 10545db71995Sopenharmony_ci loader_api_version meta_layer_api_version = loader_make_version(prop->info.specVersion); 10555db71995Sopenharmony_ci for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) { 10565db71995Sopenharmony_ci struct loader_layer_properties *search_prop = 10575db71995Sopenharmony_ci loader_find_layer_property(prop->component_layer_names.list[comp_layer], source_list); 10585db71995Sopenharmony_ci if (search_prop != NULL) { 10595db71995Sopenharmony_ci loader_api_version search_prop_version = loader_make_version(prop->info.specVersion); 10605db71995Sopenharmony_ci if (!loader_check_version_meets_required(meta_layer_api_version, search_prop_version)) { 10615db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 10625db71995Sopenharmony_ci "Meta-layer \"%s\" API version %u.%u, component layer \"%s\" version %u.%u, may have " 10635db71995Sopenharmony_ci "incompatibilities (Policy #LLP_LAYER_8)!", 10645db71995Sopenharmony_ci prop->info.layerName, meta_layer_api_version.major, meta_layer_api_version.minor, 10655db71995Sopenharmony_ci search_prop->info.layerName, search_prop_version.major, search_prop_version.minor); 10665db71995Sopenharmony_ci } 10675db71995Sopenharmony_ci 10685db71995Sopenharmony_ci if (!loader_layer_is_available(inst, filters, search_prop)) { 10695db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 10705db71995Sopenharmony_ci "Meta Layer \"%s\" component layer \"%s\" disabled.", prop->info.layerName, search_prop->info.layerName); 10715db71995Sopenharmony_ci continue; 10725db71995Sopenharmony_ci } 10735db71995Sopenharmony_ci 10745db71995Sopenharmony_ci // If the component layer is itself an implicit layer, we need to do the implicit layer enable 10755db71995Sopenharmony_ci // checks 10765db71995Sopenharmony_ci if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) { 10775db71995Sopenharmony_ci result = loader_add_implicit_layer(inst, search_prop, filters, target_list, expanded_target_list, source_list); 10785db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 10795db71995Sopenharmony_ci } else { 10805db71995Sopenharmony_ci if (0 != (search_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { 10815db71995Sopenharmony_ci bool found_layers_in_component_meta_layer = true; 10825db71995Sopenharmony_ci result = loader_add_meta_layer(inst, filters, search_prop, target_list, expanded_target_list, source_list, 10835db71995Sopenharmony_ci &found_layers_in_component_meta_layer); 10845db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 10855db71995Sopenharmony_ci if (!found_layers_in_component_meta_layer) found_all_component_layers = false; 10865db71995Sopenharmony_ci } else if (!loader_find_layer_name_in_list(&search_prop->info.layerName[0], target_list)) { 10875db71995Sopenharmony_ci // Make sure the layer isn't already in the output_list, skip adding it if it is. 10885db71995Sopenharmony_ci result = loader_add_layer_properties_to_list(inst, target_list, search_prop); 10895db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 10905db71995Sopenharmony_ci if (NULL != expanded_target_list) { 10915db71995Sopenharmony_ci result = loader_add_layer_properties_to_list(inst, expanded_target_list, search_prop); 10925db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 10935db71995Sopenharmony_ci } 10945db71995Sopenharmony_ci } 10955db71995Sopenharmony_ci } 10965db71995Sopenharmony_ci } else { 10975db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 10985db71995Sopenharmony_ci "Failed to find layer name \"%s\" component layer \"%s\" to activate (Policy #LLP_LAYER_7)", 10995db71995Sopenharmony_ci prop->component_layer_names.list[comp_layer], prop->component_layer_names.list[comp_layer]); 11005db71995Sopenharmony_ci found_all_component_layers = false; 11015db71995Sopenharmony_ci } 11025db71995Sopenharmony_ci } 11035db71995Sopenharmony_ci 11045db71995Sopenharmony_ci // Add this layer to the overall target list (not the expanded one) 11055db71995Sopenharmony_ci if (found_all_component_layers) { 11065db71995Sopenharmony_ci result = loader_add_layer_properties_to_list(inst, target_list, prop); 11075db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 11085db71995Sopenharmony_ci // Write the result to out_found_all_component_layers in case this function is being recursed 11095db71995Sopenharmony_ci if (out_found_all_component_layers) *out_found_all_component_layers = found_all_component_layers; 11105db71995Sopenharmony_ci } 11115db71995Sopenharmony_ci 11125db71995Sopenharmony_ci return result; 11135db71995Sopenharmony_ci} 11145db71995Sopenharmony_ci 11155db71995Sopenharmony_ciVkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) { 11165db71995Sopenharmony_ci for (uint32_t i = 0; i < list->count; i++) { 11175db71995Sopenharmony_ci if (strcmp(name, list->list[i].extensionName) == 0) return &list->list[i]; 11185db71995Sopenharmony_ci } 11195db71995Sopenharmony_ci return NULL; 11205db71995Sopenharmony_ci} 11215db71995Sopenharmony_ci 11225db71995Sopenharmony_ciVkExtensionProperties *get_dev_extension_property(const char *name, const struct loader_device_extension_list *list) { 11235db71995Sopenharmony_ci for (uint32_t i = 0; i < list->count; i++) { 11245db71995Sopenharmony_ci if (strcmp(name, list->list[i].props.extensionName) == 0) return &list->list[i].props; 11255db71995Sopenharmony_ci } 11265db71995Sopenharmony_ci return NULL; 11275db71995Sopenharmony_ci} 11285db71995Sopenharmony_ci 11295db71995Sopenharmony_ci// For Instance extensions implemented within the loader (i.e. DEBUG_REPORT 11305db71995Sopenharmony_ci// the extension must provide two entry points for the loader to use: 11315db71995Sopenharmony_ci// - "trampoline" entry point - this is the address returned by GetProcAddr 11325db71995Sopenharmony_ci// and will always do what's necessary to support a 11335db71995Sopenharmony_ci// global call. 11345db71995Sopenharmony_ci// - "terminator" function - this function will be put at the end of the 11355db71995Sopenharmony_ci// instance chain and will contain the necessary logic 11365db71995Sopenharmony_ci// to call / process the extension for the appropriate 11375db71995Sopenharmony_ci// ICDs that are available. 11385db71995Sopenharmony_ci// There is no generic mechanism for including these functions, the references 11395db71995Sopenharmony_ci// must be placed into the appropriate loader entry points. 11405db71995Sopenharmony_ci// GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr 11415db71995Sopenharmony_ci// requests 11425db71995Sopenharmony_ci// loader_coalesce_extensions(void) - add extension records to the list of global 11435db71995Sopenharmony_ci// extension available to the app. 11445db71995Sopenharmony_ci// instance_disp - add function pointer for terminator function 11455db71995Sopenharmony_ci// to this array. 11465db71995Sopenharmony_ci// The extension itself should be in a separate file that will be linked directly 11475db71995Sopenharmony_ci// with the loader. 11485db71995Sopenharmony_ciVkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list, 11495db71995Sopenharmony_ci struct loader_extension_list *inst_exts) { 11505db71995Sopenharmony_ci struct loader_extension_list icd_exts; 11515db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 11525db71995Sopenharmony_ci char *env_value; 11535db71995Sopenharmony_ci bool filter_extensions = true; 11545db71995Sopenharmony_ci 11555db71995Sopenharmony_ci // Check if a user wants to disable the instance extension filtering behavior 11565db71995Sopenharmony_ci env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst); 11575db71995Sopenharmony_ci if (NULL != env_value && atoi(env_value) != 0) { 11585db71995Sopenharmony_ci filter_extensions = false; 11595db71995Sopenharmony_ci } 11605db71995Sopenharmony_ci loader_free_getenv(env_value, inst); 11615db71995Sopenharmony_ci 11625db71995Sopenharmony_ci // traverse scanned icd list adding non-duplicate extensions to the list 11635db71995Sopenharmony_ci for (uint32_t i = 0; i < icd_tramp_list->count; i++) { 11645db71995Sopenharmony_ci res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties)); 11655db71995Sopenharmony_ci if (VK_SUCCESS != res) { 11665db71995Sopenharmony_ci goto out; 11675db71995Sopenharmony_ci } 11685db71995Sopenharmony_ci res = loader_add_instance_extensions(inst, icd_tramp_list->scanned_list[i].EnumerateInstanceExtensionProperties, 11695db71995Sopenharmony_ci icd_tramp_list->scanned_list[i].lib_name, &icd_exts); 11705db71995Sopenharmony_ci if (VK_SUCCESS == res) { 11715db71995Sopenharmony_ci if (filter_extensions) { 11725db71995Sopenharmony_ci // Remove any extensions not recognized by the loader 11735db71995Sopenharmony_ci for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) { 11745db71995Sopenharmony_ci // See if the extension is in the list of supported extensions 11755db71995Sopenharmony_ci bool found = false; 11765db71995Sopenharmony_ci for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL; k++) { 11775db71995Sopenharmony_ci if (strcmp(icd_exts.list[j].extensionName, LOADER_INSTANCE_EXTENSIONS[k]) == 0) { 11785db71995Sopenharmony_ci found = true; 11795db71995Sopenharmony_ci break; 11805db71995Sopenharmony_ci } 11815db71995Sopenharmony_ci } 11825db71995Sopenharmony_ci 11835db71995Sopenharmony_ci // If it isn't in the list, remove it 11845db71995Sopenharmony_ci if (!found) { 11855db71995Sopenharmony_ci for (uint32_t k = j + 1; k < icd_exts.count; k++) { 11865db71995Sopenharmony_ci icd_exts.list[k - 1] = icd_exts.list[k]; 11875db71995Sopenharmony_ci } 11885db71995Sopenharmony_ci --icd_exts.count; 11895db71995Sopenharmony_ci --j; 11905db71995Sopenharmony_ci } 11915db71995Sopenharmony_ci } 11925db71995Sopenharmony_ci } 11935db71995Sopenharmony_ci 11945db71995Sopenharmony_ci res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list); 11955db71995Sopenharmony_ci } 11965db71995Sopenharmony_ci loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts); 11975db71995Sopenharmony_ci if (VK_SUCCESS != res) { 11985db71995Sopenharmony_ci goto out; 11995db71995Sopenharmony_ci } 12005db71995Sopenharmony_ci }; 12015db71995Sopenharmony_ci 12025db71995Sopenharmony_ci // Traverse loader's extensions, adding non-duplicate extensions to the list 12035db71995Sopenharmony_ci res = add_debug_extensions_to_ext_list(inst, inst_exts); 12045db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 12055db71995Sopenharmony_ci goto out; 12065db71995Sopenharmony_ci } 12075db71995Sopenharmony_ci const VkExtensionProperties portability_enumeration_extension_info[] = { 12085db71995Sopenharmony_ci {VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION}}; 12095db71995Sopenharmony_ci 12105db71995Sopenharmony_ci // Add VK_KHR_portability_subset 12115db71995Sopenharmony_ci res = loader_add_to_ext_list(inst, inst_exts, sizeof(portability_enumeration_extension_info) / sizeof(VkExtensionProperties), 12125db71995Sopenharmony_ci portability_enumeration_extension_info); 12135db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 12145db71995Sopenharmony_ci goto out; 12155db71995Sopenharmony_ci } 12165db71995Sopenharmony_ci 12175db71995Sopenharmony_ci const VkExtensionProperties direct_driver_loading_extension_info[] = { 12185db71995Sopenharmony_ci {VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME, VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION}}; 12195db71995Sopenharmony_ci 12205db71995Sopenharmony_ci // Add VK_LUNARG_direct_driver_loading 12215db71995Sopenharmony_ci res = loader_add_to_ext_list(inst, inst_exts, sizeof(direct_driver_loading_extension_info) / sizeof(VkExtensionProperties), 12225db71995Sopenharmony_ci direct_driver_loading_extension_info); 12235db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 12245db71995Sopenharmony_ci goto out; 12255db71995Sopenharmony_ci } 12265db71995Sopenharmony_ci 12275db71995Sopenharmony_ciout: 12285db71995Sopenharmony_ci return res; 12295db71995Sopenharmony_ci} 12305db71995Sopenharmony_ci 12315db71995Sopenharmony_cistruct loader_icd_term *loader_get_icd_and_device(const void *device, struct loader_device **found_dev, uint32_t *icd_index) { 12325db71995Sopenharmony_ci VkLayerDispatchTable *dispatch_table_device = loader_get_dispatch(device); 12335db71995Sopenharmony_ci if (NULL == dispatch_table_device) { 12345db71995Sopenharmony_ci *found_dev = NULL; 12355db71995Sopenharmony_ci return NULL; 12365db71995Sopenharmony_ci } 12375db71995Sopenharmony_ci loader_platform_thread_lock_mutex(&loader_global_instance_list_lock); 12385db71995Sopenharmony_ci *found_dev = NULL; 12395db71995Sopenharmony_ci 12405db71995Sopenharmony_ci for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 12415db71995Sopenharmony_ci uint32_t index = 0; 12425db71995Sopenharmony_ci for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) { 12435db71995Sopenharmony_ci for (struct loader_device *dev = icd_term->logical_device_list; dev; dev = dev->next) { 12445db71995Sopenharmony_ci // Value comparison of device prevents object wrapping by layers 12455db71995Sopenharmony_ci if (loader_get_dispatch(dev->icd_device) == dispatch_table_device || 12465db71995Sopenharmony_ci (dev->chain_device != VK_NULL_HANDLE && loader_get_dispatch(dev->chain_device) == dispatch_table_device)) { 12475db71995Sopenharmony_ci *found_dev = dev; 12485db71995Sopenharmony_ci if (NULL != icd_index) { 12495db71995Sopenharmony_ci *icd_index = index; 12505db71995Sopenharmony_ci } 12515db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock); 12525db71995Sopenharmony_ci return icd_term; 12535db71995Sopenharmony_ci } 12545db71995Sopenharmony_ci } 12555db71995Sopenharmony_ci index++; 12565db71995Sopenharmony_ci } 12575db71995Sopenharmony_ci } 12585db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock); 12595db71995Sopenharmony_ci return NULL; 12605db71995Sopenharmony_ci} 12615db71995Sopenharmony_ci 12625db71995Sopenharmony_civoid loader_destroy_logical_device(struct loader_device *dev, const VkAllocationCallbacks *pAllocator) { 12635db71995Sopenharmony_ci if (pAllocator) { 12645db71995Sopenharmony_ci dev->alloc_callbacks = *pAllocator; 12655db71995Sopenharmony_ci } 12665db71995Sopenharmony_ci loader_device_heap_free(dev, dev); 12675db71995Sopenharmony_ci} 12685db71995Sopenharmony_ci 12695db71995Sopenharmony_cistruct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) { 12705db71995Sopenharmony_ci struct loader_device *new_dev; 12715db71995Sopenharmony_ci new_dev = loader_calloc(pAllocator, sizeof(struct loader_device), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 12725db71995Sopenharmony_ci 12735db71995Sopenharmony_ci if (!new_dev) { 12745db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_logical_device: Failed to alloc struct loader_device"); 12755db71995Sopenharmony_ci return NULL; 12765db71995Sopenharmony_ci } 12775db71995Sopenharmony_ci 12785db71995Sopenharmony_ci new_dev->loader_dispatch.core_dispatch.magic = DEVICE_DISP_TABLE_MAGIC_NUMBER; 12795db71995Sopenharmony_ci 12805db71995Sopenharmony_ci if (pAllocator) { 12815db71995Sopenharmony_ci new_dev->alloc_callbacks = *pAllocator; 12825db71995Sopenharmony_ci } 12835db71995Sopenharmony_ci 12845db71995Sopenharmony_ci return new_dev; 12855db71995Sopenharmony_ci} 12865db71995Sopenharmony_ci 12875db71995Sopenharmony_civoid loader_add_logical_device(struct loader_icd_term *icd_term, struct loader_device *dev) { 12885db71995Sopenharmony_ci dev->next = icd_term->logical_device_list; 12895db71995Sopenharmony_ci icd_term->logical_device_list = dev; 12905db71995Sopenharmony_ci} 12915db71995Sopenharmony_ci 12925db71995Sopenharmony_civoid loader_remove_logical_device(struct loader_icd_term *icd_term, struct loader_device *found_dev, 12935db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator) { 12945db71995Sopenharmony_ci struct loader_device *dev, *prev_dev; 12955db71995Sopenharmony_ci 12965db71995Sopenharmony_ci if (!icd_term || !found_dev) return; 12975db71995Sopenharmony_ci 12985db71995Sopenharmony_ci prev_dev = NULL; 12995db71995Sopenharmony_ci dev = icd_term->logical_device_list; 13005db71995Sopenharmony_ci while (dev && dev != found_dev) { 13015db71995Sopenharmony_ci prev_dev = dev; 13025db71995Sopenharmony_ci dev = dev->next; 13035db71995Sopenharmony_ci } 13045db71995Sopenharmony_ci 13055db71995Sopenharmony_ci if (prev_dev) 13065db71995Sopenharmony_ci prev_dev->next = found_dev->next; 13075db71995Sopenharmony_ci else 13085db71995Sopenharmony_ci icd_term->logical_device_list = found_dev->next; 13095db71995Sopenharmony_ci loader_destroy_logical_device(found_dev, pAllocator); 13105db71995Sopenharmony_ci} 13115db71995Sopenharmony_ci 13125db71995Sopenharmony_civoid loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term, 13135db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator) { 13145db71995Sopenharmony_ci ptr_inst->total_icd_count--; 13155db71995Sopenharmony_ci for (struct loader_device *dev = icd_term->logical_device_list; dev;) { 13165db71995Sopenharmony_ci struct loader_device *next_dev = dev->next; 13175db71995Sopenharmony_ci loader_destroy_logical_device(dev, pAllocator); 13185db71995Sopenharmony_ci dev = next_dev; 13195db71995Sopenharmony_ci } 13205db71995Sopenharmony_ci 13215db71995Sopenharmony_ci loader_instance_heap_free(ptr_inst, icd_term); 13225db71995Sopenharmony_ci} 13235db71995Sopenharmony_ci 13245db71995Sopenharmony_cistruct loader_icd_term *loader_icd_add(struct loader_instance *ptr_inst, const struct loader_scanned_icd *scanned_icd) { 13255db71995Sopenharmony_ci struct loader_icd_term *icd_term; 13265db71995Sopenharmony_ci 13275db71995Sopenharmony_ci icd_term = loader_instance_heap_calloc(ptr_inst, sizeof(struct loader_icd_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 13285db71995Sopenharmony_ci if (!icd_term) { 13295db71995Sopenharmony_ci return NULL; 13305db71995Sopenharmony_ci } 13315db71995Sopenharmony_ci 13325db71995Sopenharmony_ci icd_term->scanned_icd = scanned_icd; 13335db71995Sopenharmony_ci icd_term->this_instance = ptr_inst; 13345db71995Sopenharmony_ci 13355db71995Sopenharmony_ci // Prepend to the list 13365db71995Sopenharmony_ci icd_term->next = ptr_inst->icd_terms; 13375db71995Sopenharmony_ci ptr_inst->icd_terms = icd_term; 13385db71995Sopenharmony_ci ptr_inst->total_icd_count++; 13395db71995Sopenharmony_ci 13405db71995Sopenharmony_ci return icd_term; 13415db71995Sopenharmony_ci} 13425db71995Sopenharmony_ci 13435db71995Sopenharmony_ci// Determine the ICD interface version to use. 13445db71995Sopenharmony_ci// @param icd 13455db71995Sopenharmony_ci// @param pVersion Output parameter indicating which version to use or 0 if 13465db71995Sopenharmony_ci// the negotiation API is not supported by the ICD 13475db71995Sopenharmony_ci// @return bool indicating true if the selected interface version is supported 13485db71995Sopenharmony_ci// by the loader, false indicates the version is not supported 13495db71995Sopenharmony_cibool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version, uint32_t *pVersion) { 13505db71995Sopenharmony_ci if (fp_negotiate_icd_version == NULL) { 13515db71995Sopenharmony_ci // ICD does not support the negotiation API, it supports version 0 or 1 13525db71995Sopenharmony_ci // calling code must determine if it is version 0 or 1 13535db71995Sopenharmony_ci *pVersion = 0; 13545db71995Sopenharmony_ci } else { 13555db71995Sopenharmony_ci // ICD supports the negotiation API, so call it with the loader's 13565db71995Sopenharmony_ci // latest version supported 13575db71995Sopenharmony_ci *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION; 13585db71995Sopenharmony_ci VkResult result = fp_negotiate_icd_version(pVersion); 13595db71995Sopenharmony_ci 13605db71995Sopenharmony_ci if (result == VK_ERROR_INCOMPATIBLE_DRIVER) { 13615db71995Sopenharmony_ci // ICD no longer supports the loader's latest interface version so 13625db71995Sopenharmony_ci // fail loading the ICD 13635db71995Sopenharmony_ci return false; 13645db71995Sopenharmony_ci } 13655db71995Sopenharmony_ci } 13665db71995Sopenharmony_ci 13675db71995Sopenharmony_ci#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0 13685db71995Sopenharmony_ci if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) { 13695db71995Sopenharmony_ci // Loader no longer supports the ICD's latest interface version so fail 13705db71995Sopenharmony_ci // loading the ICD 13715db71995Sopenharmony_ci return false; 13725db71995Sopenharmony_ci } 13735db71995Sopenharmony_ci#endif 13745db71995Sopenharmony_ci return true; 13755db71995Sopenharmony_ci} 13765db71995Sopenharmony_ci 13775db71995Sopenharmony_civoid loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) { 13785db71995Sopenharmony_ci if (0 != icd_tramp_list->capacity && icd_tramp_list->scanned_list) { 13795db71995Sopenharmony_ci for (uint32_t i = 0; i < icd_tramp_list->count; i++) { 13805db71995Sopenharmony_ci if (icd_tramp_list->scanned_list[i].handle) { 13815db71995Sopenharmony_ci loader_platform_close_library(icd_tramp_list->scanned_list[i].handle); 13825db71995Sopenharmony_ci icd_tramp_list->scanned_list[i].handle = NULL; 13835db71995Sopenharmony_ci } 13845db71995Sopenharmony_ci loader_instance_heap_free(inst, icd_tramp_list->scanned_list[i].lib_name); 13855db71995Sopenharmony_ci } 13865db71995Sopenharmony_ci loader_instance_heap_free(inst, icd_tramp_list->scanned_list); 13875db71995Sopenharmony_ci } 13885db71995Sopenharmony_ci memset(icd_tramp_list, 0, sizeof(struct loader_icd_tramp_list)); 13895db71995Sopenharmony_ci} 13905db71995Sopenharmony_ci 13915db71995Sopenharmony_ciVkResult loader_scanned_icd_init(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) { 13925db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 13935db71995Sopenharmony_ci loader_scanned_icd_clear(inst, icd_tramp_list); 13945db71995Sopenharmony_ci icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd); 13955db71995Sopenharmony_ci icd_tramp_list->scanned_list = loader_instance_heap_alloc(inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 13965db71995Sopenharmony_ci if (NULL == icd_tramp_list->scanned_list) { 13975db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 13985db71995Sopenharmony_ci "loader_scanned_icd_init: Realloc failed for layer list when attempting to add new layer"); 13995db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 14005db71995Sopenharmony_ci } 14015db71995Sopenharmony_ci return res; 14025db71995Sopenharmony_ci} 14035db71995Sopenharmony_ci 14045db71995Sopenharmony_ciVkResult loader_add_direct_driver(const struct loader_instance *inst, uint32_t index, 14055db71995Sopenharmony_ci const VkDirectDriverLoadingInfoLUNARG *pDriver, struct loader_icd_tramp_list *icd_tramp_list) { 14065db71995Sopenharmony_ci // Assume pDriver is valid, since there is no real way to check it. Calling code should make sure the pointer to the array 14075db71995Sopenharmony_ci // of VkDirectDriverLoadingInfoLUNARG structures is non-null. 14085db71995Sopenharmony_ci if (NULL == pDriver->pfnGetInstanceProcAddr) { 14095db71995Sopenharmony_ci loader_log( 14105db71995Sopenharmony_ci inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 14115db71995Sopenharmony_ci "loader_add_direct_driver: VkDirectDriverLoadingInfoLUNARG structure at index %d contains a NULL pointer for the " 14125db71995Sopenharmony_ci "pfnGetInstanceProcAddr member, skipping.", 14135db71995Sopenharmony_ci index); 14145db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 14155db71995Sopenharmony_ci } 14165db71995Sopenharmony_ci 14175db71995Sopenharmony_ci PFN_vkGetInstanceProcAddr fp_get_proc_addr = pDriver->pfnGetInstanceProcAddr; 14185db71995Sopenharmony_ci PFN_vkCreateInstance fp_create_inst = NULL; 14195db71995Sopenharmony_ci PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props = NULL; 14205db71995Sopenharmony_ci PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL; 14215db71995Sopenharmony_ci PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version = NULL; 14225db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 14235db71995Sopenharmony_ci PFN_vk_icdEnumerateAdapterPhysicalDevices fp_enum_dxgi_adapter_phys_devs = NULL; 14245db71995Sopenharmony_ci#endif 14255db71995Sopenharmony_ci struct loader_scanned_icd *new_scanned_icd; 14265db71995Sopenharmony_ci uint32_t interface_version = 0; 14275db71995Sopenharmony_ci 14285db71995Sopenharmony_ci // Try to get the negotiate ICD interface version function 14295db71995Sopenharmony_ci fp_negotiate_icd_version = (PFN_vk_icdNegotiateLoaderICDInterfaceVersion)pDriver->pfnGetInstanceProcAddr( 14305db71995Sopenharmony_ci NULL, "vk_icdNegotiateLoaderICDInterfaceVersion"); 14315db71995Sopenharmony_ci 14325db71995Sopenharmony_ci if (NULL == fp_negotiate_icd_version) { 14335db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 14345db71995Sopenharmony_ci "loader_add_direct_driver: Could not get 'vk_icdNegotiateLoaderICDInterfaceVersion' from " 14355db71995Sopenharmony_ci "VkDirectDriverLoadingInfoLUNARG structure at " 14365db71995Sopenharmony_ci "index %d, skipping.", 14375db71995Sopenharmony_ci index); 14385db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 14395db71995Sopenharmony_ci } 14405db71995Sopenharmony_ci 14415db71995Sopenharmony_ci if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_version)) { 14425db71995Sopenharmony_ci loader_log( 14435db71995Sopenharmony_ci inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 14445db71995Sopenharmony_ci "loader_add_direct_driver: VkDirectDriverLoadingInfoLUNARG structure at index %d supports interface version %d, " 14455db71995Sopenharmony_ci "which is incompatible with the Loader Driver Interface version that supports the VK_LUNARG_direct_driver_loading " 14465db71995Sopenharmony_ci "extension, skipping.", 14475db71995Sopenharmony_ci index, interface_version); 14485db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 14495db71995Sopenharmony_ci } 14505db71995Sopenharmony_ci 14515db71995Sopenharmony_ci if (interface_version < 7) { 14525db71995Sopenharmony_ci loader_log( 14535db71995Sopenharmony_ci inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 14545db71995Sopenharmony_ci "loader_add_direct_driver: VkDirectDriverLoadingInfoLUNARG structure at index %d supports interface version %d, " 14555db71995Sopenharmony_ci "which is incompatible with the Loader Driver Interface version that supports the VK_LUNARG_direct_driver_loading " 14565db71995Sopenharmony_ci "extension, skipping.", 14575db71995Sopenharmony_ci index, interface_version); 14585db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 14595db71995Sopenharmony_ci } 14605db71995Sopenharmony_ci 14615db71995Sopenharmony_ci fp_create_inst = (PFN_vkCreateInstance)pDriver->pfnGetInstanceProcAddr(NULL, "vkCreateInstance"); 14625db71995Sopenharmony_ci if (NULL == fp_create_inst) { 14635db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 14645db71995Sopenharmony_ci "loader_add_direct_driver: Could not get 'vkCreateInstance' from VkDirectDriverLoadingInfoLUNARG structure at " 14655db71995Sopenharmony_ci "index %d, skipping.", 14665db71995Sopenharmony_ci index); 14675db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 14685db71995Sopenharmony_ci } 14695db71995Sopenharmony_ci fp_get_inst_ext_props = 14705db71995Sopenharmony_ci (PFN_vkEnumerateInstanceExtensionProperties)pDriver->pfnGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); 14715db71995Sopenharmony_ci if (NULL == fp_get_inst_ext_props) { 14725db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 14735db71995Sopenharmony_ci "loader_add_direct_driver: Could not get 'vkEnumerateInstanceExtensionProperties' from " 14745db71995Sopenharmony_ci "VkDirectDriverLoadingInfoLUNARG structure at index %d, skipping.", 14755db71995Sopenharmony_ci index); 14765db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 14775db71995Sopenharmony_ci } 14785db71995Sopenharmony_ci 14795db71995Sopenharmony_ci fp_get_phys_dev_proc_addr = 14805db71995Sopenharmony_ci (PFN_vk_icdGetPhysicalDeviceProcAddr)pDriver->pfnGetInstanceProcAddr(NULL, "vk_icdGetPhysicalDeviceProcAddr"); 14815db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 14825db71995Sopenharmony_ci // Query "vk_icdEnumerateAdapterPhysicalDevices" with vk_icdGetInstanceProcAddr if the library reports interface version 14835db71995Sopenharmony_ci // 7 or greater, otherwise fallback to loading it from the platform dynamic linker 14845db71995Sopenharmony_ci fp_enum_dxgi_adapter_phys_devs = 14855db71995Sopenharmony_ci (PFN_vk_icdEnumerateAdapterPhysicalDevices)pDriver->pfnGetInstanceProcAddr(NULL, "vk_icdEnumerateAdapterPhysicalDevices"); 14865db71995Sopenharmony_ci#endif 14875db71995Sopenharmony_ci 14885db71995Sopenharmony_ci // check for enough capacity 14895db71995Sopenharmony_ci if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) { 14905db71995Sopenharmony_ci void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity, 14915db71995Sopenharmony_ci icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 14925db71995Sopenharmony_ci if (NULL == new_ptr) { 14935db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 14945db71995Sopenharmony_ci "loader_add_direct_driver: Realloc failed on icd library list for ICD index %u", index); 14955db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 14965db71995Sopenharmony_ci } 14975db71995Sopenharmony_ci icd_tramp_list->scanned_list = new_ptr; 14985db71995Sopenharmony_ci 14995db71995Sopenharmony_ci // double capacity 15005db71995Sopenharmony_ci icd_tramp_list->capacity *= 2; 15015db71995Sopenharmony_ci } 15025db71995Sopenharmony_ci 15035db71995Sopenharmony_ci // Driver must be 1.1 to support version 7 15045db71995Sopenharmony_ci uint32_t api_version = VK_API_VERSION_1_1; 15055db71995Sopenharmony_ci PFN_vkEnumerateInstanceVersion icd_enumerate_instance_version = 15065db71995Sopenharmony_ci (PFN_vkEnumerateInstanceVersion)pDriver->pfnGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion"); 15075db71995Sopenharmony_ci 15085db71995Sopenharmony_ci if (icd_enumerate_instance_version) { 15095db71995Sopenharmony_ci VkResult res = icd_enumerate_instance_version(&api_version); 15105db71995Sopenharmony_ci if (res != VK_SUCCESS) { 15115db71995Sopenharmony_ci return res; 15125db71995Sopenharmony_ci } 15135db71995Sopenharmony_ci } 15145db71995Sopenharmony_ci 15155db71995Sopenharmony_ci new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]); 15165db71995Sopenharmony_ci new_scanned_icd->handle = NULL; 15175db71995Sopenharmony_ci new_scanned_icd->api_version = api_version; 15185db71995Sopenharmony_ci new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr; 15195db71995Sopenharmony_ci new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr; 15205db71995Sopenharmony_ci new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props; 15215db71995Sopenharmony_ci new_scanned_icd->CreateInstance = fp_create_inst; 15225db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 15235db71995Sopenharmony_ci new_scanned_icd->EnumerateAdapterPhysicalDevices = fp_enum_dxgi_adapter_phys_devs; 15245db71995Sopenharmony_ci#endif 15255db71995Sopenharmony_ci new_scanned_icd->interface_version = interface_version; 15265db71995Sopenharmony_ci 15275db71995Sopenharmony_ci new_scanned_icd->lib_name = NULL; 15285db71995Sopenharmony_ci icd_tramp_list->count++; 15295db71995Sopenharmony_ci 15305db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 15315db71995Sopenharmony_ci "loader_add_direct_driver: Adding driver found in index %d of " 15325db71995Sopenharmony_ci "VkDirectDriverLoadingListLUNARG::pDrivers structure. pfnGetInstanceProcAddr was set to %p", 15335db71995Sopenharmony_ci index, pDriver->pfnGetInstanceProcAddr); 15345db71995Sopenharmony_ci 15355db71995Sopenharmony_ci return VK_SUCCESS; 15365db71995Sopenharmony_ci} 15375db71995Sopenharmony_ci 15385db71995Sopenharmony_ci// Search through VkInstanceCreateInfo's pNext chain for any drivers from the direct driver loading extension and load them. 15395db71995Sopenharmony_ciVkResult loader_scan_for_direct_drivers(const struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo, 15405db71995Sopenharmony_ci struct loader_icd_tramp_list *icd_tramp_list, bool *direct_driver_loading_exclusive_mode) { 15415db71995Sopenharmony_ci if (NULL == pCreateInfo) { 15425db71995Sopenharmony_ci // Don't do this logic unless we are being called from vkCreateInstance, when pCreateInfo will be non-null 15435db71995Sopenharmony_ci return VK_SUCCESS; 15445db71995Sopenharmony_ci } 15455db71995Sopenharmony_ci bool direct_driver_loading_enabled = false; 15465db71995Sopenharmony_ci // Try to if VK_LUNARG_direct_driver_loading is enabled and if we are using it exclusively 15475db71995Sopenharmony_ci // Skip this step if inst is NULL, aka when this function is being called before instance creation 15485db71995Sopenharmony_ci if (inst != NULL && pCreateInfo->ppEnabledExtensionNames && pCreateInfo->enabledExtensionCount > 0) { 15495db71995Sopenharmony_ci // Look through the enabled extension list, make sure VK_LUNARG_direct_driver_loading is present 15505db71995Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 15515db71995Sopenharmony_ci if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME) == 0) { 15525db71995Sopenharmony_ci direct_driver_loading_enabled = true; 15535db71995Sopenharmony_ci break; 15545db71995Sopenharmony_ci } 15555db71995Sopenharmony_ci } 15565db71995Sopenharmony_ci } 15575db71995Sopenharmony_ci const VkDirectDriverLoadingListLUNARG *ddl_list = NULL; 15585db71995Sopenharmony_ci // Find the VkDirectDriverLoadingListLUNARG struct in the pNext chain of vkInstanceCreateInfo 15595db71995Sopenharmony_ci const VkBaseOutStructure *chain = pCreateInfo->pNext; 15605db71995Sopenharmony_ci while (chain) { 15615db71995Sopenharmony_ci if (chain->sType == VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG) { 15625db71995Sopenharmony_ci ddl_list = (VkDirectDriverLoadingListLUNARG *)chain; 15635db71995Sopenharmony_ci break; 15645db71995Sopenharmony_ci } 15655db71995Sopenharmony_ci chain = (const VkBaseOutStructure *)chain->pNext; 15665db71995Sopenharmony_ci } 15675db71995Sopenharmony_ci if (NULL == ddl_list) { 15685db71995Sopenharmony_ci if (direct_driver_loading_enabled) { 15695db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 15705db71995Sopenharmony_ci "loader_scan_for_direct_drivers: The VK_LUNARG_direct_driver_loading extension was enabled but the " 15715db71995Sopenharmony_ci "pNext chain of " 15725db71995Sopenharmony_ci "VkInstanceCreateInfo did not contain the " 15735db71995Sopenharmony_ci "VkDirectDriverLoadingListLUNARG structure."); 15745db71995Sopenharmony_ci } 15755db71995Sopenharmony_ci // Always want to exit early if there was no VkDirectDriverLoadingListLUNARG in the pNext chain 15765db71995Sopenharmony_ci return VK_SUCCESS; 15775db71995Sopenharmony_ci } 15785db71995Sopenharmony_ci 15795db71995Sopenharmony_ci if (!direct_driver_loading_enabled) { 15805db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 15815db71995Sopenharmony_ci "loader_scan_for_direct_drivers: The pNext chain of VkInstanceCreateInfo contained the " 15825db71995Sopenharmony_ci "VkDirectDriverLoadingListLUNARG structure, but the VK_LUNARG_direct_driver_loading extension was " 15835db71995Sopenharmony_ci "not enabled."); 15845db71995Sopenharmony_ci return VK_SUCCESS; 15855db71995Sopenharmony_ci } 15865db71995Sopenharmony_ci // If we are using exclusive mode, skip looking for any more drivers from system or environment variables 15875db71995Sopenharmony_ci if (ddl_list->mode == VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG) { 15885db71995Sopenharmony_ci *direct_driver_loading_exclusive_mode = true; 15895db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 15905db71995Sopenharmony_ci "loader_scan_for_direct_drivers: The VK_LUNARG_direct_driver_loading extension is active and specified " 15915db71995Sopenharmony_ci "VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG, skipping system and environment " 15925db71995Sopenharmony_ci "variable driver search mechanisms."); 15935db71995Sopenharmony_ci } 15945db71995Sopenharmony_ci if (NULL == ddl_list->pDrivers) { 15955db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 15965db71995Sopenharmony_ci "loader_scan_for_direct_drivers: The VkDirectDriverLoadingListLUNARG structure in the pNext chain of " 15975db71995Sopenharmony_ci "VkInstanceCreateInfo has a NULL pDrivers member."); 15985db71995Sopenharmony_ci return VK_SUCCESS; 15995db71995Sopenharmony_ci } 16005db71995Sopenharmony_ci if (ddl_list->driverCount == 0) { 16015db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 16025db71995Sopenharmony_ci "loader_scan_for_direct_drivers: The VkDirectDriverLoadingListLUNARG structure in the pNext chain of " 16035db71995Sopenharmony_ci "VkInstanceCreateInfo has a non-null pDrivers member but a driverCount member with a value " 16045db71995Sopenharmony_ci "of zero."); 16055db71995Sopenharmony_ci return VK_SUCCESS; 16065db71995Sopenharmony_ci } 16075db71995Sopenharmony_ci // Go through all VkDirectDriverLoadingInfoLUNARG entries and add each driver 16085db71995Sopenharmony_ci // Because icd_tramp's are prepended, this will result in the drivers appearing at the end 16095db71995Sopenharmony_ci for (uint32_t i = 0; i < ddl_list->driverCount; i++) { 16105db71995Sopenharmony_ci VkResult res = loader_add_direct_driver(inst, i, &ddl_list->pDrivers[i], icd_tramp_list); 16115db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 16125db71995Sopenharmony_ci return res; 16135db71995Sopenharmony_ci } 16145db71995Sopenharmony_ci } 16155db71995Sopenharmony_ci 16165db71995Sopenharmony_ci return VK_SUCCESS; 16175db71995Sopenharmony_ci} 16185db71995Sopenharmony_ci 16195db71995Sopenharmony_ciVkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list, 16205db71995Sopenharmony_ci const char *filename, uint32_t api_version, enum loader_layer_library_status *lib_status) { 16215db71995Sopenharmony_ci loader_platform_dl_handle handle = NULL; 16225db71995Sopenharmony_ci PFN_vkCreateInstance fp_create_inst = NULL; 16235db71995Sopenharmony_ci PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props = NULL; 16245db71995Sopenharmony_ci PFN_vkGetInstanceProcAddr fp_get_proc_addr = NULL; 16255db71995Sopenharmony_ci PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL; 16265db71995Sopenharmony_ci PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version = NULL; 16275db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 16285db71995Sopenharmony_ci PFN_vk_icdEnumerateAdapterPhysicalDevices fp_enum_dxgi_adapter_phys_devs = NULL; 16295db71995Sopenharmony_ci#endif 16305db71995Sopenharmony_ci struct loader_scanned_icd *new_scanned_icd = NULL; 16315db71995Sopenharmony_ci uint32_t interface_vers; 16325db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 16335db71995Sopenharmony_ci 16345db71995Sopenharmony_ci // This shouldn't happen, but the check is necessary because dlopen returns a handle to the main program when 16355db71995Sopenharmony_ci // filename is NULL 16365db71995Sopenharmony_ci if (filename == NULL) { 16375db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: A NULL filename was used, skipping this ICD", 16385db71995Sopenharmony_ci filename); 16395db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 16405db71995Sopenharmony_ci goto out; 16415db71995Sopenharmony_ci } 16425db71995Sopenharmony_ci 16435db71995Sopenharmony_ci// TODO implement smarter opening/closing of libraries. For now this 16445db71995Sopenharmony_ci// function leaves libraries open and the scanned_icd_clear closes them 16455db71995Sopenharmony_ci#if defined(__Fuchsia__) 16465db71995Sopenharmony_ci handle = loader_platform_open_driver(filename); 16475db71995Sopenharmony_ci#else 16485db71995Sopenharmony_ci handle = loader_platform_open_library(filename); 16495db71995Sopenharmony_ci#endif 16505db71995Sopenharmony_ci if (NULL == handle) { 16515db71995Sopenharmony_ci loader_handle_load_library_error(inst, filename, lib_status); 16525db71995Sopenharmony_ci if (lib_status && *lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) { 16535db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 16545db71995Sopenharmony_ci } else { 16555db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 16565db71995Sopenharmony_ci } 16575db71995Sopenharmony_ci goto out; 16585db71995Sopenharmony_ci } 16595db71995Sopenharmony_ci 16605db71995Sopenharmony_ci // Try to load the driver's exported vk_icdNegotiateLoaderICDInterfaceVersion 16615db71995Sopenharmony_ci fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion"); 16625db71995Sopenharmony_ci 16635db71995Sopenharmony_ci // If it isn't exported, we are dealing with either a v0, v1, or a v7 and up driver 16645db71995Sopenharmony_ci if (NULL == fp_negotiate_icd_version) { 16655db71995Sopenharmony_ci // Try to load the driver's exported vk_icdGetInstanceProcAddr - if this is a v7 or up driver, we can use it to get 16665db71995Sopenharmony_ci // the driver's vk_icdNegotiateLoaderICDInterfaceVersion function 16675db71995Sopenharmony_ci fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr"); 16685db71995Sopenharmony_ci 16695db71995Sopenharmony_ci // If we successfully loaded vk_icdGetInstanceProcAddr, try to get vk_icdNegotiateLoaderICDInterfaceVersion 16705db71995Sopenharmony_ci if (fp_get_proc_addr) { 16715db71995Sopenharmony_ci fp_negotiate_icd_version = 16725db71995Sopenharmony_ci (PFN_vk_icdNegotiateLoaderICDInterfaceVersion)fp_get_proc_addr(NULL, "vk_icdNegotiateLoaderICDInterfaceVersion"); 16735db71995Sopenharmony_ci } 16745db71995Sopenharmony_ci } 16755db71995Sopenharmony_ci 16765db71995Sopenharmony_ci // Try to negotiate the Loader and Driver Interface Versions 16775db71995Sopenharmony_ci // loader_get_icd_interface_version will check if fp_negotiate_icd_version is NULL, so we don't have to. 16785db71995Sopenharmony_ci // If it *is* NULL, that means this driver uses interface version 0 or 1 16795db71995Sopenharmony_ci if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_vers)) { 16805db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 16815db71995Sopenharmony_ci "loader_scanned_icd_add: ICD %s doesn't support interface version compatible with loader, skip this ICD.", 16825db71995Sopenharmony_ci filename); 16835db71995Sopenharmony_ci goto out; 16845db71995Sopenharmony_ci } 16855db71995Sopenharmony_ci 16865db71995Sopenharmony_ci // If we didn't already query vk_icdGetInstanceProcAddr, try now 16875db71995Sopenharmony_ci if (NULL == fp_get_proc_addr) { 16885db71995Sopenharmony_ci fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr"); 16895db71995Sopenharmony_ci } 16905db71995Sopenharmony_ci 16915db71995Sopenharmony_ci // If vk_icdGetInstanceProcAddr is NULL, this ICD is using version 0 and so we should respond accordingly. 16925db71995Sopenharmony_ci if (NULL == fp_get_proc_addr) { 16935db71995Sopenharmony_ci // Exporting vk_icdNegotiateLoaderICDInterfaceVersion but not vk_icdGetInstanceProcAddr violates Version 2's 16945db71995Sopenharmony_ci // requirements, as for Version 2 to be supported Version 1 must also be supported 16955db71995Sopenharmony_ci if (interface_vers != 0) { 16965db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 16975db71995Sopenharmony_ci "loader_scanned_icd_add: ICD %s reports an interface version of %d but doesn't export " 16985db71995Sopenharmony_ci "vk_icdGetInstanceProcAddr, skip this ICD.", 16995db71995Sopenharmony_ci filename, interface_vers); 17005db71995Sopenharmony_ci goto out; 17015db71995Sopenharmony_ci } 17025db71995Sopenharmony_ci // Use deprecated interface from version 0 17035db71995Sopenharmony_ci fp_get_proc_addr = loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr"); 17045db71995Sopenharmony_ci if (NULL == fp_get_proc_addr) { 17055db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 17065db71995Sopenharmony_ci "loader_scanned_icd_add: Attempt to retrieve either \'vkGetInstanceProcAddr\' or " 17075db71995Sopenharmony_ci "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.", 17085db71995Sopenharmony_ci filename); 17095db71995Sopenharmony_ci goto out; 17105db71995Sopenharmony_ci } else { 17115db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 17125db71995Sopenharmony_ci "loader_scanned_icd_add: Using deprecated ICD interface of \'vkGetInstanceProcAddr\' instead of " 17135db71995Sopenharmony_ci "\'vk_icdGetInstanceProcAddr\' for ICD %s", 17145db71995Sopenharmony_ci filename); 17155db71995Sopenharmony_ci } 17165db71995Sopenharmony_ci fp_create_inst = loader_platform_get_proc_address(handle, "vkCreateInstance"); 17175db71995Sopenharmony_ci if (NULL == fp_create_inst) { 17185db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 17195db71995Sopenharmony_ci "loader_scanned_icd_add: Failed querying \'vkCreateInstance\' via dlsym/LoadLibrary for ICD %s", filename); 17205db71995Sopenharmony_ci goto out; 17215db71995Sopenharmony_ci } 17225db71995Sopenharmony_ci fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties"); 17235db71995Sopenharmony_ci if (NULL == fp_get_inst_ext_props) { 17245db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 17255db71995Sopenharmony_ci "loader_scanned_icd_add: Could not get \'vkEnumerateInstanceExtensionProperties\' via dlsym/LoadLibrary " 17265db71995Sopenharmony_ci "for ICD %s", 17275db71995Sopenharmony_ci filename); 17285db71995Sopenharmony_ci goto out; 17295db71995Sopenharmony_ci } 17305db71995Sopenharmony_ci } else { 17315db71995Sopenharmony_ci // vk_icdGetInstanceProcAddr was successfully found, we can assume the version is at least one 17325db71995Sopenharmony_ci // If vk_icdNegotiateLoaderICDInterfaceVersion was also found, interface_vers must be 2 or greater, so this check is 17335db71995Sopenharmony_ci // fine 17345db71995Sopenharmony_ci if (interface_vers == 0) { 17355db71995Sopenharmony_ci interface_vers = 1; 17365db71995Sopenharmony_ci } 17375db71995Sopenharmony_ci 17385db71995Sopenharmony_ci fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance"); 17395db71995Sopenharmony_ci if (NULL == fp_create_inst) { 17405db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 17415db71995Sopenharmony_ci "loader_scanned_icd_add: Could not get \'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\' for ICD %s", 17425db71995Sopenharmony_ci filename); 17435db71995Sopenharmony_ci goto out; 17445db71995Sopenharmony_ci } 17455db71995Sopenharmony_ci fp_get_inst_ext_props = 17465db71995Sopenharmony_ci (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(NULL, "vkEnumerateInstanceExtensionProperties"); 17475db71995Sopenharmony_ci if (NULL == fp_get_inst_ext_props) { 17485db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 17495db71995Sopenharmony_ci "loader_scanned_icd_add: Could not get \'vkEnumerateInstanceExtensionProperties\' via " 17505db71995Sopenharmony_ci "\'vk_icdGetInstanceProcAddr\' for ICD %s", 17515db71995Sopenharmony_ci filename); 17525db71995Sopenharmony_ci goto out; 17535db71995Sopenharmony_ci } 17545db71995Sopenharmony_ci // Query "vk_icdGetPhysicalDeviceProcAddr" with vk_icdGetInstanceProcAddr if the library reports interface version 7 or 17555db71995Sopenharmony_ci // greater, otherwise fallback to loading it from the platform dynamic linker 17565db71995Sopenharmony_ci if (interface_vers >= 7) { 17575db71995Sopenharmony_ci fp_get_phys_dev_proc_addr = 17585db71995Sopenharmony_ci (PFN_vk_icdGetPhysicalDeviceProcAddr)fp_get_proc_addr(NULL, "vk_icdGetPhysicalDeviceProcAddr"); 17595db71995Sopenharmony_ci } 17605db71995Sopenharmony_ci if (NULL == fp_get_phys_dev_proc_addr && interface_vers >= 3) { 17615db71995Sopenharmony_ci fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr"); 17625db71995Sopenharmony_ci } 17635db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 17645db71995Sopenharmony_ci // Query "vk_icdEnumerateAdapterPhysicalDevices" with vk_icdGetInstanceProcAddr if the library reports interface version 17655db71995Sopenharmony_ci // 7 or greater, otherwise fallback to loading it from the platform dynamic linker 17665db71995Sopenharmony_ci if (interface_vers >= 7) { 17675db71995Sopenharmony_ci fp_enum_dxgi_adapter_phys_devs = 17685db71995Sopenharmony_ci (PFN_vk_icdEnumerateAdapterPhysicalDevices)fp_get_proc_addr(NULL, "vk_icdEnumerateAdapterPhysicalDevices"); 17695db71995Sopenharmony_ci } 17705db71995Sopenharmony_ci if (NULL == fp_enum_dxgi_adapter_phys_devs && interface_vers >= 6) { 17715db71995Sopenharmony_ci fp_enum_dxgi_adapter_phys_devs = loader_platform_get_proc_address(handle, "vk_icdEnumerateAdapterPhysicalDevices"); 17725db71995Sopenharmony_ci } 17735db71995Sopenharmony_ci#endif 17745db71995Sopenharmony_ci } 17755db71995Sopenharmony_ci 17765db71995Sopenharmony_ci // check for enough capacity 17775db71995Sopenharmony_ci if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) { 17785db71995Sopenharmony_ci void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity, 17795db71995Sopenharmony_ci icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 17805db71995Sopenharmony_ci if (NULL == new_ptr) { 17815db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 17825db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: Realloc failed on icd library list for ICD %s", 17835db71995Sopenharmony_ci filename); 17845db71995Sopenharmony_ci goto out; 17855db71995Sopenharmony_ci } 17865db71995Sopenharmony_ci icd_tramp_list->scanned_list = new_ptr; 17875db71995Sopenharmony_ci 17885db71995Sopenharmony_ci // double capacity 17895db71995Sopenharmony_ci icd_tramp_list->capacity *= 2; 17905db71995Sopenharmony_ci } 17915db71995Sopenharmony_ci 17925db71995Sopenharmony_ci loader_api_version api_version_struct = loader_make_version(api_version); 17935db71995Sopenharmony_ci if (interface_vers <= 4 && loader_check_version_meets_required(LOADER_VERSION_1_1_0, api_version_struct)) { 17945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 17955db71995Sopenharmony_ci "loader_scanned_icd_add: Driver %s supports Vulkan %u.%u, but only supports loader interface version %u." 17965db71995Sopenharmony_ci " Interface version 5 or newer required to support this version of Vulkan (Policy #LDP_DRIVER_7)", 17975db71995Sopenharmony_ci filename, api_version_struct.major, api_version_struct.minor, interface_vers); 17985db71995Sopenharmony_ci } 17995db71995Sopenharmony_ci 18005db71995Sopenharmony_ci new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]); 18015db71995Sopenharmony_ci new_scanned_icd->handle = handle; 18025db71995Sopenharmony_ci new_scanned_icd->api_version = api_version; 18035db71995Sopenharmony_ci new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr; 18045db71995Sopenharmony_ci new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr; 18055db71995Sopenharmony_ci new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props; 18065db71995Sopenharmony_ci new_scanned_icd->CreateInstance = fp_create_inst; 18075db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 18085db71995Sopenharmony_ci new_scanned_icd->EnumerateAdapterPhysicalDevices = fp_enum_dxgi_adapter_phys_devs; 18095db71995Sopenharmony_ci#endif 18105db71995Sopenharmony_ci new_scanned_icd->interface_version = interface_vers; 18115db71995Sopenharmony_ci 18125db71995Sopenharmony_ci res = loader_copy_to_new_str(inst, filename, &new_scanned_icd->lib_name); 18135db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 18145db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: Out of memory can't add ICD %s", filename); 18155db71995Sopenharmony_ci goto out; 18165db71995Sopenharmony_ci } 18175db71995Sopenharmony_ci icd_tramp_list->count++; 18185db71995Sopenharmony_ci 18195db71995Sopenharmony_ciout: 18205db71995Sopenharmony_ci 18215db71995Sopenharmony_ci return res; 18225db71995Sopenharmony_ci} 18235db71995Sopenharmony_ci 18245db71995Sopenharmony_civoid loader_initialize(void) { 18255db71995Sopenharmony_ci // initialize mutexes 18265db71995Sopenharmony_ci loader_platform_thread_create_mutex(&loader_lock); 18275db71995Sopenharmony_ci loader_platform_thread_create_mutex(&loader_preload_icd_lock); 18285db71995Sopenharmony_ci loader_platform_thread_create_mutex(&loader_global_instance_list_lock); 18295db71995Sopenharmony_ci init_global_loader_settings(); 18305db71995Sopenharmony_ci 18315db71995Sopenharmony_ci // initialize logging 18325db71995Sopenharmony_ci loader_init_global_debug_level(); 18335db71995Sopenharmony_ci#if defined(_WIN32) 18345db71995Sopenharmony_ci windows_initialization(); 18355db71995Sopenharmony_ci#endif 18365db71995Sopenharmony_ci 18375db71995Sopenharmony_ci loader_api_version version = loader_make_full_version(VK_HEADER_VERSION_COMPLETE); 18385db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_INFO_BIT, 0, "Vulkan Loader Version %d.%d.%d", version.major, version.minor, version.patch); 18395db71995Sopenharmony_ci 18405db71995Sopenharmony_ci#if defined(GIT_BRANCH_NAME) && defined(GIT_TAG_INFO) 18415db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_INFO_BIT, 0, "[Vulkan Loader Git - Tag: " GIT_BRANCH_NAME ", Branch/Commit: " GIT_TAG_INFO "]"); 18425db71995Sopenharmony_ci#endif 18435db71995Sopenharmony_ci 18445db71995Sopenharmony_ci char *loader_disable_dynamic_library_unloading_env_var = loader_getenv("VK_LOADER_DISABLE_DYNAMIC_LIBRARY_UNLOADING", NULL); 18455db71995Sopenharmony_ci if (loader_disable_dynamic_library_unloading_env_var && 18465db71995Sopenharmony_ci 0 == strncmp(loader_disable_dynamic_library_unloading_env_var, "1", 2)) { 18475db71995Sopenharmony_ci loader_disable_dynamic_library_unloading = true; 18485db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_WARN_BIT, 0, "Vulkan Loader: library unloading is disabled"); 18495db71995Sopenharmony_ci } else { 18505db71995Sopenharmony_ci loader_disable_dynamic_library_unloading = false; 18515db71995Sopenharmony_ci } 18525db71995Sopenharmony_ci loader_free_getenv(loader_disable_dynamic_library_unloading_env_var, NULL); 18535db71995Sopenharmony_ci#if defined(LOADER_USE_UNSAFE_FILE_SEARCH) 18545db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_WARN_BIT, 0, "Vulkan Loader: unsafe searching is enabled"); 18555db71995Sopenharmony_ci#endif 18565db71995Sopenharmony_ci} 18575db71995Sopenharmony_ci 18585db71995Sopenharmony_civoid loader_release() { 18595db71995Sopenharmony_ci // Guarantee release of the preloaded ICD libraries. This may have already been called in vkDestroyInstance. 18605db71995Sopenharmony_ci loader_unload_preloaded_icds(); 18615db71995Sopenharmony_ci 18625db71995Sopenharmony_ci // release mutexes 18635db71995Sopenharmony_ci teardown_global_loader_settings(); 18645db71995Sopenharmony_ci loader_platform_thread_delete_mutex(&loader_lock); 18655db71995Sopenharmony_ci loader_platform_thread_delete_mutex(&loader_preload_icd_lock); 18665db71995Sopenharmony_ci loader_platform_thread_delete_mutex(&loader_global_instance_list_lock); 18675db71995Sopenharmony_ci} 18685db71995Sopenharmony_ci 18695db71995Sopenharmony_ci// Preload the ICD libraries that are likely to be needed so we don't repeatedly load/unload them later 18705db71995Sopenharmony_civoid loader_preload_icds(void) { 18715db71995Sopenharmony_ci loader_platform_thread_lock_mutex(&loader_preload_icd_lock); 18725db71995Sopenharmony_ci 18735db71995Sopenharmony_ci // Already preloaded, skip loading again. 18745db71995Sopenharmony_ci if (scanned_icds.scanned_list != NULL) { 18755db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_preload_icd_lock); 18765db71995Sopenharmony_ci return; 18775db71995Sopenharmony_ci } 18785db71995Sopenharmony_ci 18795db71995Sopenharmony_ci VkResult result = loader_icd_scan(NULL, &scanned_icds, NULL, NULL); 18805db71995Sopenharmony_ci if (result != VK_SUCCESS) { 18815db71995Sopenharmony_ci loader_scanned_icd_clear(NULL, &scanned_icds); 18825db71995Sopenharmony_ci } 18835db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_preload_icd_lock); 18845db71995Sopenharmony_ci} 18855db71995Sopenharmony_ci 18865db71995Sopenharmony_ci// Release the ICD libraries that were preloaded 18875db71995Sopenharmony_civoid loader_unload_preloaded_icds(void) { 18885db71995Sopenharmony_ci loader_platform_thread_lock_mutex(&loader_preload_icd_lock); 18895db71995Sopenharmony_ci loader_scanned_icd_clear(NULL, &scanned_icds); 18905db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_preload_icd_lock); 18915db71995Sopenharmony_ci} 18925db71995Sopenharmony_ci 18935db71995Sopenharmony_ci#if !defined(_WIN32) 18945db71995Sopenharmony_ci__attribute__((constructor)) void loader_init_library(void) { loader_initialize(); } 18955db71995Sopenharmony_ci 18965db71995Sopenharmony_ci__attribute__((destructor)) void loader_free_library(void) { loader_release(); } 18975db71995Sopenharmony_ci#endif 18985db71995Sopenharmony_ci 18995db71995Sopenharmony_ci// Get next file or dirname given a string list or registry key path 19005db71995Sopenharmony_ci// 19015db71995Sopenharmony_ci// \returns 19025db71995Sopenharmony_ci// A pointer to first char in the next path. 19035db71995Sopenharmony_ci// The next path (or NULL) in the list is returned in next_path. 19045db71995Sopenharmony_ci// Note: input string is modified in some cases. PASS IN A COPY! 19055db71995Sopenharmony_cichar *loader_get_next_path(char *path) { 19065db71995Sopenharmony_ci uint32_t len; 19075db71995Sopenharmony_ci char *next; 19085db71995Sopenharmony_ci 19095db71995Sopenharmony_ci if (path == NULL) return NULL; 19105db71995Sopenharmony_ci next = strchr(path, PATH_SEPARATOR); 19115db71995Sopenharmony_ci if (next == NULL) { 19125db71995Sopenharmony_ci len = (uint32_t)strlen(path); 19135db71995Sopenharmony_ci next = path + len; 19145db71995Sopenharmony_ci } else { 19155db71995Sopenharmony_ci *next = '\0'; 19165db71995Sopenharmony_ci next++; 19175db71995Sopenharmony_ci } 19185db71995Sopenharmony_ci 19195db71995Sopenharmony_ci return next; 19205db71995Sopenharmony_ci} 19215db71995Sopenharmony_ci 19225db71995Sopenharmony_ci/* Processes a json manifest's library_path and the location of the json manifest to create the path of the library 19235db71995Sopenharmony_ci * The output is stored in out_fullpath by allocating a string - so its the caller's responsibility to free it 19245db71995Sopenharmony_ci * The output is the combination of the base path of manifest_file_path concatenated with library path 19255db71995Sopenharmony_ci * If library_path is an absolute path, we do not prepend the base path of manifest_file_path 19265db71995Sopenharmony_ci * 19275db71995Sopenharmony_ci * This function takes ownership of library_path - caller does not need to worry about freeing it. 19285db71995Sopenharmony_ci */ 19295db71995Sopenharmony_ciVkResult combine_manifest_directory_and_library_path(const struct loader_instance *inst, char *library_path, 19305db71995Sopenharmony_ci const char *manifest_file_path, char **out_fullpath) { 19315db71995Sopenharmony_ci assert(library_path && manifest_file_path && out_fullpath); 19325db71995Sopenharmony_ci if (loader_platform_is_path_absolute(library_path)) { 19335db71995Sopenharmony_ci *out_fullpath = library_path; 19345db71995Sopenharmony_ci return VK_SUCCESS; 19355db71995Sopenharmony_ci } 19365db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 19375db71995Sopenharmony_ci 19385db71995Sopenharmony_ci size_t library_path_len = strlen(library_path); 19395db71995Sopenharmony_ci size_t manifest_file_path_str_len = strlen(manifest_file_path); 19405db71995Sopenharmony_ci bool library_path_contains_directory_symbol = false; 19415db71995Sopenharmony_ci for (size_t i = 0; i < library_path_len; i++) { 19425db71995Sopenharmony_ci if (library_path[i] == DIRECTORY_SYMBOL) { 19435db71995Sopenharmony_ci library_path_contains_directory_symbol = true; 19445db71995Sopenharmony_ci break; 19455db71995Sopenharmony_ci } 19465db71995Sopenharmony_ci } 19475db71995Sopenharmony_ci // Means that the library_path is neither absolute nor relative - thus we should not modify it at all 19485db71995Sopenharmony_ci if (!library_path_contains_directory_symbol) { 19495db71995Sopenharmony_ci *out_fullpath = library_path; 19505db71995Sopenharmony_ci return VK_SUCCESS; 19515db71995Sopenharmony_ci } 19525db71995Sopenharmony_ci // must include both a directory symbol and the null terminator 19535db71995Sopenharmony_ci size_t new_str_len = library_path_len + manifest_file_path_str_len + 1 + 1; 19545db71995Sopenharmony_ci 19555db71995Sopenharmony_ci *out_fullpath = loader_instance_heap_calloc(inst, new_str_len, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 19565db71995Sopenharmony_ci if (NULL == *out_fullpath) { 19575db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 19585db71995Sopenharmony_ci goto out; 19595db71995Sopenharmony_ci } 19605db71995Sopenharmony_ci size_t cur_loc_in_out_fullpath = 0; 19615db71995Sopenharmony_ci // look for the last occurrence of DIRECTORY_SYMBOL in manifest_file_path 19625db71995Sopenharmony_ci size_t last_directory_symbol = 0; 19635db71995Sopenharmony_ci bool found_directory_symbol = false; 19645db71995Sopenharmony_ci for (size_t i = 0; i < manifest_file_path_str_len; i++) { 19655db71995Sopenharmony_ci if (manifest_file_path[i] == DIRECTORY_SYMBOL) { 19665db71995Sopenharmony_ci last_directory_symbol = i + 1; // we want to include the symbol 19675db71995Sopenharmony_ci found_directory_symbol = true; 19685db71995Sopenharmony_ci // dont break because we want to find the last occurrence 19695db71995Sopenharmony_ci } 19705db71995Sopenharmony_ci } 19715db71995Sopenharmony_ci // Add manifest_file_path up to the last directory symbol 19725db71995Sopenharmony_ci if (found_directory_symbol) { 19735db71995Sopenharmony_ci loader_strncpy(*out_fullpath, new_str_len, manifest_file_path, last_directory_symbol); 19745db71995Sopenharmony_ci cur_loc_in_out_fullpath += last_directory_symbol; 19755db71995Sopenharmony_ci } 19765db71995Sopenharmony_ci loader_strncpy(&(*out_fullpath)[cur_loc_in_out_fullpath], new_str_len - cur_loc_in_out_fullpath, library_path, 19775db71995Sopenharmony_ci library_path_len); 19785db71995Sopenharmony_ci cur_loc_in_out_fullpath += library_path_len + 1; 19795db71995Sopenharmony_ci (*out_fullpath)[cur_loc_in_out_fullpath] = '\0'; 19805db71995Sopenharmony_ci 19815db71995Sopenharmony_ciout: 19825db71995Sopenharmony_ci loader_instance_heap_free(inst, library_path); 19835db71995Sopenharmony_ci 19845db71995Sopenharmony_ci return res; 19855db71995Sopenharmony_ci} 19865db71995Sopenharmony_ci 19875db71995Sopenharmony_ci// Given a filename (file) and a list of paths (in_dirs), try to find an existing 19885db71995Sopenharmony_ci// file in the paths. If filename already is a path then no searching in the given paths. 19895db71995Sopenharmony_ci// 19905db71995Sopenharmony_ci// @return - A string in out_fullpath of either the full path or file. 19915db71995Sopenharmony_civoid loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size, char *out_fullpath) { 19925db71995Sopenharmony_ci if (!loader_platform_is_path(file) && *in_dirs) { 19935db71995Sopenharmony_ci size_t dirs_copy_len = strlen(in_dirs) + 1; 19945db71995Sopenharmony_ci char *dirs_copy = loader_stack_alloc(dirs_copy_len); 19955db71995Sopenharmony_ci loader_strncpy(dirs_copy, dirs_copy_len, in_dirs, dirs_copy_len); 19965db71995Sopenharmony_ci 19975db71995Sopenharmony_ci // find if file exists after prepending paths in given list 19985db71995Sopenharmony_ci // for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir)); dir = next_dir) { 19995db71995Sopenharmony_ci char *dir = dirs_copy; 20005db71995Sopenharmony_ci char *next_dir = loader_get_next_path(dir); 20015db71995Sopenharmony_ci while (*dir && next_dir) { 20025db71995Sopenharmony_ci int path_concat_ret = snprintf(out_fullpath, out_size, "%s%c%s", dir, DIRECTORY_SYMBOL, file); 20035db71995Sopenharmony_ci if (path_concat_ret < 0) { 20045db71995Sopenharmony_ci continue; 20055db71995Sopenharmony_ci } 20065db71995Sopenharmony_ci if (loader_platform_file_exists(out_fullpath)) { 20075db71995Sopenharmony_ci return; 20085db71995Sopenharmony_ci } 20095db71995Sopenharmony_ci dir = next_dir; 20105db71995Sopenharmony_ci next_dir = loader_get_next_path(dir); 20115db71995Sopenharmony_ci } 20125db71995Sopenharmony_ci } 20135db71995Sopenharmony_ci 20145db71995Sopenharmony_ci (void)snprintf(out_fullpath, out_size, "%s", file); 20155db71995Sopenharmony_ci} 20165db71995Sopenharmony_ci 20175db71995Sopenharmony_ci// Verify that all component layers in a meta-layer are valid. 20185db71995Sopenharmony_cibool verify_meta_layer_component_layers(const struct loader_instance *inst, struct loader_layer_properties *prop, 20195db71995Sopenharmony_ci struct loader_layer_list *instance_layers) { 20205db71995Sopenharmony_ci loader_api_version meta_layer_version = loader_make_version(prop->info.specVersion); 20215db71995Sopenharmony_ci 20225db71995Sopenharmony_ci for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) { 20235db71995Sopenharmony_ci struct loader_layer_properties *comp_prop = 20245db71995Sopenharmony_ci loader_find_layer_property(prop->component_layer_names.list[comp_layer], instance_layers); 20255db71995Sopenharmony_ci if (comp_prop == NULL) { 20265db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 20275db71995Sopenharmony_ci "verify_meta_layer_component_layers: Meta-layer %s can't find component layer %s at index %d." 20285db71995Sopenharmony_ci " Skipping this layer.", 20295db71995Sopenharmony_ci prop->info.layerName, prop->component_layer_names.list[comp_layer], comp_layer); 20305db71995Sopenharmony_ci 20315db71995Sopenharmony_ci return false; 20325db71995Sopenharmony_ci } 20335db71995Sopenharmony_ci 20345db71995Sopenharmony_ci // Check the version of each layer, they need to be at least MAJOR and MINOR 20355db71995Sopenharmony_ci loader_api_version comp_prop_version = loader_make_version(comp_prop->info.specVersion); 20365db71995Sopenharmony_ci if (!loader_check_version_meets_required(meta_layer_version, comp_prop_version)) { 20375db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 20385db71995Sopenharmony_ci "verify_meta_layer_component_layers: Meta-layer uses API version %d.%d, but component " 20395db71995Sopenharmony_ci "layer %d has API version %d.%d that is lower. Skipping this layer.", 20405db71995Sopenharmony_ci meta_layer_version.major, meta_layer_version.minor, comp_layer, comp_prop_version.major, 20415db71995Sopenharmony_ci comp_prop_version.minor); 20425db71995Sopenharmony_ci 20435db71995Sopenharmony_ci return false; 20445db71995Sopenharmony_ci } 20455db71995Sopenharmony_ci 20465db71995Sopenharmony_ci // Make sure the layer isn't using it's own name 20475db71995Sopenharmony_ci if (!strcmp(prop->info.layerName, prop->component_layer_names.list[comp_layer])) { 20485db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 20495db71995Sopenharmony_ci "verify_meta_layer_component_layers: Meta-layer %s lists itself in its component layer " 20505db71995Sopenharmony_ci "list at index %d. Skipping this layer.", 20515db71995Sopenharmony_ci prop->info.layerName, comp_layer); 20525db71995Sopenharmony_ci 20535db71995Sopenharmony_ci return false; 20545db71995Sopenharmony_ci } 20555db71995Sopenharmony_ci if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { 20565db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 20575db71995Sopenharmony_ci "verify_meta_layer_component_layers: Adding meta-layer %s which also contains meta-layer %s", 20585db71995Sopenharmony_ci prop->info.layerName, comp_prop->info.layerName); 20595db71995Sopenharmony_ci 20605db71995Sopenharmony_ci // Make sure if the layer is using a meta-layer in its component list that we also verify that. 20615db71995Sopenharmony_ci if (!verify_meta_layer_component_layers(inst, comp_prop, instance_layers)) { 20625db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 20635db71995Sopenharmony_ci "Meta-layer %s component layer %s can not find all component layers." 20645db71995Sopenharmony_ci " Skipping this layer.", 20655db71995Sopenharmony_ci prop->info.layerName, prop->component_layer_names.list[comp_layer]); 20665db71995Sopenharmony_ci return false; 20675db71995Sopenharmony_ci } 20685db71995Sopenharmony_ci } 20695db71995Sopenharmony_ci } 20705db71995Sopenharmony_ci // Didn't exit early so that means it passed all checks 20715db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, 20725db71995Sopenharmony_ci "Meta-layer \"%s\" all %d component layers appear to be valid.", prop->info.layerName, 20735db71995Sopenharmony_ci prop->component_layer_names.count); 20745db71995Sopenharmony_ci 20755db71995Sopenharmony_ci // If layer logging is on, list the internals included in the meta-layer 20765db71995Sopenharmony_ci for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) { 20775db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " [%d] %s", comp_layer, prop->component_layer_names.list[comp_layer]); 20785db71995Sopenharmony_ci } 20795db71995Sopenharmony_ci return true; 20805db71995Sopenharmony_ci} 20815db71995Sopenharmony_ci 20825db71995Sopenharmony_ci// Add any instance and device extensions from component layers to this layer 20835db71995Sopenharmony_ci// list, so that anyone querying extensions will only need to look at the meta-layer 20845db71995Sopenharmony_cibool update_meta_layer_extensions_from_component_layers(const struct loader_instance *inst, struct loader_layer_properties *prop, 20855db71995Sopenharmony_ci struct loader_layer_list *instance_layers) { 20865db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 20875db71995Sopenharmony_ci for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) { 20885db71995Sopenharmony_ci struct loader_layer_properties *comp_prop = 20895db71995Sopenharmony_ci loader_find_layer_property(prop->component_layer_names.list[comp_layer], instance_layers); 20905db71995Sopenharmony_ci 20915db71995Sopenharmony_ci if (NULL != comp_prop->instance_extension_list.list) { 20925db71995Sopenharmony_ci for (uint32_t ext = 0; ext < comp_prop->instance_extension_list.count; ext++) { 20935db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Meta-layer %s component layer %s adding instance extension %s", 20945db71995Sopenharmony_ci prop->info.layerName, prop->component_layer_names.list[comp_layer], 20955db71995Sopenharmony_ci comp_prop->instance_extension_list.list[ext].extensionName); 20965db71995Sopenharmony_ci 20975db71995Sopenharmony_ci if (!has_vk_extension_property(&comp_prop->instance_extension_list.list[ext], &prop->instance_extension_list)) { 20985db71995Sopenharmony_ci res = loader_add_to_ext_list(inst, &prop->instance_extension_list, 1, 20995db71995Sopenharmony_ci &comp_prop->instance_extension_list.list[ext]); 21005db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 21015db71995Sopenharmony_ci return res; 21025db71995Sopenharmony_ci } 21035db71995Sopenharmony_ci } 21045db71995Sopenharmony_ci } 21055db71995Sopenharmony_ci } 21065db71995Sopenharmony_ci if (NULL != comp_prop->device_extension_list.list) { 21075db71995Sopenharmony_ci for (uint32_t ext = 0; ext < comp_prop->device_extension_list.count; ext++) { 21085db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Meta-layer %s component layer %s adding device extension %s", 21095db71995Sopenharmony_ci prop->info.layerName, prop->component_layer_names.list[comp_layer], 21105db71995Sopenharmony_ci comp_prop->device_extension_list.list[ext].props.extensionName); 21115db71995Sopenharmony_ci 21125db71995Sopenharmony_ci if (!has_vk_dev_ext_property(&comp_prop->device_extension_list.list[ext].props, &prop->device_extension_list)) { 21135db71995Sopenharmony_ci loader_add_to_dev_ext_list(inst, &prop->device_extension_list, 21145db71995Sopenharmony_ci &comp_prop->device_extension_list.list[ext].props, NULL); 21155db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 21165db71995Sopenharmony_ci return res; 21175db71995Sopenharmony_ci } 21185db71995Sopenharmony_ci } 21195db71995Sopenharmony_ci } 21205db71995Sopenharmony_ci } 21215db71995Sopenharmony_ci } 21225db71995Sopenharmony_ci return res; 21235db71995Sopenharmony_ci} 21245db71995Sopenharmony_ci 21255db71995Sopenharmony_ci// Verify that all meta-layers in a layer list are valid. 21265db71995Sopenharmony_ciVkResult verify_all_meta_layers(struct loader_instance *inst, const struct loader_envvar_all_filters *filters, 21275db71995Sopenharmony_ci struct loader_layer_list *instance_layers, bool *override_layer_present) { 21285db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 21295db71995Sopenharmony_ci *override_layer_present = false; 21305db71995Sopenharmony_ci for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) { 21315db71995Sopenharmony_ci struct loader_layer_properties *prop = &instance_layers->list[i]; 21325db71995Sopenharmony_ci 21335db71995Sopenharmony_ci // If this is a meta-layer, make sure it is valid 21345db71995Sopenharmony_ci if (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { 21355db71995Sopenharmony_ci if (verify_meta_layer_component_layers(inst, prop, instance_layers)) { 21365db71995Sopenharmony_ci // If any meta layer is valid, update its extension list to include the extensions from its component layers. 21375db71995Sopenharmony_ci res = update_meta_layer_extensions_from_component_layers(inst, prop, instance_layers); 21385db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 21395db71995Sopenharmony_ci return res; 21405db71995Sopenharmony_ci } 21415db71995Sopenharmony_ci if (prop->is_override && loader_implicit_layer_is_enabled(inst, filters, prop)) { 21425db71995Sopenharmony_ci *override_layer_present = true; 21435db71995Sopenharmony_ci } 21445db71995Sopenharmony_ci } else { 21455db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, 21465db71995Sopenharmony_ci "Removing meta-layer %s from instance layer list since it appears invalid.", prop->info.layerName); 21475db71995Sopenharmony_ci 21485db71995Sopenharmony_ci loader_remove_layer_in_list(inst, instance_layers, i); 21495db71995Sopenharmony_ci i--; 21505db71995Sopenharmony_ci } 21515db71995Sopenharmony_ci } 21525db71995Sopenharmony_ci } 21535db71995Sopenharmony_ci return res; 21545db71995Sopenharmony_ci} 21555db71995Sopenharmony_ci 21565db71995Sopenharmony_ci// If the current working directory matches any app_key_path of the layers, remove all other override layers. 21575db71995Sopenharmony_ci// Otherwise if no matching app_key was found, remove all but the global override layer, which has no app_key_path. 21585db71995Sopenharmony_civoid remove_all_non_valid_override_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) { 21595db71995Sopenharmony_ci if (instance_layers == NULL) { 21605db71995Sopenharmony_ci return; 21615db71995Sopenharmony_ci } 21625db71995Sopenharmony_ci 21635db71995Sopenharmony_ci char cur_path[1024]; 21645db71995Sopenharmony_ci char *ret = loader_platform_executable_path(cur_path, 1024); 21655db71995Sopenharmony_ci if (NULL == ret) { 21665db71995Sopenharmony_ci return; 21675db71995Sopenharmony_ci } 21685db71995Sopenharmony_ci // Find out if there is an override layer with same the app_key_path as the path to the current executable. 21695db71995Sopenharmony_ci // If more than one is found, remove it and use the first layer 21705db71995Sopenharmony_ci // Remove any layers which aren't global and do not have the same app_key_path as the path to the current executable. 21715db71995Sopenharmony_ci bool found_active_override_layer = false; 21725db71995Sopenharmony_ci int global_layer_index = -1; 21735db71995Sopenharmony_ci for (uint32_t i = 0; i < instance_layers->count; i++) { 21745db71995Sopenharmony_ci struct loader_layer_properties *props = &instance_layers->list[i]; 21755db71995Sopenharmony_ci if (strcmp(props->info.layerName, VK_OVERRIDE_LAYER_NAME) == 0) { 21765db71995Sopenharmony_ci if (props->app_key_paths.count > 0) { // not the global layer 21775db71995Sopenharmony_ci for (uint32_t j = 0; j < props->app_key_paths.count; j++) { 21785db71995Sopenharmony_ci if (strcmp(props->app_key_paths.list[j], cur_path) == 0) { 21795db71995Sopenharmony_ci if (!found_active_override_layer) { 21805db71995Sopenharmony_ci found_active_override_layer = true; 21815db71995Sopenharmony_ci } else { 21825db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 21835db71995Sopenharmony_ci "remove_all_non_valid_override_layers: Multiple override layers where the same path in " 21845db71995Sopenharmony_ci "app_keys " 21855db71995Sopenharmony_ci "was found. Using the first layer found"); 21865db71995Sopenharmony_ci 21875db71995Sopenharmony_ci // Remove duplicate active override layers that have the same app_key_path 21885db71995Sopenharmony_ci loader_remove_layer_in_list(inst, instance_layers, i); 21895db71995Sopenharmony_ci i--; 21905db71995Sopenharmony_ci } 21915db71995Sopenharmony_ci } 21925db71995Sopenharmony_ci } 21935db71995Sopenharmony_ci if (!found_active_override_layer) { 21945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, 21955db71995Sopenharmony_ci "--Override layer found but not used because app \'%s\' is not in \'app_keys\' list!", cur_path); 21965db71995Sopenharmony_ci 21975db71995Sopenharmony_ci // Remove non-global override layers that don't have an app_key that matches cur_path 21985db71995Sopenharmony_ci loader_remove_layer_in_list(inst, instance_layers, i); 21995db71995Sopenharmony_ci i--; 22005db71995Sopenharmony_ci } 22015db71995Sopenharmony_ci } else { 22025db71995Sopenharmony_ci if (global_layer_index == -1) { 22035db71995Sopenharmony_ci global_layer_index = i; 22045db71995Sopenharmony_ci } else { 22055db71995Sopenharmony_ci loader_log( 22065db71995Sopenharmony_ci inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 22075db71995Sopenharmony_ci "remove_all_non_valid_override_layers: Multiple global override layers found. Using the first global " 22085db71995Sopenharmony_ci "layer found"); 22095db71995Sopenharmony_ci loader_remove_layer_in_list(inst, instance_layers, i); 22105db71995Sopenharmony_ci i--; 22115db71995Sopenharmony_ci } 22125db71995Sopenharmony_ci } 22135db71995Sopenharmony_ci } 22145db71995Sopenharmony_ci } 22155db71995Sopenharmony_ci // Remove global layer if layer with same the app_key_path as the path to the current executable is found 22165db71995Sopenharmony_ci if (found_active_override_layer && global_layer_index >= 0) { 22175db71995Sopenharmony_ci loader_remove_layer_in_list(inst, instance_layers, global_layer_index); 22185db71995Sopenharmony_ci } 22195db71995Sopenharmony_ci // Should be at most 1 override layer in the list now. 22205db71995Sopenharmony_ci if (found_active_override_layer) { 22215db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Using the override layer for app key %s", cur_path); 22225db71995Sopenharmony_ci } else if (global_layer_index >= 0) { 22235db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Using the global override layer"); 22245db71995Sopenharmony_ci } 22255db71995Sopenharmony_ci} 22265db71995Sopenharmony_ci 22275db71995Sopenharmony_ci/* The following are required in the "layer" object: 22285db71995Sopenharmony_ci * "name" 22295db71995Sopenharmony_ci * "type" 22305db71995Sopenharmony_ci * (for non-meta layers) "library_path" 22315db71995Sopenharmony_ci * (for meta layers) "component_layers" 22325db71995Sopenharmony_ci * "api_version" 22335db71995Sopenharmony_ci * "implementation_version" 22345db71995Sopenharmony_ci * "description" 22355db71995Sopenharmony_ci * (for implicit layers) "disable_environment" 22365db71995Sopenharmony_ci */ 22375db71995Sopenharmony_ci 22385db71995Sopenharmony_ciVkResult loader_read_layer_json(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list, 22395db71995Sopenharmony_ci cJSON *layer_node, loader_api_version version, bool is_implicit, char *filename) { 22405db71995Sopenharmony_ci assert(layer_instance_list); 22415db71995Sopenharmony_ci char *type = NULL; 22425db71995Sopenharmony_ci char *api_version = NULL; 22435db71995Sopenharmony_ci char *implementation_version = NULL; 22445db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 22455db71995Sopenharmony_ci struct loader_layer_properties props = {0}; 22465db71995Sopenharmony_ci 22475db71995Sopenharmony_ci // Parse name 22485db71995Sopenharmony_ci 22495db71995Sopenharmony_ci result = loader_parse_json_string_to_existing_str(inst, layer_node, "name", VK_MAX_EXTENSION_NAME_SIZE, props.info.layerName); 22505db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out; 22515db71995Sopenharmony_ci if (VK_ERROR_INITIALIZATION_FAILED == result) { 22525db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 22535db71995Sopenharmony_ci "Layer located at %s didn't find required layer value \"name\" in manifest JSON file, skipping this layer", 22545db71995Sopenharmony_ci filename); 22555db71995Sopenharmony_ci goto out; 22565db71995Sopenharmony_ci } 22575db71995Sopenharmony_ci 22585db71995Sopenharmony_ci // Check if this layer's name matches the override layer name, set is_override to true if so. 22595db71995Sopenharmony_ci if (!strcmp(props.info.layerName, VK_OVERRIDE_LAYER_NAME)) { 22605db71995Sopenharmony_ci props.is_override = true; 22615db71995Sopenharmony_ci } 22625db71995Sopenharmony_ci 22635db71995Sopenharmony_ci if (0 != strncmp(props.info.layerName, "VK_LAYER_", 9)) { 22645db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Layer name %s does not conform to naming standard (Policy #LLP_LAYER_3)", 22655db71995Sopenharmony_ci props.info.layerName); 22665db71995Sopenharmony_ci } 22675db71995Sopenharmony_ci 22685db71995Sopenharmony_ci // Parse type 22695db71995Sopenharmony_ci 22705db71995Sopenharmony_ci result = loader_parse_json_string(layer_node, "type", &type); 22715db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out; 22725db71995Sopenharmony_ci if (VK_ERROR_INITIALIZATION_FAILED == result) { 22735db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 22745db71995Sopenharmony_ci "Layer located at %s didn't find required layer value \"type\" in manifest JSON file, skipping this layer", 22755db71995Sopenharmony_ci filename); 22765db71995Sopenharmony_ci goto out; 22775db71995Sopenharmony_ci } 22785db71995Sopenharmony_ci 22795db71995Sopenharmony_ci // Add list entry 22805db71995Sopenharmony_ci if (!strcmp(type, "DEVICE")) { 22815db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Device layers are deprecated. Skipping this layer"); 22825db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 22835db71995Sopenharmony_ci goto out; 22845db71995Sopenharmony_ci } 22855db71995Sopenharmony_ci 22865db71995Sopenharmony_ci // Allow either GLOBAL or INSTANCE type interchangeably to handle layers that must work with older loaders 22875db71995Sopenharmony_ci if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) { 22885db71995Sopenharmony_ci props.type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER; 22895db71995Sopenharmony_ci if (!is_implicit) { 22905db71995Sopenharmony_ci props.type_flags |= VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER; 22915db71995Sopenharmony_ci } 22925db71995Sopenharmony_ci } else { 22935db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 22945db71995Sopenharmony_ci goto out; 22955db71995Sopenharmony_ci } 22965db71995Sopenharmony_ci 22975db71995Sopenharmony_ci // Parse api_version 22985db71995Sopenharmony_ci 22995db71995Sopenharmony_ci result = loader_parse_json_string(layer_node, "api_version", &api_version); 23005db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out; 23015db71995Sopenharmony_ci if (VK_ERROR_INITIALIZATION_FAILED == result) { 23025db71995Sopenharmony_ci loader_log( 23035db71995Sopenharmony_ci inst, VULKAN_LOADER_WARN_BIT, 0, 23045db71995Sopenharmony_ci "Layer located at %s didn't find required layer value \"api_version\" in manifest JSON file, skipping this layer", 23055db71995Sopenharmony_ci filename); 23065db71995Sopenharmony_ci goto out; 23075db71995Sopenharmony_ci } 23085db71995Sopenharmony_ci 23095db71995Sopenharmony_ci props.info.specVersion = loader_parse_version_string(api_version); 23105db71995Sopenharmony_ci 23115db71995Sopenharmony_ci // Make sure the layer's manifest doesn't contain a non zero variant value 23125db71995Sopenharmony_ci if (VK_API_VERSION_VARIANT(props.info.specVersion) != 0) { 23135db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, 23145db71995Sopenharmony_ci "Layer \"%s\" has an \'api_version\' field which contains a non-zero variant value of %d. " 23155db71995Sopenharmony_ci " Skipping Layer.", 23165db71995Sopenharmony_ci props.info.layerName, VK_API_VERSION_VARIANT(props.info.specVersion)); 23175db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 23185db71995Sopenharmony_ci goto out; 23195db71995Sopenharmony_ci } 23205db71995Sopenharmony_ci 23215db71995Sopenharmony_ci // Parse implementation_version 23225db71995Sopenharmony_ci 23235db71995Sopenharmony_ci result = loader_parse_json_string(layer_node, "implementation_version", &implementation_version); 23245db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out; 23255db71995Sopenharmony_ci if (VK_ERROR_INITIALIZATION_FAILED == result) { 23265db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 23275db71995Sopenharmony_ci "Layer located at %s didn't find required layer value \"implementation_version\" in manifest JSON file, " 23285db71995Sopenharmony_ci "skipping this layer", 23295db71995Sopenharmony_ci filename); 23305db71995Sopenharmony_ci goto out; 23315db71995Sopenharmony_ci } 23325db71995Sopenharmony_ci props.info.implementationVersion = atoi(implementation_version); 23335db71995Sopenharmony_ci 23345db71995Sopenharmony_ci // Parse description 23355db71995Sopenharmony_ci 23365db71995Sopenharmony_ci result = loader_parse_json_string_to_existing_str(inst, layer_node, "description", VK_MAX_EXTENSION_NAME_SIZE, 23375db71995Sopenharmony_ci props.info.description); 23385db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out; 23395db71995Sopenharmony_ci if (VK_ERROR_INITIALIZATION_FAILED == result) { 23405db71995Sopenharmony_ci loader_log( 23415db71995Sopenharmony_ci inst, VULKAN_LOADER_WARN_BIT, 0, 23425db71995Sopenharmony_ci "Layer located at %s didn't find required layer value \"description\" in manifest JSON file, skipping this layer", 23435db71995Sopenharmony_ci filename); 23445db71995Sopenharmony_ci goto out; 23455db71995Sopenharmony_ci } 23465db71995Sopenharmony_ci 23475db71995Sopenharmony_ci // Parse library_path 23485db71995Sopenharmony_ci 23495db71995Sopenharmony_ci // Library path no longer required unless component_layers is also not defined 23505db71995Sopenharmony_ci cJSON *library_path = loader_cJSON_GetObjectItem(layer_node, "library_path"); 23515db71995Sopenharmony_ci 23525db71995Sopenharmony_ci if (NULL != library_path) { 23535db71995Sopenharmony_ci if (NULL != loader_cJSON_GetObjectItem(layer_node, "component_layers")) { 23545db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 23555db71995Sopenharmony_ci "Indicating meta-layer-specific component_layers, but also defining layer library path. Both are not " 23565db71995Sopenharmony_ci "compatible, so skipping this layer"); 23575db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 23585db71995Sopenharmony_ci goto out; 23595db71995Sopenharmony_ci } 23605db71995Sopenharmony_ci 23615db71995Sopenharmony_ci result = loader_copy_to_new_str(inst, filename, &props.manifest_file_name); 23625db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 23635db71995Sopenharmony_ci 23645db71995Sopenharmony_ci char *library_path_str = loader_cJSON_Print(library_path); 23655db71995Sopenharmony_ci if (NULL == library_path_str) { 23665db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 23675db71995Sopenharmony_ci "Skipping layer due to problem accessing the library_path value in manifest JSON file %s", filename); 23685db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 23695db71995Sopenharmony_ci goto out; 23705db71995Sopenharmony_ci } 23715db71995Sopenharmony_ci 23725db71995Sopenharmony_ci // This function takes ownership of library_path_str - so we don't need to clean it up 23735db71995Sopenharmony_ci result = combine_manifest_directory_and_library_path(inst, library_path_str, filename, &props.lib_name); 23745db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 23755db71995Sopenharmony_ci } 23765db71995Sopenharmony_ci 23775db71995Sopenharmony_ci // Parse component_layers 23785db71995Sopenharmony_ci 23795db71995Sopenharmony_ci if (NULL == library_path) { 23805db71995Sopenharmony_ci if (!loader_check_version_meets_required(LOADER_VERSION_1_1_0, version)) { 23815db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 23825db71995Sopenharmony_ci "Indicating meta-layer-specific component_layers, but using older JSON file version."); 23835db71995Sopenharmony_ci } 23845db71995Sopenharmony_ci 23855db71995Sopenharmony_ci result = loader_parse_json_array_of_strings(inst, layer_node, "component_layers", &(props.component_layer_names)); 23865db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) { 23875db71995Sopenharmony_ci goto out; 23885db71995Sopenharmony_ci } 23895db71995Sopenharmony_ci if (VK_ERROR_INITIALIZATION_FAILED == result) { 23905db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 23915db71995Sopenharmony_ci "Layer missing both library_path and component_layers fields. One or the other MUST be defined. Skipping " 23925db71995Sopenharmony_ci "this layer"); 23935db71995Sopenharmony_ci goto out; 23945db71995Sopenharmony_ci } 23955db71995Sopenharmony_ci // This is now, officially, a meta-layer 23965db71995Sopenharmony_ci props.type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER; 23975db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Encountered meta-layer \"%s\"", 23985db71995Sopenharmony_ci props.info.layerName); 23995db71995Sopenharmony_ci } 24005db71995Sopenharmony_ci 24015db71995Sopenharmony_ci // Parse blacklisted_layers 24025db71995Sopenharmony_ci 24035db71995Sopenharmony_ci if (props.is_override) { 24045db71995Sopenharmony_ci result = loader_parse_json_array_of_strings(inst, layer_node, "blacklisted_layers", &(props.blacklist_layer_names)); 24055db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) { 24065db71995Sopenharmony_ci goto out; 24075db71995Sopenharmony_ci } 24085db71995Sopenharmony_ci } 24095db71995Sopenharmony_ci 24105db71995Sopenharmony_ci // Parse override_paths 24115db71995Sopenharmony_ci 24125db71995Sopenharmony_ci result = loader_parse_json_array_of_strings(inst, layer_node, "override_paths", &(props.override_paths)); 24135db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == result) { 24145db71995Sopenharmony_ci goto out; 24155db71995Sopenharmony_ci } 24165db71995Sopenharmony_ci if (NULL != props.override_paths.list && !loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) { 24175db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 24185db71995Sopenharmony_ci "Indicating meta-layer-specific override paths, but using older JSON file version."); 24195db71995Sopenharmony_ci } 24205db71995Sopenharmony_ci 24215db71995Sopenharmony_ci // Parse disable_environment 24225db71995Sopenharmony_ci 24235db71995Sopenharmony_ci if (is_implicit) { 24245db71995Sopenharmony_ci cJSON *disable_environment = loader_cJSON_GetObjectItem(layer_node, "disable_environment"); 24255db71995Sopenharmony_ci if (disable_environment == NULL) { 24265db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 24275db71995Sopenharmony_ci "Didn't find required layer object disable_environment in manifest JSON file, skipping this layer"); 24285db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 24295db71995Sopenharmony_ci goto out; 24305db71995Sopenharmony_ci } 24315db71995Sopenharmony_ci 24325db71995Sopenharmony_ci if (!disable_environment->child || disable_environment->child->type != cJSON_String) { 24335db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 24345db71995Sopenharmony_ci "Didn't find required layer child value disable_environment in manifest JSON file, skipping this layer " 24355db71995Sopenharmony_ci "(Policy #LLP_LAYER_9)"); 24365db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 24375db71995Sopenharmony_ci goto out; 24385db71995Sopenharmony_ci } 24395db71995Sopenharmony_ci result = loader_copy_to_new_str(inst, disable_environment->child->string, &(props.disable_env_var.name)); 24405db71995Sopenharmony_ci if (VK_SUCCESS != result) goto out; 24415db71995Sopenharmony_ci result = loader_copy_to_new_str(inst, disable_environment->child->valuestring, &(props.disable_env_var.value)); 24425db71995Sopenharmony_ci if (VK_SUCCESS != result) goto out; 24435db71995Sopenharmony_ci } 24445db71995Sopenharmony_ci 24455db71995Sopenharmony_ci // Now get all optional items and objects and put in list: 24465db71995Sopenharmony_ci // functions 24475db71995Sopenharmony_ci // instance_extensions 24485db71995Sopenharmony_ci // device_extensions 24495db71995Sopenharmony_ci // enable_environment (implicit layers only) 24505db71995Sopenharmony_ci // library_arch 24515db71995Sopenharmony_ci 24525db71995Sopenharmony_ci // Layer interface functions 24535db71995Sopenharmony_ci // vkGetInstanceProcAddr 24545db71995Sopenharmony_ci // vkGetDeviceProcAddr 24555db71995Sopenharmony_ci // vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0) 24565db71995Sopenharmony_ci cJSON *functions = loader_cJSON_GetObjectItem(layer_node, "functions"); 24575db71995Sopenharmony_ci if (functions != NULL) { 24585db71995Sopenharmony_ci if (loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) { 24595db71995Sopenharmony_ci result = loader_parse_json_string(functions, "vkNegotiateLoaderLayerInterfaceVersion", 24605db71995Sopenharmony_ci &props.functions.str_negotiate_interface); 24615db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 24625db71995Sopenharmony_ci } 24635db71995Sopenharmony_ci result = loader_parse_json_string(functions, "vkGetInstanceProcAddr", &props.functions.str_gipa); 24645db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 24655db71995Sopenharmony_ci 24665db71995Sopenharmony_ci if (props.functions.str_gipa && loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) { 24675db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 24685db71995Sopenharmony_ci "Layer \"%s\" using deprecated \'vkGetInstanceProcAddr\' tag which was deprecated starting with JSON " 24695db71995Sopenharmony_ci "file version 1.1.0. The new vkNegotiateLoaderLayerInterfaceVersion function is preferred, though for " 24705db71995Sopenharmony_ci "compatibility reasons it may be desirable to continue using the deprecated tag.", 24715db71995Sopenharmony_ci props.info.layerName); 24725db71995Sopenharmony_ci } 24735db71995Sopenharmony_ci 24745db71995Sopenharmony_ci result = loader_parse_json_string(functions, "vkGetDeviceProcAddr", &props.functions.str_gdpa); 24755db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 24765db71995Sopenharmony_ci 24775db71995Sopenharmony_ci if (props.functions.str_gdpa && loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) { 24785db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 24795db71995Sopenharmony_ci "Layer \"%s\" using deprecated \'vkGetDeviceProcAddr\' tag which was deprecated starting with JSON " 24805db71995Sopenharmony_ci "file version 1.1.0. The new vkNegotiateLoaderLayerInterfaceVersion function is preferred, though for " 24815db71995Sopenharmony_ci "compatibility reasons it may be desirable to continue using the deprecated tag.", 24825db71995Sopenharmony_ci props.info.layerName); 24835db71995Sopenharmony_ci } 24845db71995Sopenharmony_ci } 24855db71995Sopenharmony_ci 24865db71995Sopenharmony_ci // instance_extensions 24875db71995Sopenharmony_ci // array of { 24885db71995Sopenharmony_ci // name 24895db71995Sopenharmony_ci // spec_version 24905db71995Sopenharmony_ci // } 24915db71995Sopenharmony_ci 24925db71995Sopenharmony_ci cJSON *instance_extensions = loader_cJSON_GetObjectItem(layer_node, "instance_extensions"); 24935db71995Sopenharmony_ci if (instance_extensions != NULL) { 24945db71995Sopenharmony_ci int count = loader_cJSON_GetArraySize(instance_extensions); 24955db71995Sopenharmony_ci for (int i = 0; i < count; i++) { 24965db71995Sopenharmony_ci VkExtensionProperties ext_prop = {0}; 24975db71995Sopenharmony_ci cJSON *ext_item = loader_cJSON_GetArrayItem(instance_extensions, i); 24985db71995Sopenharmony_ci result = loader_parse_json_string_to_existing_str(inst, ext_item, "name", VK_MAX_EXTENSION_NAME_SIZE, 24995db71995Sopenharmony_ci ext_prop.extensionName); 25005db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25015db71995Sopenharmony_ci if (result == VK_ERROR_INITIALIZATION_FAILED) continue; 25025db71995Sopenharmony_ci char *spec_version = NULL; 25035db71995Sopenharmony_ci result = loader_parse_json_string(ext_item, "spec_version", &spec_version); 25045db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25055db71995Sopenharmony_ci if (NULL != spec_version) { 25065db71995Sopenharmony_ci ext_prop.specVersion = atoi(spec_version); 25075db71995Sopenharmony_ci } 25085db71995Sopenharmony_ci loader_instance_heap_free(inst, spec_version); 25095db71995Sopenharmony_ci bool ext_unsupported = wsi_unsupported_instance_extension(&ext_prop); 25105db71995Sopenharmony_ci if (!ext_unsupported) { 25115db71995Sopenharmony_ci loader_add_to_ext_list(inst, &props.instance_extension_list, 1, &ext_prop); 25125db71995Sopenharmony_ci } 25135db71995Sopenharmony_ci } 25145db71995Sopenharmony_ci } 25155db71995Sopenharmony_ci 25165db71995Sopenharmony_ci // device_extensions 25175db71995Sopenharmony_ci // array of { 25185db71995Sopenharmony_ci // name 25195db71995Sopenharmony_ci // spec_version 25205db71995Sopenharmony_ci // entrypoints 25215db71995Sopenharmony_ci // } 25225db71995Sopenharmony_ci cJSON *device_extensions = loader_cJSON_GetObjectItem(layer_node, "device_extensions"); 25235db71995Sopenharmony_ci if (device_extensions != NULL) { 25245db71995Sopenharmony_ci int count = loader_cJSON_GetArraySize(device_extensions); 25255db71995Sopenharmony_ci for (int i = 0; i < count; i++) { 25265db71995Sopenharmony_ci VkExtensionProperties ext_prop = {0}; 25275db71995Sopenharmony_ci 25285db71995Sopenharmony_ci cJSON *ext_item = loader_cJSON_GetArrayItem(device_extensions, i); 25295db71995Sopenharmony_ci 25305db71995Sopenharmony_ci result = loader_parse_json_string_to_existing_str(inst, ext_item, "name", VK_MAX_EXTENSION_NAME_SIZE, 25315db71995Sopenharmony_ci ext_prop.extensionName); 25325db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25335db71995Sopenharmony_ci 25345db71995Sopenharmony_ci char *spec_version = NULL; 25355db71995Sopenharmony_ci result = loader_parse_json_string(ext_item, "spec_version", &spec_version); 25365db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25375db71995Sopenharmony_ci if (NULL != spec_version) { 25385db71995Sopenharmony_ci ext_prop.specVersion = atoi(spec_version); 25395db71995Sopenharmony_ci } 25405db71995Sopenharmony_ci loader_instance_heap_free(inst, spec_version); 25415db71995Sopenharmony_ci 25425db71995Sopenharmony_ci cJSON *entrypoints = loader_cJSON_GetObjectItem(ext_item, "entrypoints"); 25435db71995Sopenharmony_ci if (entrypoints == NULL) { 25445db71995Sopenharmony_ci result = loader_add_to_dev_ext_list(inst, &props.device_extension_list, &ext_prop, NULL); 25455db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25465db71995Sopenharmony_ci continue; 25475db71995Sopenharmony_ci } 25485db71995Sopenharmony_ci 25495db71995Sopenharmony_ci struct loader_string_list entrys = {0}; 25505db71995Sopenharmony_ci result = loader_parse_json_array_of_strings(inst, ext_item, "entrypoints", &entrys); 25515db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25525db71995Sopenharmony_ci result = loader_add_to_dev_ext_list(inst, &props.device_extension_list, &ext_prop, &entrys); 25535db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25545db71995Sopenharmony_ci } 25555db71995Sopenharmony_ci } 25565db71995Sopenharmony_ci if (is_implicit) { 25575db71995Sopenharmony_ci cJSON *enable_environment = loader_cJSON_GetObjectItem(layer_node, "enable_environment"); 25585db71995Sopenharmony_ci 25595db71995Sopenharmony_ci // enable_environment is optional 25605db71995Sopenharmony_ci if (enable_environment && enable_environment->child && enable_environment->child->type == cJSON_String) { 25615db71995Sopenharmony_ci result = loader_copy_to_new_str(inst, enable_environment->child->string, &(props.enable_env_var.name)); 25625db71995Sopenharmony_ci if (VK_SUCCESS != result) goto out; 25635db71995Sopenharmony_ci result = loader_copy_to_new_str(inst, enable_environment->child->valuestring, &(props.enable_env_var.value)); 25645db71995Sopenharmony_ci if (VK_SUCCESS != result) goto out; 25655db71995Sopenharmony_ci } 25665db71995Sopenharmony_ci } 25675db71995Sopenharmony_ci 25685db71995Sopenharmony_ci // Read in the pre-instance stuff 25695db71995Sopenharmony_ci cJSON *pre_instance = loader_cJSON_GetObjectItem(layer_node, "pre_instance_functions"); 25705db71995Sopenharmony_ci if (NULL != pre_instance) { 25715db71995Sopenharmony_ci // Supported versions started in 1.1.2, so anything newer 25725db71995Sopenharmony_ci if (!loader_check_version_meets_required(loader_combine_version(1, 1, 2), version)) { 25735db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 25745db71995Sopenharmony_ci "Found pre_instance_functions section in layer from \"%s\". This section is only valid in manifest version " 25755db71995Sopenharmony_ci "1.1.2 or later. The section will be ignored", 25765db71995Sopenharmony_ci filename); 25775db71995Sopenharmony_ci } else if (!is_implicit) { 25785db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 25795db71995Sopenharmony_ci "Found pre_instance_functions section in explicit layer from \"%s\". This section is only valid in implicit " 25805db71995Sopenharmony_ci "layers. The section will be ignored", 25815db71995Sopenharmony_ci filename); 25825db71995Sopenharmony_ci } else { 25835db71995Sopenharmony_ci result = loader_parse_json_string(pre_instance, "vkEnumerateInstanceExtensionProperties", 25845db71995Sopenharmony_ci &props.pre_instance_functions.enumerate_instance_extension_properties); 25855db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25865db71995Sopenharmony_ci 25875db71995Sopenharmony_ci result = loader_parse_json_string(pre_instance, "vkEnumerateInstanceLayerProperties", 25885db71995Sopenharmony_ci &props.pre_instance_functions.enumerate_instance_layer_properties); 25895db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25905db71995Sopenharmony_ci 25915db71995Sopenharmony_ci result = loader_parse_json_string(pre_instance, "vkEnumerateInstanceVersion", 25925db71995Sopenharmony_ci &props.pre_instance_functions.enumerate_instance_version); 25935db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 25945db71995Sopenharmony_ci } 25955db71995Sopenharmony_ci } 25965db71995Sopenharmony_ci 25975db71995Sopenharmony_ci if (loader_cJSON_GetObjectItem(layer_node, "app_keys")) { 25985db71995Sopenharmony_ci if (!props.is_override) { 25995db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 26005db71995Sopenharmony_ci "Layer %s contains app_keys, but any app_keys can only be provided by the override meta layer. " 26015db71995Sopenharmony_ci "These will be ignored.", 26025db71995Sopenharmony_ci props.info.layerName); 26035db71995Sopenharmony_ci } 26045db71995Sopenharmony_ci 26055db71995Sopenharmony_ci result = loader_parse_json_array_of_strings(inst, layer_node, "app_keys", &props.app_key_paths); 26065db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 26075db71995Sopenharmony_ci } 26085db71995Sopenharmony_ci 26095db71995Sopenharmony_ci char *library_arch = NULL; 26105db71995Sopenharmony_ci result = loader_parse_json_string(layer_node, "library_arch", &library_arch); 26115db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 26125db71995Sopenharmony_ci if (library_arch != NULL) { 26135db71995Sopenharmony_ci if ((strncmp(library_arch, "32", 2) == 0 && sizeof(void *) != 4) || 26145db71995Sopenharmony_ci (strncmp(library_arch, "64", 2) == 0 && sizeof(void *) != 8)) { 26155db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 26165db71995Sopenharmony_ci "Layer library architecture doesn't match the current running architecture, skipping this layer"); 26175db71995Sopenharmony_ci loader_instance_heap_free(inst, library_arch); 26185db71995Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 26195db71995Sopenharmony_ci goto out; 26205db71995Sopenharmony_ci } 26215db71995Sopenharmony_ci loader_instance_heap_free(inst, library_arch); 26225db71995Sopenharmony_ci } 26235db71995Sopenharmony_ci 26245db71995Sopenharmony_ci result = VK_SUCCESS; 26255db71995Sopenharmony_ci 26265db71995Sopenharmony_ciout: 26275db71995Sopenharmony_ci // Try to append the layer property 26285db71995Sopenharmony_ci if (VK_SUCCESS == result) { 26295db71995Sopenharmony_ci result = loader_append_layer_property(inst, layer_instance_list, &props); 26305db71995Sopenharmony_ci } 26315db71995Sopenharmony_ci // If appending fails - free all the memory allocated in it 26325db71995Sopenharmony_ci if (VK_SUCCESS != result) { 26335db71995Sopenharmony_ci loader_free_layer_properties(inst, &props); 26345db71995Sopenharmony_ci } 26355db71995Sopenharmony_ci loader_instance_heap_free(inst, type); 26365db71995Sopenharmony_ci loader_instance_heap_free(inst, api_version); 26375db71995Sopenharmony_ci loader_instance_heap_free(inst, implementation_version); 26385db71995Sopenharmony_ci return result; 26395db71995Sopenharmony_ci} 26405db71995Sopenharmony_ci 26415db71995Sopenharmony_cibool is_valid_layer_json_version(const loader_api_version *layer_json) { 26425db71995Sopenharmony_ci // Supported versions are: 1.0.0, 1.0.1, 1.1.0 - 1.1.2, and 1.2.0 - 1.2.1. 26435db71995Sopenharmony_ci if ((layer_json->major == 1 && layer_json->minor == 2 && layer_json->patch < 2) || 26445db71995Sopenharmony_ci (layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch < 3) || 26455db71995Sopenharmony_ci (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) { 26465db71995Sopenharmony_ci return true; 26475db71995Sopenharmony_ci } 26485db71995Sopenharmony_ci return false; 26495db71995Sopenharmony_ci} 26505db71995Sopenharmony_ci 26515db71995Sopenharmony_ci// Given a cJSON struct (json) of the top level JSON object from layer manifest 26525db71995Sopenharmony_ci// file, add entry to the layer_list. Fill out the layer_properties in this list 26535db71995Sopenharmony_ci// entry from the input cJSON object. 26545db71995Sopenharmony_ci// 26555db71995Sopenharmony_ci// \returns 26565db71995Sopenharmony_ci// void 26575db71995Sopenharmony_ci// layer_list has a new entry and initialized accordingly. 26585db71995Sopenharmony_ci// If the json input object does not have all the required fields no entry 26595db71995Sopenharmony_ci// is added to the list. 26605db71995Sopenharmony_ciVkResult loader_add_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list, cJSON *json, 26615db71995Sopenharmony_ci bool is_implicit, char *filename) { 26625db71995Sopenharmony_ci // The following Fields in layer manifest file that are required: 26635db71995Sopenharmony_ci // - "file_format_version" 26645db71995Sopenharmony_ci // - If more than one "layer" object are used, then the "layers" array is 26655db71995Sopenharmony_ci // required 26665db71995Sopenharmony_ci VkResult result = VK_ERROR_INITIALIZATION_FAILED; 26675db71995Sopenharmony_ci cJSON *item, *layers_node, *layer_node; 26685db71995Sopenharmony_ci loader_api_version json_version = {0, 0, 0}; 26695db71995Sopenharmony_ci char *file_vers = NULL; 26705db71995Sopenharmony_ci // Make sure sure the top level json value is an object 26715db71995Sopenharmony_ci if (!json || json->type != 6) { 26725db71995Sopenharmony_ci goto out; 26735db71995Sopenharmony_ci } 26745db71995Sopenharmony_ci item = loader_cJSON_GetObjectItem(json, "file_format_version"); 26755db71995Sopenharmony_ci if (item == NULL) { 26765db71995Sopenharmony_ci goto out; 26775db71995Sopenharmony_ci } 26785db71995Sopenharmony_ci file_vers = loader_cJSON_PrintUnformatted(item); 26795db71995Sopenharmony_ci if (NULL == file_vers) { 26805db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 26815db71995Sopenharmony_ci goto out; 26825db71995Sopenharmony_ci } 26835db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Found manifest file %s (file version %s)", filename, file_vers); 26845db71995Sopenharmony_ci // Get the major/minor/and patch as integers for easier comparison 26855db71995Sopenharmony_ci json_version = loader_make_full_version(loader_parse_version_string(file_vers)); 26865db71995Sopenharmony_ci 26875db71995Sopenharmony_ci if (!is_valid_layer_json_version(&json_version)) { 26885db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, 26895db71995Sopenharmony_ci "loader_add_layer_properties: %s has unknown layer manifest file version %d.%d.%d. May cause errors.", filename, 26905db71995Sopenharmony_ci json_version.major, json_version.minor, json_version.patch); 26915db71995Sopenharmony_ci } 26925db71995Sopenharmony_ci 26935db71995Sopenharmony_ci // If "layers" is present, read in the array of layer objects 26945db71995Sopenharmony_ci layers_node = loader_cJSON_GetObjectItem(json, "layers"); 26955db71995Sopenharmony_ci if (layers_node != NULL) { 26965db71995Sopenharmony_ci int numItems = loader_cJSON_GetArraySize(layers_node); 26975db71995Sopenharmony_ci // Supported versions started in 1.0.1, so anything newer 26985db71995Sopenharmony_ci if (!loader_check_version_meets_required(loader_combine_version(1, 0, 1), json_version)) { 26995db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 27005db71995Sopenharmony_ci "loader_add_layer_properties: \'layers\' tag not supported until file version 1.0.1, but %s is reporting " 27015db71995Sopenharmony_ci "version %s", 27025db71995Sopenharmony_ci filename, file_vers); 27035db71995Sopenharmony_ci } 27045db71995Sopenharmony_ci for (int curLayer = 0; curLayer < numItems; curLayer++) { 27055db71995Sopenharmony_ci layer_node = loader_cJSON_GetArrayItem(layers_node, curLayer); 27065db71995Sopenharmony_ci if (layer_node == NULL) { 27075db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 27085db71995Sopenharmony_ci "loader_add_layer_properties: Can not find 'layers' array element %d object in manifest JSON file %s. " 27095db71995Sopenharmony_ci "Skipping this file", 27105db71995Sopenharmony_ci curLayer, filename); 27115db71995Sopenharmony_ci goto out; 27125db71995Sopenharmony_ci } 27135db71995Sopenharmony_ci result = loader_read_layer_json(inst, layer_instance_list, layer_node, json_version, is_implicit, filename); 27145db71995Sopenharmony_ci } 27155db71995Sopenharmony_ci } else { 27165db71995Sopenharmony_ci // Otherwise, try to read in individual layers 27175db71995Sopenharmony_ci layer_node = loader_cJSON_GetObjectItem(json, "layer"); 27185db71995Sopenharmony_ci if (layer_node == NULL) { 27195db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 27205db71995Sopenharmony_ci "loader_add_layer_properties: Can not find 'layer' object in manifest JSON file %s. Skipping this file.", 27215db71995Sopenharmony_ci filename); 27225db71995Sopenharmony_ci goto out; 27235db71995Sopenharmony_ci } 27245db71995Sopenharmony_ci // Loop through all "layer" objects in the file to get a count of them 27255db71995Sopenharmony_ci // first. 27265db71995Sopenharmony_ci uint16_t layer_count = 0; 27275db71995Sopenharmony_ci cJSON *tempNode = layer_node; 27285db71995Sopenharmony_ci do { 27295db71995Sopenharmony_ci tempNode = tempNode->next; 27305db71995Sopenharmony_ci layer_count++; 27315db71995Sopenharmony_ci } while (tempNode != NULL); 27325db71995Sopenharmony_ci 27335db71995Sopenharmony_ci // Throw a warning if we encounter multiple "layer" objects in file 27345db71995Sopenharmony_ci // versions newer than 1.0.0. Having multiple objects with the same 27355db71995Sopenharmony_ci // name at the same level is actually a JSON standard violation. 27365db71995Sopenharmony_ci if (layer_count > 1 && loader_check_version_meets_required(loader_combine_version(1, 0, 1), json_version)) { 27375db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, 27385db71995Sopenharmony_ci "loader_add_layer_properties: Multiple 'layer' nodes are deprecated starting in file version \"1.0.1\". " 27395db71995Sopenharmony_ci "Please use 'layers' : [] array instead in %s.", 27405db71995Sopenharmony_ci filename); 27415db71995Sopenharmony_ci } else { 27425db71995Sopenharmony_ci do { 27435db71995Sopenharmony_ci result = loader_read_layer_json(inst, layer_instance_list, layer_node, json_version, is_implicit, filename); 27445db71995Sopenharmony_ci layer_node = layer_node->next; 27455db71995Sopenharmony_ci } while (layer_node != NULL); 27465db71995Sopenharmony_ci } 27475db71995Sopenharmony_ci } 27485db71995Sopenharmony_ci 27495db71995Sopenharmony_ciout: 27505db71995Sopenharmony_ci loader_instance_heap_free(inst, file_vers); 27515db71995Sopenharmony_ci 27525db71995Sopenharmony_ci return result; 27535db71995Sopenharmony_ci} 27545db71995Sopenharmony_ci 27555db71995Sopenharmony_cisize_t determine_data_file_path_size(const char *cur_path, size_t relative_path_size) { 27565db71995Sopenharmony_ci size_t path_size = 0; 27575db71995Sopenharmony_ci 27585db71995Sopenharmony_ci if (NULL != cur_path) { 27595db71995Sopenharmony_ci // For each folder in cur_path, (detected by finding additional 27605db71995Sopenharmony_ci // path separators in the string) we need to add the relative path on 27615db71995Sopenharmony_ci // the end. Plus, leave an additional two slots on the end to add an 27625db71995Sopenharmony_ci // additional directory slash and path separator if needed 27635db71995Sopenharmony_ci path_size += strlen(cur_path) + relative_path_size + 2; 27645db71995Sopenharmony_ci for (const char *x = cur_path; *x; ++x) { 27655db71995Sopenharmony_ci if (*x == PATH_SEPARATOR) { 27665db71995Sopenharmony_ci path_size += relative_path_size + 2; 27675db71995Sopenharmony_ci } 27685db71995Sopenharmony_ci } 27695db71995Sopenharmony_ci } 27705db71995Sopenharmony_ci 27715db71995Sopenharmony_ci return path_size; 27725db71995Sopenharmony_ci} 27735db71995Sopenharmony_ci 27745db71995Sopenharmony_civoid copy_data_file_info(const char *cur_path, const char *relative_path, size_t relative_path_size, char **output_path) { 27755db71995Sopenharmony_ci if (NULL != cur_path) { 27765db71995Sopenharmony_ci uint32_t start = 0; 27775db71995Sopenharmony_ci uint32_t stop = 0; 27785db71995Sopenharmony_ci char *cur_write = *output_path; 27795db71995Sopenharmony_ci 27805db71995Sopenharmony_ci while (cur_path[start] != '\0') { 27815db71995Sopenharmony_ci while (cur_path[start] == PATH_SEPARATOR) { 27825db71995Sopenharmony_ci start++; 27835db71995Sopenharmony_ci } 27845db71995Sopenharmony_ci stop = start; 27855db71995Sopenharmony_ci while (cur_path[stop] != PATH_SEPARATOR && cur_path[stop] != '\0') { 27865db71995Sopenharmony_ci stop++; 27875db71995Sopenharmony_ci } 27885db71995Sopenharmony_ci const size_t s = stop - start; 27895db71995Sopenharmony_ci if (s) { 27905db71995Sopenharmony_ci memcpy(cur_write, &cur_path[start], s); 27915db71995Sopenharmony_ci cur_write += s; 27925db71995Sopenharmony_ci 27935db71995Sopenharmony_ci // If this is a specific JSON file, just add it and don't add any 27945db71995Sopenharmony_ci // relative path or directory symbol to it. 27955db71995Sopenharmony_ci if (!is_json(cur_write - 5, s)) { 27965db71995Sopenharmony_ci // Add the relative directory if present. 27975db71995Sopenharmony_ci if (relative_path_size > 0) { 27985db71995Sopenharmony_ci // If last symbol written was not a directory symbol, add it. 27995db71995Sopenharmony_ci if (*(cur_write - 1) != DIRECTORY_SYMBOL) { 28005db71995Sopenharmony_ci *cur_write++ = DIRECTORY_SYMBOL; 28015db71995Sopenharmony_ci } 28025db71995Sopenharmony_ci memcpy(cur_write, relative_path, relative_path_size); 28035db71995Sopenharmony_ci cur_write += relative_path_size; 28045db71995Sopenharmony_ci } 28055db71995Sopenharmony_ci } 28065db71995Sopenharmony_ci 28075db71995Sopenharmony_ci *cur_write++ = PATH_SEPARATOR; 28085db71995Sopenharmony_ci start = stop; 28095db71995Sopenharmony_ci } 28105db71995Sopenharmony_ci } 28115db71995Sopenharmony_ci *output_path = cur_write; 28125db71995Sopenharmony_ci } 28135db71995Sopenharmony_ci} 28145db71995Sopenharmony_ci 28155db71995Sopenharmony_ci// If the file found is a manifest file name, add it to the out_files manifest list. 28165db71995Sopenharmony_ciVkResult add_if_manifest_file(const struct loader_instance *inst, const char *file_name, struct loader_string_list *out_files) { 28175db71995Sopenharmony_ci VkResult vk_result = VK_SUCCESS; 28185db71995Sopenharmony_ci 28195db71995Sopenharmony_ci assert(NULL != file_name && "add_if_manifest_file: Received NULL pointer for file_name"); 28205db71995Sopenharmony_ci assert(NULL != out_files && "add_if_manifest_file: Received NULL pointer for out_files"); 28215db71995Sopenharmony_ci 28225db71995Sopenharmony_ci // Look for files ending with ".json" suffix 28235db71995Sopenharmony_ci size_t name_len = strlen(file_name); 28245db71995Sopenharmony_ci const char *name_suffix = file_name + name_len - 5; 28255db71995Sopenharmony_ci if (!is_json(name_suffix, name_len)) { 28265db71995Sopenharmony_ci // Use incomplete to indicate invalid name, but to keep going. 28275db71995Sopenharmony_ci vk_result = VK_INCOMPLETE; 28285db71995Sopenharmony_ci goto out; 28295db71995Sopenharmony_ci } 28305db71995Sopenharmony_ci 28315db71995Sopenharmony_ci vk_result = copy_str_to_string_list(inst, out_files, file_name, name_len); 28325db71995Sopenharmony_ci 28335db71995Sopenharmony_ciout: 28345db71995Sopenharmony_ci 28355db71995Sopenharmony_ci return vk_result; 28365db71995Sopenharmony_ci} 28375db71995Sopenharmony_ci 28385db71995Sopenharmony_ci// Add any files found in the search_path. If any path in the search path points to a specific JSON, attempt to 28395db71995Sopenharmony_ci// only open that one JSON. Otherwise, if the path is a folder, search the folder for JSON files. 28405db71995Sopenharmony_ciVkResult add_data_files(const struct loader_instance *inst, char *search_path, struct loader_string_list *out_files, 28415db71995Sopenharmony_ci bool use_first_found_manifest) { 28425db71995Sopenharmony_ci VkResult vk_result = VK_SUCCESS; 28435db71995Sopenharmony_ci DIR *dir_stream = NULL; 28445db71995Sopenharmony_ci struct dirent *dir_entry; 28455db71995Sopenharmony_ci char *cur_file; 28465db71995Sopenharmony_ci char *next_file; 28475db71995Sopenharmony_ci char *name; 28485db71995Sopenharmony_ci char full_path[2048]; 28495db71995Sopenharmony_ci#if !defined(_WIN32) 28505db71995Sopenharmony_ci char temp_path[2048]; 28515db71995Sopenharmony_ci#endif 28525db71995Sopenharmony_ci 28535db71995Sopenharmony_ci // Now, parse the paths 28545db71995Sopenharmony_ci next_file = search_path; 28555db71995Sopenharmony_ci while (NULL != next_file && *next_file != '\0') { 28565db71995Sopenharmony_ci name = NULL; 28575db71995Sopenharmony_ci cur_file = next_file; 28585db71995Sopenharmony_ci next_file = loader_get_next_path(cur_file); 28595db71995Sopenharmony_ci 28605db71995Sopenharmony_ci // Is this a JSON file, then try to open it. 28615db71995Sopenharmony_ci size_t len = strlen(cur_file); 28625db71995Sopenharmony_ci if (is_json(cur_file + len - 5, len)) { 28635db71995Sopenharmony_ci#if defined(_WIN32) 28645db71995Sopenharmony_ci name = cur_file; 28655db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 28665db71995Sopenharmony_ci // Only Linux has relative paths, make a copy of location so it isn't modified 28675db71995Sopenharmony_ci size_t str_len; 28685db71995Sopenharmony_ci if (NULL != next_file) { 28695db71995Sopenharmony_ci str_len = next_file - cur_file + 1; 28705db71995Sopenharmony_ci } else { 28715db71995Sopenharmony_ci str_len = strlen(cur_file) + 1; 28725db71995Sopenharmony_ci } 28735db71995Sopenharmony_ci if (str_len > sizeof(temp_path)) { 28745db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "add_data_files: Path to %s too long", cur_file); 28755db71995Sopenharmony_ci continue; 28765db71995Sopenharmony_ci } 28775db71995Sopenharmony_ci strncpy(temp_path, cur_file, str_len); 28785db71995Sopenharmony_ci name = temp_path; 28795db71995Sopenharmony_ci#else 28805db71995Sopenharmony_ci#warning add_data_files must define relative path copy for this platform 28815db71995Sopenharmony_ci#endif 28825db71995Sopenharmony_ci loader_get_fullpath(cur_file, name, sizeof(full_path), full_path); 28835db71995Sopenharmony_ci name = full_path; 28845db71995Sopenharmony_ci 28855db71995Sopenharmony_ci VkResult local_res; 28865db71995Sopenharmony_ci local_res = add_if_manifest_file(inst, name, out_files); 28875db71995Sopenharmony_ci 28885db71995Sopenharmony_ci // Incomplete means this was not a valid data file. 28895db71995Sopenharmony_ci if (local_res == VK_INCOMPLETE) { 28905db71995Sopenharmony_ci continue; 28915db71995Sopenharmony_ci } else if (local_res != VK_SUCCESS) { 28925db71995Sopenharmony_ci vk_result = local_res; 28935db71995Sopenharmony_ci break; 28945db71995Sopenharmony_ci } 28955db71995Sopenharmony_ci } else { // Otherwise, treat it as a directory 28965db71995Sopenharmony_ci dir_stream = loader_opendir(inst, cur_file); 28975db71995Sopenharmony_ci if (NULL == dir_stream) { 28985db71995Sopenharmony_ci continue; 28995db71995Sopenharmony_ci } 29005db71995Sopenharmony_ci while (1) { 29015db71995Sopenharmony_ci dir_entry = readdir(dir_stream); 29025db71995Sopenharmony_ci if (NULL == dir_entry) { 29035db71995Sopenharmony_ci break; 29045db71995Sopenharmony_ci } 29055db71995Sopenharmony_ci 29065db71995Sopenharmony_ci name = &(dir_entry->d_name[0]); 29075db71995Sopenharmony_ci loader_get_fullpath(name, cur_file, sizeof(full_path), full_path); 29085db71995Sopenharmony_ci name = full_path; 29095db71995Sopenharmony_ci 29105db71995Sopenharmony_ci VkResult local_res; 29115db71995Sopenharmony_ci local_res = add_if_manifest_file(inst, name, out_files); 29125db71995Sopenharmony_ci 29135db71995Sopenharmony_ci // Incomplete means this was not a valid data file. 29145db71995Sopenharmony_ci if (local_res == VK_INCOMPLETE) { 29155db71995Sopenharmony_ci continue; 29165db71995Sopenharmony_ci } else if (local_res != VK_SUCCESS) { 29175db71995Sopenharmony_ci vk_result = local_res; 29185db71995Sopenharmony_ci break; 29195db71995Sopenharmony_ci } 29205db71995Sopenharmony_ci } 29215db71995Sopenharmony_ci loader_closedir(inst, dir_stream); 29225db71995Sopenharmony_ci if (vk_result != VK_SUCCESS) { 29235db71995Sopenharmony_ci goto out; 29245db71995Sopenharmony_ci } 29255db71995Sopenharmony_ci } 29265db71995Sopenharmony_ci if (use_first_found_manifest && out_files->count > 0) { 29275db71995Sopenharmony_ci break; 29285db71995Sopenharmony_ci } 29295db71995Sopenharmony_ci } 29305db71995Sopenharmony_ci 29315db71995Sopenharmony_ciout: 29325db71995Sopenharmony_ci 29335db71995Sopenharmony_ci return vk_result; 29345db71995Sopenharmony_ci} 29355db71995Sopenharmony_ci 29365db71995Sopenharmony_ci// Look for data files in the provided paths, but first check the environment override to determine if we should use that 29375db71995Sopenharmony_ci// instead. 29385db71995Sopenharmony_ciVkResult read_data_files_in_search_paths(const struct loader_instance *inst, enum loader_data_files_type manifest_type, 29395db71995Sopenharmony_ci const char *path_override, bool *override_active, struct loader_string_list *out_files) { 29405db71995Sopenharmony_ci VkResult vk_result = VK_SUCCESS; 29415db71995Sopenharmony_ci char *override_env = NULL; 29425db71995Sopenharmony_ci const char *override_path = NULL; 29435db71995Sopenharmony_ci char *additional_env = NULL; 29445db71995Sopenharmony_ci size_t search_path_size = 0; 29455db71995Sopenharmony_ci char *search_path = NULL; 29465db71995Sopenharmony_ci char *cur_path_ptr = NULL; 29475db71995Sopenharmony_ci bool use_first_found_manifest = false; 29485db71995Sopenharmony_ci#if COMMON_UNIX_PLATFORMS 29495db71995Sopenharmony_ci char *relative_location = NULL; // Only used on unix platforms 29505db71995Sopenharmony_ci size_t rel_size = 0; // unused in windows, dont declare so no compiler warnings are generated 29515db71995Sopenharmony_ci#endif 29525db71995Sopenharmony_ci 29535db71995Sopenharmony_ci#if defined(_WIN32) 29545db71995Sopenharmony_ci char *package_path = NULL; 29555db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 29565db71995Sopenharmony_ci // Determine how much space is needed to generate the full search path 29575db71995Sopenharmony_ci // for the current manifest files. 29585db71995Sopenharmony_ci char *xdg_config_home = loader_secure_getenv("XDG_CONFIG_HOME", inst); 29595db71995Sopenharmony_ci char *xdg_config_dirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst); 29605db71995Sopenharmony_ci 29615db71995Sopenharmony_ci#if !defined(__Fuchsia__) && !defined(__QNX__) && !defined(__OHOS__) 29625db71995Sopenharmony_ci if (NULL == xdg_config_dirs || '\0' == xdg_config_dirs[0]) { 29635db71995Sopenharmony_ci xdg_config_dirs = FALLBACK_CONFIG_DIRS; 29645db71995Sopenharmony_ci } 29655db71995Sopenharmony_ci#endif 29665db71995Sopenharmony_ci 29675db71995Sopenharmony_ci char *xdg_data_home = loader_secure_getenv("XDG_DATA_HOME", inst); 29685db71995Sopenharmony_ci char *xdg_data_dirs = loader_secure_getenv("XDG_DATA_DIRS", inst); 29695db71995Sopenharmony_ci 29705db71995Sopenharmony_ci#if !defined(__Fuchsia__) && !defined(__QNX__) && !defined(__OHOS__) 29715db71995Sopenharmony_ci if (NULL == xdg_data_dirs || '\0' == xdg_data_dirs[0]) { 29725db71995Sopenharmony_ci xdg_data_dirs = FALLBACK_DATA_DIRS; 29735db71995Sopenharmony_ci } 29745db71995Sopenharmony_ci#endif 29755db71995Sopenharmony_ci 29765db71995Sopenharmony_ci char *home = NULL; 29775db71995Sopenharmony_ci char *default_data_home = NULL; 29785db71995Sopenharmony_ci char *default_config_home = NULL; 29795db71995Sopenharmony_ci char *home_data_dir = NULL; 29805db71995Sopenharmony_ci char *home_config_dir = NULL; 29815db71995Sopenharmony_ci 29825db71995Sopenharmony_ci // Only use HOME if XDG_DATA_HOME is not present on the system 29835db71995Sopenharmony_ci home = loader_secure_getenv("HOME", inst); 29845db71995Sopenharmony_ci if (home != NULL) { 29855db71995Sopenharmony_ci if (NULL == xdg_config_home || '\0' == xdg_config_home[0]) { 29865db71995Sopenharmony_ci const char config_suffix[] = "/.config"; 29875db71995Sopenharmony_ci size_t default_config_home_len = strlen(home) + sizeof(config_suffix) + 1; 29885db71995Sopenharmony_ci default_config_home = loader_instance_heap_calloc(inst, default_config_home_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 29895db71995Sopenharmony_ci if (default_config_home == NULL) { 29905db71995Sopenharmony_ci vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; 29915db71995Sopenharmony_ci goto out; 29925db71995Sopenharmony_ci } 29935db71995Sopenharmony_ci strncpy(default_config_home, home, default_config_home_len); 29945db71995Sopenharmony_ci strncat(default_config_home, config_suffix, default_config_home_len); 29955db71995Sopenharmony_ci } 29965db71995Sopenharmony_ci if (NULL == xdg_data_home || '\0' == xdg_data_home[0]) { 29975db71995Sopenharmony_ci const char data_suffix[] = "/.local/share"; 29985db71995Sopenharmony_ci size_t default_data_home_len = strlen(home) + sizeof(data_suffix) + 1; 29995db71995Sopenharmony_ci default_data_home = loader_instance_heap_calloc(inst, default_data_home_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 30005db71995Sopenharmony_ci if (default_data_home == NULL) { 30015db71995Sopenharmony_ci vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; 30025db71995Sopenharmony_ci goto out; 30035db71995Sopenharmony_ci } 30045db71995Sopenharmony_ci strncpy(default_data_home, home, default_data_home_len); 30055db71995Sopenharmony_ci strncat(default_data_home, data_suffix, default_data_home_len); 30065db71995Sopenharmony_ci } 30075db71995Sopenharmony_ci } 30085db71995Sopenharmony_ci 30095db71995Sopenharmony_ci if (NULL != default_config_home) { 30105db71995Sopenharmony_ci home_config_dir = default_config_home; 30115db71995Sopenharmony_ci } else { 30125db71995Sopenharmony_ci home_config_dir = xdg_config_home; 30135db71995Sopenharmony_ci } 30145db71995Sopenharmony_ci if (NULL != default_data_home) { 30155db71995Sopenharmony_ci home_data_dir = default_data_home; 30165db71995Sopenharmony_ci } else { 30175db71995Sopenharmony_ci home_data_dir = xdg_data_home; 30185db71995Sopenharmony_ci } 30195db71995Sopenharmony_ci 30205db71995Sopenharmony_ci#if defined(__OHOS__) 30215db71995Sopenharmony_ci char *debug_layer_name = loader_secure_getenv("debug.graphic.debug_layer", inst); // squid squidsubcapture 30225db71995Sopenharmony_ci char *debug_hap_name = loader_secure_getenv("debug.graphic.debug_hap", inst); 30235db71995Sopenharmony_ci char *debug_layer_json_path = NULL; 30245db71995Sopenharmony_ci 30255db71995Sopenharmony_ci bool currentProcessEnableDebugLayer = false; 30265db71995Sopenharmony_ci if (NULL != debug_layer_name && '\0' != debug_layer_name[0] && InitBundleInfo(debug_hap_name)) { 30275db71995Sopenharmony_ci currentProcessEnableDebugLayer = true; 30285db71995Sopenharmony_ci debug_layer_json_path = loader_secure_getenv("debug.graphic.vklayer_json_path",inst); 30295db71995Sopenharmony_ci if (NULL == debug_layer_json_path || '\0' == debug_layer_json_path[0]){ 30305db71995Sopenharmony_ci const char default_json_path[] = "/data/storage/el2/base/haps/entry/files/"; 30315db71995Sopenharmony_ci const char json_suffix[] = ".json"; 30325db71995Sopenharmony_ci size_t debug_layer_json_path_len = strlen(default_json_path) + sizeof(debug_layer_name) + sizeof(json_suffix) +1; 30335db71995Sopenharmony_ci debug_layer_json_path = loader_instance_heap_calloc(inst,debug_layer_json_path_len,VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 30345db71995Sopenharmony_ci if(debug_layer_json_path == NULL){ 30355db71995Sopenharmony_ci vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; 30365db71995Sopenharmony_ci goto out; 30375db71995Sopenharmony_ci } 30385db71995Sopenharmony_ci strncpy(debug_layer_json_path,default_json_path,debug_layer_json_path_len); 30395db71995Sopenharmony_ci strncat(debug_layer_json_path,debug_layer_name,debug_layer_json_path_len); 30405db71995Sopenharmony_ci strncat(debug_layer_json_path,json_suffix,debug_layer_json_path_len); 30415db71995Sopenharmony_ci } 30425db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "OHOS:: debug_layer_json_path: %s", debug_layer_json_path); 30435db71995Sopenharmony_ci } 30445db71995Sopenharmony_ci#endif 30455db71995Sopenharmony_ci 30465db71995Sopenharmony_ci#else 30475db71995Sopenharmony_ci#warning read_data_files_in_search_paths unsupported platform 30485db71995Sopenharmony_ci#endif 30495db71995Sopenharmony_ci 30505db71995Sopenharmony_ci switch (manifest_type) { 30515db71995Sopenharmony_ci case LOADER_DATA_FILE_MANIFEST_DRIVER: 30525db71995Sopenharmony_ci override_env = loader_secure_getenv(VK_DRIVER_FILES_ENV_VAR, inst); 30535db71995Sopenharmony_ci if (NULL == override_env) { 30545db71995Sopenharmony_ci // Not there, so fall back to the old name 30555db71995Sopenharmony_ci override_env = loader_secure_getenv(VK_ICD_FILENAMES_ENV_VAR, inst); 30565db71995Sopenharmony_ci } 30575db71995Sopenharmony_ci additional_env = loader_secure_getenv(VK_ADDITIONAL_DRIVER_FILES_ENV_VAR, inst); 30585db71995Sopenharmony_ci#if COMMON_UNIX_PLATFORMS 30595db71995Sopenharmony_ci relative_location = VK_DRIVERS_INFO_RELATIVE_DIR; 30605db71995Sopenharmony_ci#endif 30615db71995Sopenharmony_ci#if defined(_WIN32) 30625db71995Sopenharmony_ci package_path = windows_get_app_package_manifest_path(inst); 30635db71995Sopenharmony_ci#endif 30645db71995Sopenharmony_ci break; 30655db71995Sopenharmony_ci case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER: 30665db71995Sopenharmony_ci#if COMMON_UNIX_PLATFORMS 30675db71995Sopenharmony_ci relative_location = VK_ILAYERS_INFO_RELATIVE_DIR; 30685db71995Sopenharmony_ci#endif 30695db71995Sopenharmony_ci break; 30705db71995Sopenharmony_ci case LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER: 30715db71995Sopenharmony_ci override_env = loader_secure_getenv(VK_LAYER_PATH_ENV_VAR, inst); 30725db71995Sopenharmony_ci additional_env = loader_secure_getenv(VK_ADDITIONAL_LAYER_PATH_ENV_VAR, inst); 30735db71995Sopenharmony_ci#if COMMON_UNIX_PLATFORMS 30745db71995Sopenharmony_ci relative_location = VK_ELAYERS_INFO_RELATIVE_DIR; 30755db71995Sopenharmony_ci#endif 30765db71995Sopenharmony_ci break; 30775db71995Sopenharmony_ci default: 30785db71995Sopenharmony_ci assert(false && "Shouldn't get here!"); 30795db71995Sopenharmony_ci break; 30805db71995Sopenharmony_ci } 30815db71995Sopenharmony_ci 30825db71995Sopenharmony_ci // Log a message when VK_LAYER_PATH is set but the override layer paths take priority 30835db71995Sopenharmony_ci if (manifest_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER && NULL != override_env && NULL != path_override) { 30845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, 30855db71995Sopenharmony_ci "Ignoring VK_LAYER_PATH. The Override layer is active and has override paths set, which takes priority. " 30865db71995Sopenharmony_ci "VK_LAYER_PATH is set to %s", 30875db71995Sopenharmony_ci override_env); 30885db71995Sopenharmony_ci } 30895db71995Sopenharmony_ci 30905db71995Sopenharmony_ci if (path_override != NULL) { 30915db71995Sopenharmony_ci override_path = path_override; 30925db71995Sopenharmony_ci } else if (override_env != NULL) { 30935db71995Sopenharmony_ci override_path = override_env; 30945db71995Sopenharmony_ci } 30955db71995Sopenharmony_ci 30965db71995Sopenharmony_ci // Add two by default for NULL terminator and one path separator on end (just in case) 30975db71995Sopenharmony_ci search_path_size = 2; 30985db71995Sopenharmony_ci 30995db71995Sopenharmony_ci // If there's an override, use that (and the local folder if required) and nothing else 31005db71995Sopenharmony_ci if (NULL != override_path) { 31015db71995Sopenharmony_ci // Local folder and null terminator 31025db71995Sopenharmony_ci search_path_size += strlen(override_path) + 2; 31035db71995Sopenharmony_ci } else { 31045db71995Sopenharmony_ci // Add the size of any additional search paths defined in the additive environment variable 31055db71995Sopenharmony_ci if (NULL != additional_env) { 31065db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(additional_env, 0) + 2; 31075db71995Sopenharmony_ci#if defined(_WIN32) 31085db71995Sopenharmony_ci } 31095db71995Sopenharmony_ci if (NULL != package_path) { 31105db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(package_path, 0) + 2; 31115db71995Sopenharmony_ci } 31125db71995Sopenharmony_ci if (search_path_size == 2) { 31135db71995Sopenharmony_ci goto out; 31145db71995Sopenharmony_ci } 31155db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 31165db71995Sopenharmony_ci } 31175db71995Sopenharmony_ci 31185db71995Sopenharmony_ci // Add the general search folders (with the appropriate relative folder added) 31195db71995Sopenharmony_ci rel_size = strlen(relative_location); 31205db71995Sopenharmony_ci if (rel_size > 0) { 31215db71995Sopenharmony_ci#if defined(__APPLE__) 31225db71995Sopenharmony_ci search_path_size += MAXPATHLEN; 31235db71995Sopenharmony_ci#endif 31245db71995Sopenharmony_ci // Only add the home folders if defined 31255db71995Sopenharmony_ci if (NULL != home_config_dir) { 31265db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(home_config_dir, rel_size); 31275db71995Sopenharmony_ci } 31285db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(xdg_config_dirs, rel_size); 31295db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(SYSCONFDIR, rel_size); 31305db71995Sopenharmony_ci#if defined(EXTRASYSCONFDIR) 31315db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(EXTRASYSCONFDIR, rel_size); 31325db71995Sopenharmony_ci#endif 31335db71995Sopenharmony_ci // Only add the home folders if defined 31345db71995Sopenharmony_ci if (NULL != home_data_dir) { 31355db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(home_data_dir, rel_size); 31365db71995Sopenharmony_ci } 31375db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(xdg_data_dirs, rel_size); 31385db71995Sopenharmony_ci#if defined (__OHOS__) 31395db71995Sopenharmony_ci if(currentProcessEnableDebugLayer) { 31405db71995Sopenharmony_ci search_path_size += determine_data_file_path_size(debug_layer_json_path, rel_size); 31415db71995Sopenharmony_ci } 31425db71995Sopenharmony_ci search_path_size += determine_data_file_path_size("/system/etc/vulkan/swapchain", rel_size); 31435db71995Sopenharmony_ci#endif 31445db71995Sopenharmony_ci } 31455db71995Sopenharmony_ci#else 31465db71995Sopenharmony_ci#warning read_data_files_in_search_paths unsupported platform 31475db71995Sopenharmony_ci#endif 31485db71995Sopenharmony_ci } 31495db71995Sopenharmony_ci 31505db71995Sopenharmony_ci // Allocate the required space 31515db71995Sopenharmony_ci search_path = loader_instance_heap_calloc(inst, search_path_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 31525db71995Sopenharmony_ci if (NULL == search_path) { 31535db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 31545db71995Sopenharmony_ci "read_data_files_in_search_paths: Failed to allocate space for search path of length %d", 31555db71995Sopenharmony_ci (uint32_t)search_path_size); 31565db71995Sopenharmony_ci vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; 31575db71995Sopenharmony_ci goto out; 31585db71995Sopenharmony_ci } 31595db71995Sopenharmony_ci 31605db71995Sopenharmony_ci cur_path_ptr = search_path; 31615db71995Sopenharmony_ci 31625db71995Sopenharmony_ci // Add the remaining paths to the list 31635db71995Sopenharmony_ci if (NULL != override_path) { 31645db71995Sopenharmony_ci size_t override_path_len = strlen(override_path); 31655db71995Sopenharmony_ci loader_strncpy(cur_path_ptr, search_path_size, override_path, override_path_len); 31665db71995Sopenharmony_ci cur_path_ptr += override_path_len; 31675db71995Sopenharmony_ci } else { 31685db71995Sopenharmony_ci // Add any additional search paths defined in the additive environment variable 31695db71995Sopenharmony_ci if (NULL != additional_env) { 31705db71995Sopenharmony_ci copy_data_file_info(additional_env, NULL, 0, &cur_path_ptr); 31715db71995Sopenharmony_ci } 31725db71995Sopenharmony_ci 31735db71995Sopenharmony_ci#if defined(_WIN32) 31745db71995Sopenharmony_ci if (NULL != package_path) { 31755db71995Sopenharmony_ci copy_data_file_info(package_path, NULL, 0, &cur_path_ptr); 31765db71995Sopenharmony_ci } 31775db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 31785db71995Sopenharmony_ci if (rel_size > 0) { 31795db71995Sopenharmony_ci#if defined(__APPLE__) 31805db71995Sopenharmony_ci // Add the bundle's Resources dir to the beginning of the search path. 31815db71995Sopenharmony_ci // Looks for manifests in the bundle first, before any system directories. 31825db71995Sopenharmony_ci // This also appears to work unmodified for iOS, it finds the app bundle on the devices 31835db71995Sopenharmony_ci // file system. (RSW) 31845db71995Sopenharmony_ci CFBundleRef main_bundle = CFBundleGetMainBundle(); 31855db71995Sopenharmony_ci if (NULL != main_bundle) { 31865db71995Sopenharmony_ci CFURLRef ref = CFBundleCopyResourcesDirectoryURL(main_bundle); 31875db71995Sopenharmony_ci if (NULL != ref) { 31885db71995Sopenharmony_ci if (CFURLGetFileSystemRepresentation(ref, TRUE, (UInt8 *)cur_path_ptr, search_path_size)) { 31895db71995Sopenharmony_ci cur_path_ptr += strlen(cur_path_ptr); 31905db71995Sopenharmony_ci *cur_path_ptr++ = DIRECTORY_SYMBOL; 31915db71995Sopenharmony_ci memcpy(cur_path_ptr, relative_location, rel_size); 31925db71995Sopenharmony_ci cur_path_ptr += rel_size; 31935db71995Sopenharmony_ci *cur_path_ptr++ = PATH_SEPARATOR; 31945db71995Sopenharmony_ci if (manifest_type == LOADER_DATA_FILE_MANIFEST_DRIVER) { 31955db71995Sopenharmony_ci use_first_found_manifest = true; 31965db71995Sopenharmony_ci } 31975db71995Sopenharmony_ci } 31985db71995Sopenharmony_ci CFRelease(ref); 31995db71995Sopenharmony_ci } 32005db71995Sopenharmony_ci } 32015db71995Sopenharmony_ci#endif // __APPLE__ 32025db71995Sopenharmony_ci 32035db71995Sopenharmony_ci // Only add the home folders if not NULL 32045db71995Sopenharmony_ci if (NULL != home_config_dir) { 32055db71995Sopenharmony_ci copy_data_file_info(home_config_dir, relative_location, rel_size, &cur_path_ptr); 32065db71995Sopenharmony_ci } 32075db71995Sopenharmony_ci copy_data_file_info(xdg_config_dirs, relative_location, rel_size, &cur_path_ptr); 32085db71995Sopenharmony_ci copy_data_file_info(SYSCONFDIR, relative_location, rel_size, &cur_path_ptr); 32095db71995Sopenharmony_ci#if defined(EXTRASYSCONFDIR) 32105db71995Sopenharmony_ci copy_data_file_info(EXTRASYSCONFDIR, relative_location, rel_size, &cur_path_ptr); 32115db71995Sopenharmony_ci#endif 32125db71995Sopenharmony_ci 32135db71995Sopenharmony_ci // Only add the home folders if not NULL 32145db71995Sopenharmony_ci if (NULL != home_data_dir) { 32155db71995Sopenharmony_ci copy_data_file_info(home_data_dir, relative_location, rel_size, &cur_path_ptr); 32165db71995Sopenharmony_ci } 32175db71995Sopenharmony_ci copy_data_file_info(xdg_data_dirs, relative_location, rel_size, &cur_path_ptr); 32185db71995Sopenharmony_ci#if defined (__OHOS__) 32195db71995Sopenharmony_ci if(currentProcessEnableDebugLayer){ 32205db71995Sopenharmony_ci copy_data_file_info(debug_layer_json_path,relative_location,rel_size,&cur_path_ptr); 32215db71995Sopenharmony_ci } 32225db71995Sopenharmony_ci copy_data_file_info("/system/etc/vulkan/swapchain/",relative_location,rel_size,&cur_path_ptr); 32235db71995Sopenharmony_ci#endif 32245db71995Sopenharmony_ci } 32255db71995Sopenharmony_ci 32265db71995Sopenharmony_ci // Remove the last path separator 32275db71995Sopenharmony_ci --cur_path_ptr; 32285db71995Sopenharmony_ci 32295db71995Sopenharmony_ci assert(cur_path_ptr - search_path < (ptrdiff_t)search_path_size); 32305db71995Sopenharmony_ci *cur_path_ptr = '\0'; 32315db71995Sopenharmony_ci#else 32325db71995Sopenharmony_ci#warning read_data_files_in_search_paths unsupported platform 32335db71995Sopenharmony_ci#endif 32345db71995Sopenharmony_ci } 32355db71995Sopenharmony_ci 32365db71995Sopenharmony_ci // Remove duplicate paths, or it would result in duplicate extensions, duplicate devices, etc. 32375db71995Sopenharmony_ci // This uses minimal memory, but is O(N^2) on the number of paths. Expect only a few paths. 32385db71995Sopenharmony_ci char path_sep_str[2] = {PATH_SEPARATOR, '\0'}; 32395db71995Sopenharmony_ci size_t search_path_updated_size = strlen(search_path); 32405db71995Sopenharmony_ci for (size_t first = 0; first < search_path_updated_size;) { 32415db71995Sopenharmony_ci // If this is an empty path, erase it 32425db71995Sopenharmony_ci if (search_path[first] == PATH_SEPARATOR) { 32435db71995Sopenharmony_ci memmove(&search_path[first], &search_path[first + 1], search_path_updated_size - first + 1); 32445db71995Sopenharmony_ci search_path_updated_size -= 1; 32455db71995Sopenharmony_ci continue; 32465db71995Sopenharmony_ci } 32475db71995Sopenharmony_ci 32485db71995Sopenharmony_ci size_t first_end = first + 1; 32495db71995Sopenharmony_ci first_end += strcspn(&search_path[first_end], path_sep_str); 32505db71995Sopenharmony_ci for (size_t second = first_end + 1; second < search_path_updated_size;) { 32515db71995Sopenharmony_ci size_t second_end = second + 1; 32525db71995Sopenharmony_ci second_end += strcspn(&search_path[second_end], path_sep_str); 32535db71995Sopenharmony_ci if (first_end - first == second_end - second && 32545db71995Sopenharmony_ci !strncmp(&search_path[first], &search_path[second], second_end - second)) { 32555db71995Sopenharmony_ci // Found duplicate. Include PATH_SEPARATOR in second_end, then erase it from search_path. 32565db71995Sopenharmony_ci if (search_path[second_end] == PATH_SEPARATOR) { 32575db71995Sopenharmony_ci second_end++; 32585db71995Sopenharmony_ci } 32595db71995Sopenharmony_ci memmove(&search_path[second], &search_path[second_end], search_path_updated_size - second_end + 1); 32605db71995Sopenharmony_ci search_path_updated_size -= second_end - second; 32615db71995Sopenharmony_ci } else { 32625db71995Sopenharmony_ci second = second_end + 1; 32635db71995Sopenharmony_ci } 32645db71995Sopenharmony_ci } 32655db71995Sopenharmony_ci first = first_end + 1; 32665db71995Sopenharmony_ci } 32675db71995Sopenharmony_ci search_path_size = search_path_updated_size; 32685db71995Sopenharmony_ci 32695db71995Sopenharmony_ci // Print out the paths being searched if debugging is enabled 32705db71995Sopenharmony_ci uint32_t log_flags = 0; 32715db71995Sopenharmony_ci if (search_path_size > 0) { 32725db71995Sopenharmony_ci char *tmp_search_path = loader_instance_heap_alloc(inst, search_path_size + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 32735db71995Sopenharmony_ci if (NULL != tmp_search_path) { 32745db71995Sopenharmony_ci loader_strncpy(tmp_search_path, search_path_size + 1, search_path, search_path_size); 32755db71995Sopenharmony_ci tmp_search_path[search_path_size] = '\0'; 32765db71995Sopenharmony_ci if (manifest_type == LOADER_DATA_FILE_MANIFEST_DRIVER) { 32775db71995Sopenharmony_ci log_flags = VULKAN_LOADER_DRIVER_BIT; 32785db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Searching for driver manifest files"); 32795db71995Sopenharmony_ci } else { 32805db71995Sopenharmony_ci log_flags = VULKAN_LOADER_LAYER_BIT; 32815db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "Searching for %s layer manifest files", 32825db71995Sopenharmony_ci manifest_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER ? "explicit" : "implicit"); 32835db71995Sopenharmony_ci } 32845db71995Sopenharmony_ci loader_log(inst, log_flags, 0, " In following locations:"); 32855db71995Sopenharmony_ci char *cur_file; 32865db71995Sopenharmony_ci char *next_file = tmp_search_path; 32875db71995Sopenharmony_ci while (NULL != next_file && *next_file != '\0') { 32885db71995Sopenharmony_ci cur_file = next_file; 32895db71995Sopenharmony_ci next_file = loader_get_next_path(cur_file); 32905db71995Sopenharmony_ci loader_log(inst, log_flags, 0, " %s", cur_file); 32915db71995Sopenharmony_ci } 32925db71995Sopenharmony_ci loader_instance_heap_free(inst, tmp_search_path); 32935db71995Sopenharmony_ci } 32945db71995Sopenharmony_ci } 32955db71995Sopenharmony_ci 32965db71995Sopenharmony_ci // Now, parse the paths and add any manifest files found in them. 32975db71995Sopenharmony_ci vk_result = add_data_files(inst, search_path, out_files, use_first_found_manifest); 32985db71995Sopenharmony_ci 32995db71995Sopenharmony_ci if (log_flags != 0 && out_files->count > 0) { 33005db71995Sopenharmony_ci loader_log(inst, log_flags, 0, " Found the following files:"); 33015db71995Sopenharmony_ci for (uint32_t cur_file = 0; cur_file < out_files->count; ++cur_file) { 33025db71995Sopenharmony_ci loader_log(inst, log_flags, 0, " %s", out_files->list[cur_file]); 33035db71995Sopenharmony_ci } 33045db71995Sopenharmony_ci } else { 33055db71995Sopenharmony_ci loader_log(inst, log_flags, 0, " Found no files"); 33065db71995Sopenharmony_ci } 33075db71995Sopenharmony_ci 33085db71995Sopenharmony_ci if (NULL != override_path) { 33095db71995Sopenharmony_ci *override_active = true; 33105db71995Sopenharmony_ci } else { 33115db71995Sopenharmony_ci *override_active = false; 33125db71995Sopenharmony_ci } 33135db71995Sopenharmony_ci 33145db71995Sopenharmony_ciout: 33155db71995Sopenharmony_ci 33165db71995Sopenharmony_ci loader_free_getenv(additional_env, inst); 33175db71995Sopenharmony_ci loader_free_getenv(override_env, inst); 33185db71995Sopenharmony_ci#if defined(_WIN32) 33195db71995Sopenharmony_ci loader_instance_heap_free(inst, package_path); 33205db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS 33215db71995Sopenharmony_ci loader_free_getenv(xdg_config_home, inst); 33225db71995Sopenharmony_ci loader_free_getenv(xdg_config_dirs, inst); 33235db71995Sopenharmony_ci loader_free_getenv(xdg_data_home, inst); 33245db71995Sopenharmony_ci loader_free_getenv(xdg_data_dirs, inst); 33255db71995Sopenharmony_ci loader_free_getenv(xdg_data_home, inst); 33265db71995Sopenharmony_ci loader_free_getenv(home, inst); 33275db71995Sopenharmony_ci loader_instance_heap_free(inst, default_data_home); 33285db71995Sopenharmony_ci loader_instance_heap_free(inst, default_config_home); 33295db71995Sopenharmony_ci#elif defined(__OHOS__) 33305db71995Sopenharmony_ci if(currentProcessEnableDebugLayer){ 33315db71995Sopenharmony_ci loader_free_getenv(debug_layer_json_path, inst); 33325db71995Sopenharmony_ci } 33335db71995Sopenharmony_ci loader_free_getenv(debug_layer_name, inst); 33345db71995Sopenharmony_ci loader_free_getenv(debug_hap_name, inst); 33355db71995Sopenharmony_ci#else 33365db71995Sopenharmony_ci#warning read_data_files_in_search_paths unsupported platform 33375db71995Sopenharmony_ci#endif 33385db71995Sopenharmony_ci 33395db71995Sopenharmony_ci loader_instance_heap_free(inst, search_path); 33405db71995Sopenharmony_ci 33415db71995Sopenharmony_ci return vk_result; 33425db71995Sopenharmony_ci} 33435db71995Sopenharmony_ci 33445db71995Sopenharmony_ci// Find the Vulkan library manifest files. 33455db71995Sopenharmony_ci// 33465db71995Sopenharmony_ci// This function scans the appropriate locations for a list of JSON manifest files based on the 33475db71995Sopenharmony_ci// "manifest_type". The location is interpreted as Registry path on Windows and a directory path(s) 33485db71995Sopenharmony_ci// on Linux. 33495db71995Sopenharmony_ci// "home_location" is an additional directory in the users home directory to look at. It is 33505db71995Sopenharmony_ci// expanded into the dir path $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location 33515db71995Sopenharmony_ci// depending on environment variables. This "home_location" is only used on Linux. 33525db71995Sopenharmony_ci// 33535db71995Sopenharmony_ci// \returns 33545db71995Sopenharmony_ci// VKResult 33555db71995Sopenharmony_ci// A string list of manifest files to be opened in out_files param. 33565db71995Sopenharmony_ci// List has a pointer to string for each manifest filename. 33575db71995Sopenharmony_ci// When done using the list in out_files, pointers should be freed. 33585db71995Sopenharmony_ci// Location or override string lists can be either files or directories as 33595db71995Sopenharmony_ci// follows: 33605db71995Sopenharmony_ci// | location | override 33615db71995Sopenharmony_ci// -------------------------------- 33625db71995Sopenharmony_ci// Win ICD | files | files 33635db71995Sopenharmony_ci// Win Layer | files | dirs 33645db71995Sopenharmony_ci// Linux ICD | dirs | files 33655db71995Sopenharmony_ci// Linux Layer| dirs | dirs 33665db71995Sopenharmony_ci 33675db71995Sopenharmony_ciVkResult loader_get_data_files(const struct loader_instance *inst, enum loader_data_files_type manifest_type, 33685db71995Sopenharmony_ci const char *path_override, struct loader_string_list *out_files) { 33695db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 33705db71995Sopenharmony_ci bool override_active = false; 33715db71995Sopenharmony_ci 33725db71995Sopenharmony_ci // Free and init the out_files information so there's no false data left from uninitialized variables. 33735db71995Sopenharmony_ci free_string_list(inst, out_files); 33745db71995Sopenharmony_ci 33755db71995Sopenharmony_ci res = read_data_files_in_search_paths(inst, manifest_type, path_override, &override_active, out_files); 33765db71995Sopenharmony_ci if (VK_SUCCESS != res) { 33775db71995Sopenharmony_ci goto out; 33785db71995Sopenharmony_ci } 33795db71995Sopenharmony_ci 33805db71995Sopenharmony_ci#if defined(_WIN32) 33815db71995Sopenharmony_ci // Read the registry if the override wasn't active. 33825db71995Sopenharmony_ci if (!override_active) { 33835db71995Sopenharmony_ci bool warn_if_not_present = false; 33845db71995Sopenharmony_ci char *registry_location = NULL; 33855db71995Sopenharmony_ci 33865db71995Sopenharmony_ci switch (manifest_type) { 33875db71995Sopenharmony_ci default: 33885db71995Sopenharmony_ci goto out; 33895db71995Sopenharmony_ci case LOADER_DATA_FILE_MANIFEST_DRIVER: 33905db71995Sopenharmony_ci warn_if_not_present = true; 33915db71995Sopenharmony_ci registry_location = VK_DRIVERS_INFO_REGISTRY_LOC; 33925db71995Sopenharmony_ci break; 33935db71995Sopenharmony_ci case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER: 33945db71995Sopenharmony_ci registry_location = VK_ILAYERS_INFO_REGISTRY_LOC; 33955db71995Sopenharmony_ci break; 33965db71995Sopenharmony_ci case LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER: 33975db71995Sopenharmony_ci warn_if_not_present = true; 33985db71995Sopenharmony_ci registry_location = VK_ELAYERS_INFO_REGISTRY_LOC; 33995db71995Sopenharmony_ci break; 34005db71995Sopenharmony_ci } 34015db71995Sopenharmony_ci VkResult tmp_res = 34025db71995Sopenharmony_ci windows_read_data_files_in_registry(inst, manifest_type, warn_if_not_present, registry_location, out_files); 34035db71995Sopenharmony_ci // Only return an error if there was an error this time, and no manifest files from before. 34045db71995Sopenharmony_ci if (VK_SUCCESS != tmp_res && out_files->count == 0) { 34055db71995Sopenharmony_ci res = tmp_res; 34065db71995Sopenharmony_ci goto out; 34075db71995Sopenharmony_ci } 34085db71995Sopenharmony_ci } 34095db71995Sopenharmony_ci#endif 34105db71995Sopenharmony_ci 34115db71995Sopenharmony_ciout: 34125db71995Sopenharmony_ci 34135db71995Sopenharmony_ci if (VK_SUCCESS != res) { 34145db71995Sopenharmony_ci free_string_list(inst, out_files); 34155db71995Sopenharmony_ci } 34165db71995Sopenharmony_ci 34175db71995Sopenharmony_ci return res; 34185db71995Sopenharmony_ci} 34195db71995Sopenharmony_ci 34205db71995Sopenharmony_cistruct ICDManifestInfo { 34215db71995Sopenharmony_ci char *full_library_path; 34225db71995Sopenharmony_ci uint32_t version; 34235db71995Sopenharmony_ci}; 34245db71995Sopenharmony_ci 34255db71995Sopenharmony_ci// Takes a json file, opens, reads, and parses an ICD Manifest out of it. 34265db71995Sopenharmony_ci// Should only return VK_SUCCESS, VK_ERROR_INCOMPATIBLE_DRIVER, or VK_ERROR_OUT_OF_HOST_MEMORY 34275db71995Sopenharmony_ciVkResult loader_parse_icd_manifest(const struct loader_instance *inst, char *file_str, struct ICDManifestInfo *icd, 34285db71995Sopenharmony_ci bool *skipped_portability_drivers) { 34295db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 34305db71995Sopenharmony_ci cJSON *json = NULL; 34315db71995Sopenharmony_ci char *file_vers_str = NULL; 34325db71995Sopenharmony_ci char *library_arch_str = NULL; 34335db71995Sopenharmony_ci char *version_str = NULL; 34345db71995Sopenharmony_ci 34355db71995Sopenharmony_ci if (file_str == NULL) { 34365db71995Sopenharmony_ci goto out; 34375db71995Sopenharmony_ci } 34385db71995Sopenharmony_ci 34395db71995Sopenharmony_ci res = loader_get_json(inst, file_str, &json); 34405db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 34415db71995Sopenharmony_ci goto out; 34425db71995Sopenharmony_ci } 34435db71995Sopenharmony_ci if (res != VK_SUCCESS || NULL == json) { 34445db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 34455db71995Sopenharmony_ci goto out; 34465db71995Sopenharmony_ci } 34475db71995Sopenharmony_ci 34485db71995Sopenharmony_ci cJSON *item = loader_cJSON_GetObjectItem(json, "file_format_version"); 34495db71995Sopenharmony_ci if (item == NULL) { 34505db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 34515db71995Sopenharmony_ci "loader_parse_icd_manifest: ICD JSON %s does not have a \'file_format_version\' field. Skipping ICD JSON.", 34525db71995Sopenharmony_ci file_str); 34535db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 34545db71995Sopenharmony_ci goto out; 34555db71995Sopenharmony_ci } 34565db71995Sopenharmony_ci 34575db71995Sopenharmony_ci file_vers_str = loader_cJSON_Print(item); 34585db71995Sopenharmony_ci if (NULL == file_vers_str) { 34595db71995Sopenharmony_ci // Only reason the print can fail is if there was an allocation issue 34605db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 34615db71995Sopenharmony_ci "loader_parse_icd_manifest: Failed retrieving ICD JSON %s \'file_format_version\' field. Skipping ICD JSON", 34625db71995Sopenharmony_ci file_str); 34635db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 34645db71995Sopenharmony_ci goto out; 34655db71995Sopenharmony_ci } 34665db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Found ICD manifest file %s, version %s", file_str, file_vers_str); 34675db71995Sopenharmony_ci 34685db71995Sopenharmony_ci // Get the version of the driver manifest 34695db71995Sopenharmony_ci loader_api_version json_file_version = loader_make_full_version(loader_parse_version_string(file_vers_str)); 34705db71995Sopenharmony_ci 34715db71995Sopenharmony_ci // Loader only knows versions 1.0.0 and 1.0.1, anything above it is unknown 34725db71995Sopenharmony_ci if (loader_check_version_meets_required(loader_combine_version(1, 0, 2), json_file_version)) { 34735db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 34745db71995Sopenharmony_ci "loader_parse_icd_manifest: %s has unknown icd manifest file version %d.%d.%d. May cause errors.", file_str, 34755db71995Sopenharmony_ci json_file_version.major, json_file_version.minor, json_file_version.patch); 34765db71995Sopenharmony_ci } 34775db71995Sopenharmony_ci 34785db71995Sopenharmony_ci cJSON *itemICD = loader_cJSON_GetObjectItem(json, "ICD"); 34795db71995Sopenharmony_ci if (itemICD == NULL) { 34805db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 34815db71995Sopenharmony_ci "loader_parse_icd_manifest: Can not find \'ICD\' object in ICD JSON file %s. Skipping ICD JSON", file_str); 34825db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 34835db71995Sopenharmony_ci goto out; 34845db71995Sopenharmony_ci } 34855db71995Sopenharmony_ci 34865db71995Sopenharmony_ci item = loader_cJSON_GetObjectItem(itemICD, "library_path"); 34875db71995Sopenharmony_ci if (item == NULL) { 34885db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 34895db71995Sopenharmony_ci "loader_parse_icd_manifest: Failed to find \'library_path\' object in ICD JSON file %s. Skipping ICD JSON.", 34905db71995Sopenharmony_ci file_str); 34915db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 34925db71995Sopenharmony_ci goto out; 34935db71995Sopenharmony_ci } 34945db71995Sopenharmony_ci char *library_path = loader_cJSON_Print(item); 34955db71995Sopenharmony_ci if (!library_path) { 34965db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 34975db71995Sopenharmony_ci "loader_parse_icd_manifest: Failed retrieving ICD JSON %s \'library_path\' field. Skipping ICD JSON.", file_str); 34985db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 34995db71995Sopenharmony_ci goto out; 35005db71995Sopenharmony_ci } 35015db71995Sopenharmony_ci 35025db71995Sopenharmony_ci if (strlen(library_path) == 0) { 35035db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 35045db71995Sopenharmony_ci "loader_parse_icd_manifest: ICD JSON %s \'library_path\' field is empty. Skipping ICD JSON.", file_str); 35055db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 35065db71995Sopenharmony_ci goto out; 35075db71995Sopenharmony_ci } 35085db71995Sopenharmony_ci 35095db71995Sopenharmony_ci // Print out the paths being searched if debugging is enabled 35105db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "Searching for ICD drivers named %s", library_path); 35115db71995Sopenharmony_ci // This function takes ownership of library_path - so we don't need to clean it up 35125db71995Sopenharmony_ci res = combine_manifest_directory_and_library_path(inst, library_path, file_str, &icd->full_library_path); 35135db71995Sopenharmony_ci if (VK_SUCCESS != res) { 35145db71995Sopenharmony_ci goto out; 35155db71995Sopenharmony_ci } 35165db71995Sopenharmony_ci 35175db71995Sopenharmony_ci item = loader_cJSON_GetObjectItem(itemICD, "api_version"); 35185db71995Sopenharmony_ci if (item == NULL) { 35195db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 35205db71995Sopenharmony_ci "loader_parse_icd_manifest: ICD JSON %s does not have an \'api_version\' field. Skipping ICD JSON.", file_str); 35215db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 35225db71995Sopenharmony_ci goto out; 35235db71995Sopenharmony_ci } 35245db71995Sopenharmony_ci version_str = loader_cJSON_Print(item); 35255db71995Sopenharmony_ci if (NULL == version_str) { 35265db71995Sopenharmony_ci // Only reason the print can fail is if there was an allocation issue 35275db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 35285db71995Sopenharmony_ci "loader_parse_icd_manifest: Failed retrieving ICD JSON %s \'api_version\' field. Skipping ICD JSON.", file_str); 35295db71995Sopenharmony_ci 35305db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 35315db71995Sopenharmony_ci goto out; 35325db71995Sopenharmony_ci } 35335db71995Sopenharmony_ci icd->version = loader_parse_version_string(version_str); 35345db71995Sopenharmony_ci 35355db71995Sopenharmony_ci if (VK_API_VERSION_VARIANT(icd->version) != 0) { 35365db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 35375db71995Sopenharmony_ci "loader_parse_icd_manifest: Driver's ICD JSON %s \'api_version\' field contains a non-zero variant value of %d. " 35385db71995Sopenharmony_ci " Skipping ICD JSON.", 35395db71995Sopenharmony_ci file_str, VK_API_VERSION_VARIANT(icd->version)); 35405db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 35415db71995Sopenharmony_ci goto out; 35425db71995Sopenharmony_ci } 35435db71995Sopenharmony_ci 35445db71995Sopenharmony_ci // Skip over ICD's which contain a true "is_portability_driver" value whenever the application doesn't enable 35455db71995Sopenharmony_ci // portability enumeration. 35465db71995Sopenharmony_ci item = loader_cJSON_GetObjectItem(itemICD, "is_portability_driver"); 35475db71995Sopenharmony_ci if (item != NULL && item->type == cJSON_True && inst && !inst->portability_enumeration_enabled) { 35485db71995Sopenharmony_ci if (skipped_portability_drivers) { 35495db71995Sopenharmony_ci *skipped_portability_drivers = true; 35505db71995Sopenharmony_ci } 35515db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 35525db71995Sopenharmony_ci goto out; 35535db71995Sopenharmony_ci } 35545db71995Sopenharmony_ci 35555db71995Sopenharmony_ci item = loader_cJSON_GetObjectItem(itemICD, "library_arch"); 35565db71995Sopenharmony_ci if (item != NULL) { 35575db71995Sopenharmony_ci library_arch_str = loader_cJSON_Print(item); 35585db71995Sopenharmony_ci if (NULL != library_arch_str) { 35595db71995Sopenharmony_ci // cJSON includes the quotes by default, so we need to look for those here 35605db71995Sopenharmony_ci if ((strncmp(library_arch_str, "32", 4) == 0 && sizeof(void *) != 4) || 35615db71995Sopenharmony_ci (strncmp(library_arch_str, "64", 4) == 0 && sizeof(void *) != 8)) { 35625db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 35635db71995Sopenharmony_ci "loader_parse_icd_manifest: Driver library architecture doesn't match the current running " 35645db71995Sopenharmony_ci "architecture, skipping this driver"); 35655db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 35665db71995Sopenharmony_ci goto out; 35675db71995Sopenharmony_ci } 35685db71995Sopenharmony_ci } else { 35695db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 35705db71995Sopenharmony_ci goto out; 35715db71995Sopenharmony_ci } 35725db71995Sopenharmony_ci } 35735db71995Sopenharmony_ciout: 35745db71995Sopenharmony_ci loader_cJSON_Delete(json); 35755db71995Sopenharmony_ci loader_instance_heap_free(inst, file_vers_str); 35765db71995Sopenharmony_ci loader_instance_heap_free(inst, version_str); 35775db71995Sopenharmony_ci loader_instance_heap_free(inst, library_arch_str); 35785db71995Sopenharmony_ci return res; 35795db71995Sopenharmony_ci} 35805db71995Sopenharmony_ci 35815db71995Sopenharmony_ci// Try to find the Vulkan ICD driver(s). 35825db71995Sopenharmony_ci// 35835db71995Sopenharmony_ci// This function scans the default system loader path(s) or path specified by either the 35845db71995Sopenharmony_ci// VK_DRIVER_FILES or VK_ICD_FILENAMES environment variable in order to find loadable 35855db71995Sopenharmony_ci// VK ICDs manifest files. 35865db71995Sopenharmony_ci// From these manifest files it finds the ICD libraries. 35875db71995Sopenharmony_ci// 35885db71995Sopenharmony_ci// skipped_portability_drivers is used to report whether the loader found drivers which report 35895db71995Sopenharmony_ci// portability but the application didn't enable the bit to enumerate them 35905db71995Sopenharmony_ci// Can be NULL 35915db71995Sopenharmony_ci// 35925db71995Sopenharmony_ci// \returns 35935db71995Sopenharmony_ci// Vulkan result 35945db71995Sopenharmony_ci// (on result == VK_SUCCESS) a list of icds that were discovered 35955db71995Sopenharmony_ciVkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list, 35965db71995Sopenharmony_ci const VkInstanceCreateInfo *pCreateInfo, bool *skipped_portability_drivers) { 35975db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 35985db71995Sopenharmony_ci struct loader_string_list manifest_files = {0}; 35995db71995Sopenharmony_ci struct loader_envvar_filter select_filter = {0}; 36005db71995Sopenharmony_ci struct loader_envvar_filter disable_filter = {0}; 36015db71995Sopenharmony_ci struct ICDManifestInfo *icd_details = NULL; 36025db71995Sopenharmony_ci 36035db71995Sopenharmony_ci // Set up the ICD Trampoline list so elements can be written into it. 36045db71995Sopenharmony_ci res = loader_scanned_icd_init(inst, icd_tramp_list); 36055db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 36065db71995Sopenharmony_ci return res; 36075db71995Sopenharmony_ci } 36085db71995Sopenharmony_ci 36095db71995Sopenharmony_ci bool direct_driver_loading_exclusive_mode = false; 36105db71995Sopenharmony_ci res = loader_scan_for_direct_drivers(inst, pCreateInfo, icd_tramp_list, &direct_driver_loading_exclusive_mode); 36115db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 36125db71995Sopenharmony_ci goto out; 36135db71995Sopenharmony_ci } 36145db71995Sopenharmony_ci if (direct_driver_loading_exclusive_mode) { 36155db71995Sopenharmony_ci // Make sure to jump over the system & env-var driver discovery mechanisms if exclusive mode is set, even if no drivers 36165db71995Sopenharmony_ci // were successfully found through the direct driver loading mechanism 36175db71995Sopenharmony_ci goto out; 36185db71995Sopenharmony_ci } 36195db71995Sopenharmony_ci 36205db71995Sopenharmony_ci // Parse the filter environment variables to determine if we have any special behavior 36215db71995Sopenharmony_ci res = parse_generic_filter_environment_var(inst, VK_DRIVERS_SELECT_ENV_VAR, &select_filter); 36225db71995Sopenharmony_ci if (VK_SUCCESS != res) { 36235db71995Sopenharmony_ci goto out; 36245db71995Sopenharmony_ci } 36255db71995Sopenharmony_ci res = parse_generic_filter_environment_var(inst, VK_DRIVERS_DISABLE_ENV_VAR, &disable_filter); 36265db71995Sopenharmony_ci if (VK_SUCCESS != res) { 36275db71995Sopenharmony_ci goto out; 36285db71995Sopenharmony_ci } 36295db71995Sopenharmony_ci 36305db71995Sopenharmony_ci // Get a list of manifest files for ICDs 36315db71995Sopenharmony_ci res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_DRIVER, NULL, &manifest_files); 36325db71995Sopenharmony_ci if (VK_SUCCESS != res) { 36335db71995Sopenharmony_ci goto out; 36345db71995Sopenharmony_ci } 36355db71995Sopenharmony_ci 36365db71995Sopenharmony_ci icd_details = loader_stack_alloc(sizeof(struct ICDManifestInfo) * manifest_files.count); 36375db71995Sopenharmony_ci if (NULL == icd_details) { 36385db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 36395db71995Sopenharmony_ci goto out; 36405db71995Sopenharmony_ci } 36415db71995Sopenharmony_ci memset(icd_details, 0, sizeof(struct ICDManifestInfo) * manifest_files.count); 36425db71995Sopenharmony_ci 36435db71995Sopenharmony_ci for (uint32_t i = 0; i < manifest_files.count; i++) { 36445db71995Sopenharmony_ci VkResult icd_res = VK_SUCCESS; 36455db71995Sopenharmony_ci 36465db71995Sopenharmony_ci icd_res = loader_parse_icd_manifest(inst, manifest_files.list[i], &icd_details[i], skipped_portability_drivers); 36475db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_res) { 36485db71995Sopenharmony_ci res = icd_res; 36495db71995Sopenharmony_ci goto out; 36505db71995Sopenharmony_ci } else if (VK_ERROR_INCOMPATIBLE_DRIVER == icd_res) { 36515db71995Sopenharmony_ci continue; 36525db71995Sopenharmony_ci } 36535db71995Sopenharmony_ci 36545db71995Sopenharmony_ci if (select_filter.count > 0 || disable_filter.count > 0) { 36555db71995Sopenharmony_ci // Get only the filename for comparing to the filters 36565db71995Sopenharmony_ci char *just_filename_str = strrchr(manifest_files.list[i], DIRECTORY_SYMBOL); 36575db71995Sopenharmony_ci 36585db71995Sopenharmony_ci // No directory symbol, just the filename 36595db71995Sopenharmony_ci if (NULL == just_filename_str) { 36605db71995Sopenharmony_ci just_filename_str = manifest_files.list[i]; 36615db71995Sopenharmony_ci } else { 36625db71995Sopenharmony_ci just_filename_str++; 36635db71995Sopenharmony_ci } 36645db71995Sopenharmony_ci 36655db71995Sopenharmony_ci bool name_matches_select = 36665db71995Sopenharmony_ci (select_filter.count > 0 && check_name_matches_filter_environment_var(just_filename_str, &select_filter)); 36675db71995Sopenharmony_ci bool name_matches_disable = 36685db71995Sopenharmony_ci (disable_filter.count > 0 && check_name_matches_filter_environment_var(just_filename_str, &disable_filter)); 36695db71995Sopenharmony_ci 36705db71995Sopenharmony_ci if (name_matches_disable && !name_matches_select) { 36715db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 36725db71995Sopenharmony_ci "Driver \"%s\" ignored because it was disabled by env var \'%s\'", just_filename_str, 36735db71995Sopenharmony_ci VK_DRIVERS_DISABLE_ENV_VAR); 36745db71995Sopenharmony_ci continue; 36755db71995Sopenharmony_ci } 36765db71995Sopenharmony_ci if (select_filter.count != 0 && !name_matches_select) { 36775db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 36785db71995Sopenharmony_ci "Driver \"%s\" ignored because not selected by env var \'%s\'", just_filename_str, 36795db71995Sopenharmony_ci VK_DRIVERS_SELECT_ENV_VAR); 36805db71995Sopenharmony_ci continue; 36815db71995Sopenharmony_ci } 36825db71995Sopenharmony_ci } 36835db71995Sopenharmony_ci 36845db71995Sopenharmony_ci enum loader_layer_library_status lib_status; 36855db71995Sopenharmony_ci icd_res = 36865db71995Sopenharmony_ci loader_scanned_icd_add(inst, icd_tramp_list, icd_details[i].full_library_path, icd_details[i].version, &lib_status); 36875db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_res) { 36885db71995Sopenharmony_ci res = icd_res; 36895db71995Sopenharmony_ci goto out; 36905db71995Sopenharmony_ci } else if (VK_ERROR_INCOMPATIBLE_DRIVER == icd_res) { 36915db71995Sopenharmony_ci switch (lib_status) { 36925db71995Sopenharmony_ci case LOADER_LAYER_LIB_NOT_LOADED: 36935db71995Sopenharmony_ci case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD: 36945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 36955db71995Sopenharmony_ci "loader_icd_scan: Failed loading library associated with ICD JSON %s. Ignoring this JSON", 36965db71995Sopenharmony_ci icd_details[i].full_library_path); 36975db71995Sopenharmony_ci break; 36985db71995Sopenharmony_ci case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: { 36995db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Requested ICD %s was wrong bit-type. Ignoring this JSON", 37005db71995Sopenharmony_ci icd_details[i].full_library_path); 37015db71995Sopenharmony_ci break; 37025db71995Sopenharmony_ci } 37035db71995Sopenharmony_ci case LOADER_LAYER_LIB_SUCCESS_LOADED: 37045db71995Sopenharmony_ci case LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY: 37055db71995Sopenharmony_ci // Shouldn't be able to reach this but if it is, best to report a debug 37065db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 37075db71995Sopenharmony_ci "Shouldn't reach this. A valid version of requested ICD %s was loaded but something bad " 37085db71995Sopenharmony_ci "happened afterwards.", 37095db71995Sopenharmony_ci icd_details[i].full_library_path); 37105db71995Sopenharmony_ci break; 37115db71995Sopenharmony_ci } 37125db71995Sopenharmony_ci } 37135db71995Sopenharmony_ci } 37145db71995Sopenharmony_ci 37155db71995Sopenharmony_ciout: 37165db71995Sopenharmony_ci if (NULL != icd_details) { 37175db71995Sopenharmony_ci // Successfully got the icd_details structure, which means we need to free the paths contained within 37185db71995Sopenharmony_ci for (uint32_t i = 0; i < manifest_files.count; i++) { 37195db71995Sopenharmony_ci loader_instance_heap_free(inst, icd_details[i].full_library_path); 37205db71995Sopenharmony_ci } 37215db71995Sopenharmony_ci } 37225db71995Sopenharmony_ci free_string_list(inst, &manifest_files); 37235db71995Sopenharmony_ci return res; 37245db71995Sopenharmony_ci} 37255db71995Sopenharmony_ci 37265db71995Sopenharmony_ci// Gets the layer data files corresponding to manifest_type & path_override, then parses the resulting json objects 37275db71995Sopenharmony_ci// into instance_layers 37285db71995Sopenharmony_ci// Manifest type must be either implicit or explicit 37295db71995Sopenharmony_ciVkResult loader_parse_instance_layers(struct loader_instance *inst, enum loader_data_files_type manifest_type, 37305db71995Sopenharmony_ci const char *path_override, struct loader_layer_list *instance_layers) { 37315db71995Sopenharmony_ci assert(manifest_type == LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER || manifest_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER); 37325db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 37335db71995Sopenharmony_ci struct loader_string_list manifest_files = {0}; 37345db71995Sopenharmony_ci 37355db71995Sopenharmony_ci res = loader_get_data_files(inst, manifest_type, path_override, &manifest_files); 37365db71995Sopenharmony_ci if (VK_SUCCESS != res) { 37375db71995Sopenharmony_ci goto out; 37385db71995Sopenharmony_ci } 37395db71995Sopenharmony_ci 37405db71995Sopenharmony_ci for (uint32_t i = 0; i < manifest_files.count; i++) { 37415db71995Sopenharmony_ci char *file_str = manifest_files.list[i]; 37425db71995Sopenharmony_ci if (file_str == NULL) { 37435db71995Sopenharmony_ci continue; 37445db71995Sopenharmony_ci } 37455db71995Sopenharmony_ci 37465db71995Sopenharmony_ci // Parse file into JSON struct 37475db71995Sopenharmony_ci cJSON *json = NULL; 37485db71995Sopenharmony_ci VkResult local_res = loader_get_json(inst, file_str, &json); 37495db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) { 37505db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 37515db71995Sopenharmony_ci goto out; 37525db71995Sopenharmony_ci } else if (VK_SUCCESS != local_res || NULL == json) { 37535db71995Sopenharmony_ci continue; 37545db71995Sopenharmony_ci } 37555db71995Sopenharmony_ci 37565db71995Sopenharmony_ci local_res = loader_add_layer_properties(inst, instance_layers, json, 37575db71995Sopenharmony_ci manifest_type == LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, file_str); 37585db71995Sopenharmony_ci loader_cJSON_Delete(json); 37595db71995Sopenharmony_ci 37605db71995Sopenharmony_ci // If the error is anything other than out of memory we still want to try to load the other layers 37615db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) { 37625db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 37635db71995Sopenharmony_ci goto out; 37645db71995Sopenharmony_ci } 37655db71995Sopenharmony_ci } 37665db71995Sopenharmony_ciout: 37675db71995Sopenharmony_ci free_string_list(inst, &manifest_files); 37685db71995Sopenharmony_ci 37695db71995Sopenharmony_ci return res; 37705db71995Sopenharmony_ci} 37715db71995Sopenharmony_ci 37725db71995Sopenharmony_ci// Given a loader_layer_properties struct that is a valid override layer, concatenate the properties override paths and put them 37735db71995Sopenharmony_ci// into the output parameter override_paths 37745db71995Sopenharmony_ciVkResult get_override_layer_override_paths(struct loader_instance *inst, struct loader_layer_properties *prop, 37755db71995Sopenharmony_ci char **override_paths) { 37765db71995Sopenharmony_ci if (prop->override_paths.count > 0) { 37775db71995Sopenharmony_ci char *cur_write_ptr = NULL; 37785db71995Sopenharmony_ci size_t override_path_size = 0; 37795db71995Sopenharmony_ci for (uint32_t j = 0; j < prop->override_paths.count; j++) { 37805db71995Sopenharmony_ci override_path_size += determine_data_file_path_size(prop->override_paths.list[j], 0); 37815db71995Sopenharmony_ci } 37825db71995Sopenharmony_ci *override_paths = loader_instance_heap_alloc(inst, override_path_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 37835db71995Sopenharmony_ci if (*override_paths == NULL) { 37845db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 37855db71995Sopenharmony_ci } 37865db71995Sopenharmony_ci cur_write_ptr = &(*override_paths)[0]; 37875db71995Sopenharmony_ci for (uint32_t j = 0; j < prop->override_paths.count; j++) { 37885db71995Sopenharmony_ci copy_data_file_info(prop->override_paths.list[j], NULL, 0, &cur_write_ptr); 37895db71995Sopenharmony_ci } 37905db71995Sopenharmony_ci // Remove the last path separator 37915db71995Sopenharmony_ci --cur_write_ptr; 37925db71995Sopenharmony_ci assert(cur_write_ptr - (*override_paths) < (ptrdiff_t)override_path_size); 37935db71995Sopenharmony_ci *cur_write_ptr = '\0'; 37945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Override layer has override paths set to %s", 37955db71995Sopenharmony_ci *override_paths); 37965db71995Sopenharmony_ci } 37975db71995Sopenharmony_ci return VK_SUCCESS; 37985db71995Sopenharmony_ci} 37995db71995Sopenharmony_ci 38005db71995Sopenharmony_ciVkResult loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers, 38015db71995Sopenharmony_ci const struct loader_envvar_all_filters *filters) { 38025db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 38035db71995Sopenharmony_ci struct loader_layer_list settings_layers = {0}; 38045db71995Sopenharmony_ci struct loader_layer_list regular_instance_layers = {0}; 38055db71995Sopenharmony_ci bool override_layer_valid = false; 38065db71995Sopenharmony_ci char *override_paths = NULL; 38075db71995Sopenharmony_ci 38085db71995Sopenharmony_ci bool should_search_for_other_layers = true; 38095db71995Sopenharmony_ci res = get_settings_layers(inst, &settings_layers, &should_search_for_other_layers); 38105db71995Sopenharmony_ci if (VK_SUCCESS != res) { 38115db71995Sopenharmony_ci goto out; 38125db71995Sopenharmony_ci } 38135db71995Sopenharmony_ci 38145db71995Sopenharmony_ci // If we should not look for layers using other mechanisms, assign settings_layers to instance_layers and jump to the 38155db71995Sopenharmony_ci // output 38165db71995Sopenharmony_ci if (!should_search_for_other_layers) { 38175db71995Sopenharmony_ci *instance_layers = settings_layers; 38185db71995Sopenharmony_ci memset(&settings_layers, 0, sizeof(struct loader_layer_list)); 38195db71995Sopenharmony_ci goto out; 38205db71995Sopenharmony_ci } 38215db71995Sopenharmony_ci 38225db71995Sopenharmony_ci res = loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, ®ular_instance_layers); 38235db71995Sopenharmony_ci if (VK_SUCCESS != res) { 38245db71995Sopenharmony_ci goto out; 38255db71995Sopenharmony_ci } 38265db71995Sopenharmony_ci 38275db71995Sopenharmony_ci // Remove any extraneous override layers. 38285db71995Sopenharmony_ci remove_all_non_valid_override_layers(inst, ®ular_instance_layers); 38295db71995Sopenharmony_ci 38305db71995Sopenharmony_ci // Check to see if the override layer is present, and use it's override paths. 38315db71995Sopenharmony_ci for (uint32_t i = 0; i < regular_instance_layers.count; i++) { 38325db71995Sopenharmony_ci struct loader_layer_properties *prop = ®ular_instance_layers.list[i]; 38335db71995Sopenharmony_ci if (prop->is_override && loader_implicit_layer_is_enabled(inst, filters, prop) && prop->override_paths.count > 0) { 38345db71995Sopenharmony_ci res = get_override_layer_override_paths(inst, prop, &override_paths); 38355db71995Sopenharmony_ci if (VK_SUCCESS != res) { 38365db71995Sopenharmony_ci goto out; 38375db71995Sopenharmony_ci } 38385db71995Sopenharmony_ci break; 38395db71995Sopenharmony_ci } 38405db71995Sopenharmony_ci } 38415db71995Sopenharmony_ci 38425db71995Sopenharmony_ci // Get a list of manifest files for explicit layers 38435db71995Sopenharmony_ci res = loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER, override_paths, ®ular_instance_layers); 38445db71995Sopenharmony_ci if (VK_SUCCESS != res) { 38455db71995Sopenharmony_ci goto out; 38465db71995Sopenharmony_ci } 38475db71995Sopenharmony_ci 38485db71995Sopenharmony_ci // Verify any meta-layers in the list are valid and all the component layers are 38495db71995Sopenharmony_ci // actually present in the available layer list 38505db71995Sopenharmony_ci res = verify_all_meta_layers(inst, filters, ®ular_instance_layers, &override_layer_valid); 38515db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 38525db71995Sopenharmony_ci return res; 38535db71995Sopenharmony_ci } 38545db71995Sopenharmony_ci 38555db71995Sopenharmony_ci if (override_layer_valid) { 38565db71995Sopenharmony_ci loader_remove_layers_in_blacklist(inst, ®ular_instance_layers); 38575db71995Sopenharmony_ci if (NULL != inst) { 38585db71995Sopenharmony_ci inst->override_layer_present = true; 38595db71995Sopenharmony_ci } 38605db71995Sopenharmony_ci } 38615db71995Sopenharmony_ci 38625db71995Sopenharmony_ci // Remove disabled layers 38635db71995Sopenharmony_ci for (uint32_t i = 0; i < regular_instance_layers.count; ++i) { 38645db71995Sopenharmony_ci if (!loader_layer_is_available(inst, filters, ®ular_instance_layers.list[i])) { 38655db71995Sopenharmony_ci loader_remove_layer_in_list(inst, ®ular_instance_layers, i); 38665db71995Sopenharmony_ci i--; 38675db71995Sopenharmony_ci } 38685db71995Sopenharmony_ci } 38695db71995Sopenharmony_ci 38705db71995Sopenharmony_ci res = combine_settings_layers_with_regular_layers(inst, &settings_layers, ®ular_instance_layers, instance_layers); 38715db71995Sopenharmony_ci 38725db71995Sopenharmony_ciout: 38735db71995Sopenharmony_ci loader_delete_layer_list_and_properties(inst, &settings_layers); 38745db71995Sopenharmony_ci loader_delete_layer_list_and_properties(inst, ®ular_instance_layers); 38755db71995Sopenharmony_ci 38765db71995Sopenharmony_ci loader_instance_heap_free(inst, override_paths); 38775db71995Sopenharmony_ci return res; 38785db71995Sopenharmony_ci} 38795db71995Sopenharmony_ci 38805db71995Sopenharmony_ciVkResult loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers, 38815db71995Sopenharmony_ci const struct loader_envvar_all_filters *layer_filters) { 38825db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 38835db71995Sopenharmony_ci struct loader_layer_list settings_layers = {0}; 38845db71995Sopenharmony_ci struct loader_layer_list regular_instance_layers = {0}; 38855db71995Sopenharmony_ci bool override_layer_valid = false; 38865db71995Sopenharmony_ci char *override_paths = NULL; 38875db71995Sopenharmony_ci bool implicit_metalayer_present = false; 38885db71995Sopenharmony_ci 38895db71995Sopenharmony_ci bool should_search_for_other_layers = true; 38905db71995Sopenharmony_ci res = get_settings_layers(inst, &settings_layers, &should_search_for_other_layers); 38915db71995Sopenharmony_ci if (VK_SUCCESS != res) { 38925db71995Sopenharmony_ci goto out; 38935db71995Sopenharmony_ci } 38945db71995Sopenharmony_ci 38955db71995Sopenharmony_ci // If we should not look for layers using other mechanisms, assign settings_layers to instance_layers and jump to the 38965db71995Sopenharmony_ci // output 38975db71995Sopenharmony_ci if (!should_search_for_other_layers) { 38985db71995Sopenharmony_ci *instance_layers = settings_layers; 38995db71995Sopenharmony_ci memset(&settings_layers, 0, sizeof(struct loader_layer_list)); 39005db71995Sopenharmony_ci goto out; 39015db71995Sopenharmony_ci } 39025db71995Sopenharmony_ci 39035db71995Sopenharmony_ci res = loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, ®ular_instance_layers); 39045db71995Sopenharmony_ci if (VK_SUCCESS != res) { 39055db71995Sopenharmony_ci goto out; 39065db71995Sopenharmony_ci } 39075db71995Sopenharmony_ci 39085db71995Sopenharmony_ci // Remove any extraneous override layers. 39095db71995Sopenharmony_ci remove_all_non_valid_override_layers(inst, ®ular_instance_layers); 39105db71995Sopenharmony_ci 39115db71995Sopenharmony_ci // Check to see if either the override layer is present, or another implicit meta-layer. 39125db71995Sopenharmony_ci // Each of these may require explicit layers to be enabled at this time. 39135db71995Sopenharmony_ci for (uint32_t i = 0; i < regular_instance_layers.count; i++) { 39145db71995Sopenharmony_ci struct loader_layer_properties *prop = ®ular_instance_layers.list[i]; 39155db71995Sopenharmony_ci if (prop->is_override && loader_implicit_layer_is_enabled(inst, layer_filters, prop)) { 39165db71995Sopenharmony_ci override_layer_valid = true; 39175db71995Sopenharmony_ci res = get_override_layer_override_paths(inst, prop, &override_paths); 39185db71995Sopenharmony_ci if (VK_SUCCESS != res) { 39195db71995Sopenharmony_ci goto out; 39205db71995Sopenharmony_ci } 39215db71995Sopenharmony_ci } else if (!prop->is_override && prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { 39225db71995Sopenharmony_ci implicit_metalayer_present = true; 39235db71995Sopenharmony_ci } 39245db71995Sopenharmony_ci } 39255db71995Sopenharmony_ci 39265db71995Sopenharmony_ci // If either the override layer or an implicit meta-layer are present, we need to add 39275db71995Sopenharmony_ci // explicit layer info as well. Not to worry, though, all explicit layers not included 39285db71995Sopenharmony_ci // in the override layer will be removed below in loader_remove_layers_in_blacklist(). 39295db71995Sopenharmony_ci if (override_layer_valid || implicit_metalayer_present) { 39305db71995Sopenharmony_ci res = 39315db71995Sopenharmony_ci loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER, override_paths, ®ular_instance_layers); 39325db71995Sopenharmony_ci if (VK_SUCCESS != res) { 39335db71995Sopenharmony_ci goto out; 39345db71995Sopenharmony_ci } 39355db71995Sopenharmony_ci } 39365db71995Sopenharmony_ci 39375db71995Sopenharmony_ci // Verify any meta-layers in the list are valid and all the component layers are 39385db71995Sopenharmony_ci // actually present in the available layer list 39395db71995Sopenharmony_ci res = verify_all_meta_layers(inst, layer_filters, ®ular_instance_layers, &override_layer_valid); 39405db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 39415db71995Sopenharmony_ci return res; 39425db71995Sopenharmony_ci } 39435db71995Sopenharmony_ci 39445db71995Sopenharmony_ci if (override_layer_valid || implicit_metalayer_present) { 39455db71995Sopenharmony_ci loader_remove_layers_not_in_implicit_meta_layers(inst, ®ular_instance_layers); 39465db71995Sopenharmony_ci if (override_layer_valid && inst != NULL) { 39475db71995Sopenharmony_ci inst->override_layer_present = true; 39485db71995Sopenharmony_ci } 39495db71995Sopenharmony_ci } 39505db71995Sopenharmony_ci 39515db71995Sopenharmony_ci // Remove disabled layers 39525db71995Sopenharmony_ci for (uint32_t i = 0; i < regular_instance_layers.count; ++i) { 39535db71995Sopenharmony_ci if (!loader_implicit_layer_is_enabled(inst, layer_filters, ®ular_instance_layers.list[i])) { 39545db71995Sopenharmony_ci loader_remove_layer_in_list(inst, ®ular_instance_layers, i); 39555db71995Sopenharmony_ci i--; 39565db71995Sopenharmony_ci } 39575db71995Sopenharmony_ci } 39585db71995Sopenharmony_ci 39595db71995Sopenharmony_ci res = combine_settings_layers_with_regular_layers(inst, &settings_layers, ®ular_instance_layers, instance_layers); 39605db71995Sopenharmony_ci 39615db71995Sopenharmony_ciout: 39625db71995Sopenharmony_ci loader_delete_layer_list_and_properties(inst, &settings_layers); 39635db71995Sopenharmony_ci loader_delete_layer_list_and_properties(inst, ®ular_instance_layers); 39645db71995Sopenharmony_ci 39655db71995Sopenharmony_ci loader_instance_heap_free(inst, override_paths); 39665db71995Sopenharmony_ci return res; 39675db71995Sopenharmony_ci} 39685db71995Sopenharmony_ci 39695db71995Sopenharmony_ciVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) { 39705db71995Sopenharmony_ci // inst is not wrapped 39715db71995Sopenharmony_ci if (inst == VK_NULL_HANDLE) { 39725db71995Sopenharmony_ci return NULL; 39735db71995Sopenharmony_ci } 39745db71995Sopenharmony_ci 39755db71995Sopenharmony_ci VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst; 39765db71995Sopenharmony_ci 39775db71995Sopenharmony_ci if (disp_table == NULL) return NULL; 39785db71995Sopenharmony_ci 39795db71995Sopenharmony_ci struct loader_instance *loader_inst = loader_get_instance(inst); 39805db71995Sopenharmony_ci 39815db71995Sopenharmony_ci if (loader_inst->instance_finished_creation) { 39825db71995Sopenharmony_ci disp_table = &loader_inst->terminator_dispatch; 39835db71995Sopenharmony_ci } 39845db71995Sopenharmony_ci 39855db71995Sopenharmony_ci bool found_name; 39865db71995Sopenharmony_ci void *addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name); 39875db71995Sopenharmony_ci if (found_name) { 39885db71995Sopenharmony_ci return addr; 39895db71995Sopenharmony_ci } 39905db71995Sopenharmony_ci 39915db71995Sopenharmony_ci // Check if any drivers support the function, and if so, add it to the unknown function list 39925db71995Sopenharmony_ci addr = loader_phys_dev_ext_gpa_term(loader_get_instance(inst), pName); 39935db71995Sopenharmony_ci if (NULL != addr) return addr; 39945db71995Sopenharmony_ci 39955db71995Sopenharmony_ci // Don't call down the chain, this would be an infinite loop 39965db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_DEBUG_BIT, 0, "loader_gpdpa_instance_terminator() unrecognized name %s", pName); 39975db71995Sopenharmony_ci return NULL; 39985db71995Sopenharmony_ci} 39995db71995Sopenharmony_ci 40005db71995Sopenharmony_ciVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_terminator(VkInstance inst, const char *pName) { 40015db71995Sopenharmony_ci // Global functions - Do not need a valid instance handle to query 40025db71995Sopenharmony_ci if (!strcmp(pName, "vkGetInstanceProcAddr")) { 40035db71995Sopenharmony_ci return (PFN_vkVoidFunction)loader_gpa_instance_terminator; 40045db71995Sopenharmony_ci } 40055db71995Sopenharmony_ci if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) { 40065db71995Sopenharmony_ci return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator; 40075db71995Sopenharmony_ci } 40085db71995Sopenharmony_ci if (!strcmp(pName, "vkCreateInstance")) { 40095db71995Sopenharmony_ci return (PFN_vkVoidFunction)terminator_CreateInstance; 40105db71995Sopenharmony_ci } 40115db71995Sopenharmony_ci 40125db71995Sopenharmony_ci // While the spec is very clear that querying vkCreateDevice requires a valid VkInstance, because the loader allowed querying 40135db71995Sopenharmony_ci // with a NULL VkInstance handle for a long enough time, it is impractical to fix this bug in the loader 40145db71995Sopenharmony_ci 40155db71995Sopenharmony_ci // As such, this is a bug to maintain compatibility for the RTSS layer (Riva Tuner Statistics Server) but may 40165db71995Sopenharmony_ci // be depended upon by other layers out in the wild. 40175db71995Sopenharmony_ci if (!strcmp(pName, "vkCreateDevice")) { 40185db71995Sopenharmony_ci return (PFN_vkVoidFunction)terminator_CreateDevice; 40195db71995Sopenharmony_ci } 40205db71995Sopenharmony_ci 40215db71995Sopenharmony_ci // inst is not wrapped 40225db71995Sopenharmony_ci if (inst == VK_NULL_HANDLE) { 40235db71995Sopenharmony_ci return NULL; 40245db71995Sopenharmony_ci } 40255db71995Sopenharmony_ci VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst; 40265db71995Sopenharmony_ci 40275db71995Sopenharmony_ci if (disp_table == NULL) return NULL; 40285db71995Sopenharmony_ci 40295db71995Sopenharmony_ci struct loader_instance *loader_inst = loader_get_instance(inst); 40305db71995Sopenharmony_ci 40315db71995Sopenharmony_ci // The VK_EXT_debug_utils functions need a special case here so the terminators can still be found from 40325db71995Sopenharmony_ci // vkGetInstanceProcAddr This is because VK_EXT_debug_utils is an instance level extension with device level functions, and 40335db71995Sopenharmony_ci // is 'supported' by the loader. 40345db71995Sopenharmony_ci // These functions need a terminator to handle the case of a driver not supporting VK_EXT_debug_utils when there are layers 40355db71995Sopenharmony_ci // present which not check for NULL before calling the function. 40365db71995Sopenharmony_ci if (!strcmp(pName, "vkSetDebugUtilsObjectNameEXT")) { 40375db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectNameEXT 40385db71995Sopenharmony_ci : NULL; 40395db71995Sopenharmony_ci } 40405db71995Sopenharmony_ci if (!strcmp(pName, "vkSetDebugUtilsObjectTagEXT")) { 40415db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectTagEXT 40425db71995Sopenharmony_ci : NULL; 40435db71995Sopenharmony_ci } 40445db71995Sopenharmony_ci if (!strcmp(pName, "vkQueueBeginDebugUtilsLabelEXT")) { 40455db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_QueueBeginDebugUtilsLabelEXT 40465db71995Sopenharmony_ci : NULL; 40475db71995Sopenharmony_ci } 40485db71995Sopenharmony_ci if (!strcmp(pName, "vkQueueEndDebugUtilsLabelEXT")) { 40495db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_QueueEndDebugUtilsLabelEXT 40505db71995Sopenharmony_ci : NULL; 40515db71995Sopenharmony_ci } 40525db71995Sopenharmony_ci if (!strcmp(pName, "vkQueueInsertDebugUtilsLabelEXT")) { 40535db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_QueueInsertDebugUtilsLabelEXT 40545db71995Sopenharmony_ci : NULL; 40555db71995Sopenharmony_ci } 40565db71995Sopenharmony_ci if (!strcmp(pName, "vkCmdBeginDebugUtilsLabelEXT")) { 40575db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_CmdBeginDebugUtilsLabelEXT 40585db71995Sopenharmony_ci : NULL; 40595db71995Sopenharmony_ci } 40605db71995Sopenharmony_ci if (!strcmp(pName, "vkCmdEndDebugUtilsLabelEXT")) { 40615db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_CmdEndDebugUtilsLabelEXT 40625db71995Sopenharmony_ci : NULL; 40635db71995Sopenharmony_ci } 40645db71995Sopenharmony_ci if (!strcmp(pName, "vkCmdInsertDebugUtilsLabelEXT")) { 40655db71995Sopenharmony_ci return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_CmdInsertDebugUtilsLabelEXT 40665db71995Sopenharmony_ci : NULL; 40675db71995Sopenharmony_ci } 40685db71995Sopenharmony_ci 40695db71995Sopenharmony_ci if (loader_inst->instance_finished_creation) { 40705db71995Sopenharmony_ci disp_table = &loader_inst->terminator_dispatch; 40715db71995Sopenharmony_ci } 40725db71995Sopenharmony_ci 40735db71995Sopenharmony_ci bool found_name; 40745db71995Sopenharmony_ci void *addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name); 40755db71995Sopenharmony_ci if (found_name) { 40765db71995Sopenharmony_ci return addr; 40775db71995Sopenharmony_ci } 40785db71995Sopenharmony_ci 40795db71995Sopenharmony_ci // Check if it is an unknown physical device function, to see if any drivers support it. 40805db71995Sopenharmony_ci addr = loader_phys_dev_ext_gpa_term(loader_get_instance(inst), pName); 40815db71995Sopenharmony_ci if (addr) { 40825db71995Sopenharmony_ci return addr; 40835db71995Sopenharmony_ci } 40845db71995Sopenharmony_ci 40855db71995Sopenharmony_ci // Assume it is an unknown device function, check to see if any drivers support it. 40865db71995Sopenharmony_ci addr = loader_dev_ext_gpa_term(loader_get_instance(inst), pName); 40875db71995Sopenharmony_ci if (addr) { 40885db71995Sopenharmony_ci return addr; 40895db71995Sopenharmony_ci } 40905db71995Sopenharmony_ci 40915db71995Sopenharmony_ci // Don't call down the chain, this would be an infinite loop 40925db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_DEBUG_BIT, 0, "loader_gpa_instance_terminator() unrecognized name %s", pName); 40935db71995Sopenharmony_ci return NULL; 40945db71995Sopenharmony_ci} 40955db71995Sopenharmony_ci 40965db71995Sopenharmony_ciVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_device_terminator(VkDevice device, const char *pName) { 40975db71995Sopenharmony_ci struct loader_device *dev; 40985db71995Sopenharmony_ci struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL); 40995db71995Sopenharmony_ci 41005db71995Sopenharmony_ci // Return this function if a layer above here is asking for the vkGetDeviceProcAddr. 41015db71995Sopenharmony_ci // This is so we can properly intercept any device commands needing a terminator. 41025db71995Sopenharmony_ci if (!strcmp(pName, "vkGetDeviceProcAddr")) { 41035db71995Sopenharmony_ci return (PFN_vkVoidFunction)loader_gpa_device_terminator; 41045db71995Sopenharmony_ci } 41055db71995Sopenharmony_ci 41065db71995Sopenharmony_ci // NOTE: Device Funcs needing Trampoline/Terminator. 41075db71995Sopenharmony_ci // Overrides for device functions needing a trampoline and 41085db71995Sopenharmony_ci // a terminator because certain device entry-points still need to go 41095db71995Sopenharmony_ci // through a terminator before hitting the ICD. This could be for 41105db71995Sopenharmony_ci // several reasons, but the main one is currently unwrapping an 41115db71995Sopenharmony_ci // object before passing the appropriate info along to the ICD. 41125db71995Sopenharmony_ci // This is why we also have to override the direct ICD call to 41135db71995Sopenharmony_ci // vkGetDeviceProcAddr to intercept those calls. 41145db71995Sopenharmony_ci // If the pName is for a 'known' function but isn't available, due to 41155db71995Sopenharmony_ci // the corresponding extension/feature not being enabled, we need to 41165db71995Sopenharmony_ci // return NULL and not call down to the driver's GetDeviceProcAddr. 41175db71995Sopenharmony_ci if (NULL != dev) { 41185db71995Sopenharmony_ci bool found_name = false; 41195db71995Sopenharmony_ci PFN_vkVoidFunction addr = get_extension_device_proc_terminator(dev, pName, &found_name); 41205db71995Sopenharmony_ci if (found_name) { 41215db71995Sopenharmony_ci return addr; 41225db71995Sopenharmony_ci } 41235db71995Sopenharmony_ci } 41245db71995Sopenharmony_ci 41255db71995Sopenharmony_ci if (icd_term == NULL) { 41265db71995Sopenharmony_ci return NULL; 41275db71995Sopenharmony_ci } 41285db71995Sopenharmony_ci 41295db71995Sopenharmony_ci return icd_term->dispatch.GetDeviceProcAddr(device, pName); 41305db71995Sopenharmony_ci} 41315db71995Sopenharmony_ci 41325db71995Sopenharmony_cistruct loader_instance *loader_get_instance(const VkInstance instance) { 41335db71995Sopenharmony_ci // look up the loader_instance in our list by comparing dispatch tables, as 41345db71995Sopenharmony_ci // there is no guarantee the instance is still a loader_instance* after any 41355db71995Sopenharmony_ci // layers which wrap the instance object. 41365db71995Sopenharmony_ci const VkLayerInstanceDispatchTable *disp; 41375db71995Sopenharmony_ci struct loader_instance *ptr_instance = (struct loader_instance *)instance; 41385db71995Sopenharmony_ci if (VK_NULL_HANDLE == instance || LOADER_MAGIC_NUMBER != ptr_instance->magic) { 41395db71995Sopenharmony_ci return NULL; 41405db71995Sopenharmony_ci } else { 41415db71995Sopenharmony_ci disp = loader_get_instance_layer_dispatch(instance); 41425db71995Sopenharmony_ci loader_platform_thread_lock_mutex(&loader_global_instance_list_lock); 41435db71995Sopenharmony_ci for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 41445db71995Sopenharmony_ci if (&inst->disp->layer_inst_disp == disp) { 41455db71995Sopenharmony_ci ptr_instance = inst; 41465db71995Sopenharmony_ci break; 41475db71995Sopenharmony_ci } 41485db71995Sopenharmony_ci } 41495db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock); 41505db71995Sopenharmony_ci } 41515db71995Sopenharmony_ci return ptr_instance; 41525db71995Sopenharmony_ci} 41535db71995Sopenharmony_ci 41545db71995Sopenharmony_ciloader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop) { 41555db71995Sopenharmony_ci char* libPath = prop->lib_name; 41565db71995Sopenharmony_ci#if defined(__OHOS__) 41575db71995Sopenharmony_ci char *debug_layer_name = loader_secure_getenv("debug.graphic.debug_layer", inst); 41585db71995Sopenharmony_ci char *debug_hap_name = loader_secure_getenv("debug.graphic.debug_hap", inst); 41595db71995Sopenharmony_ci bool isDebugLayer = false; 41605db71995Sopenharmony_ci char* debugLayerLibPath = NULL; 41615db71995Sopenharmony_ci if (NULL != debug_layer_name && '\0' != debug_layer_name[0] && InitBundleInfo(debug_hap_name)) { 41625db71995Sopenharmony_ci const char lib_prefix[] = "lib"; 41635db71995Sopenharmony_ci const char so_suffix[] = ".so"; 41645db71995Sopenharmony_ci size_t totalLen = strlen(debug_layer_name) + strlen(lib_prefix) + strlen(so_suffix) + 1; 41655db71995Sopenharmony_ci char* layerSoName = loader_instance_heap_calloc(inst, totalLen, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 41665db71995Sopenharmony_ci if (layerSoName == NULL) { 41675db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "malloc layerSoName fail"); 41685db71995Sopenharmony_ci goto mallocErr; 41695db71995Sopenharmony_ci } 41705db71995Sopenharmony_ci strncpy(layerSoName, lib_prefix, totalLen); 41715db71995Sopenharmony_ci strncat(layerSoName, debug_layer_name, totalLen); 41725db71995Sopenharmony_ci strncat(layerSoName, so_suffix, totalLen); 41735db71995Sopenharmony_ci if (strcmp(layerSoName, libPath) == 0) { 41745db71995Sopenharmony_ci isDebugLayer = true; 41755db71995Sopenharmony_ci debugLayerLibPath = GetDebugLayerLibPath(inst, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 41765db71995Sopenharmony_ci if(debugLayerLibPath == NULL) { 41775db71995Sopenharmony_ci loader_instance_heap_free(inst, layerSoName); 41785db71995Sopenharmony_ci isDebugLayer = false; 41795db71995Sopenharmony_ci goto mallocErr; 41805db71995Sopenharmony_ci } 41815db71995Sopenharmony_ci size_t totalLength = strlen(libPath) + strlen(debugLayerLibPath) + 1; 41825db71995Sopenharmony_ci libPath = loader_instance_heap_calloc(inst, totalLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 41835db71995Sopenharmony_ci if (libPath == NULL) { 41845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "malloc libPath fail"); 41855db71995Sopenharmony_ci loader_instance_heap_free(inst, layerSoName); 41865db71995Sopenharmony_ci loader_instance_heap_free(inst, debugLayerLibPath); 41875db71995Sopenharmony_ci libPath = prop->lib_name; 41885db71995Sopenharmony_ci isDebugLayer = false; 41895db71995Sopenharmony_ci goto mallocErr; 41905db71995Sopenharmony_ci } 41915db71995Sopenharmony_ci strncpy(libPath, debugLayerLibPath, totalLength); 41925db71995Sopenharmony_ci strncat(libPath, prop->lib_name, totalLength); 41935db71995Sopenharmony_ci } else { 41945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "layerSoName != libPath : %s != %s", 41955db71995Sopenharmony_ci layerSoName, libPath); 41965db71995Sopenharmony_ci } 41975db71995Sopenharmony_ci loader_instance_heap_free(inst, layerSoName); 41985db71995Sopenharmony_ci } 41995db71995Sopenharmony_cimallocErr: 42005db71995Sopenharmony_ci loader_free_getenv(debug_layer_name, inst); 42015db71995Sopenharmony_ci loader_free_getenv(debug_hap_name, inst); 42025db71995Sopenharmony_ci#endif 42035db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "try to open libPath: %s", libPath); 42045db71995Sopenharmony_ci if ((prop->lib_handle = loader_platform_open_library(libPath)) == NULL) { 42055db71995Sopenharmony_ci loader_handle_load_library_error(inst, prop->lib_name, &prop->lib_status); 42065db71995Sopenharmony_ci } else { 42075db71995Sopenharmony_ci prop->lib_status = LOADER_LAYER_LIB_SUCCESS_LOADED; 42085db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Loading layer library %s", prop->lib_name); 42095db71995Sopenharmony_ci } 42105db71995Sopenharmony_ci#if defined(__OHOS__) 42115db71995Sopenharmony_ci if (isDebugLayer) { 42125db71995Sopenharmony_ci loader_instance_heap_free(inst, debugLayerLibPath); 42135db71995Sopenharmony_ci loader_instance_heap_free(inst, libPath); 42145db71995Sopenharmony_ci } 42155db71995Sopenharmony_ci#endif 42165db71995Sopenharmony_ci return prop->lib_handle; 42175db71995Sopenharmony_ci} 42185db71995Sopenharmony_ci 42195db71995Sopenharmony_ci// Go through the search_list and find any layers which match type. If layer 42205db71995Sopenharmony_ci// type match is found in then add it to ext_list. 42215db71995Sopenharmony_ciVkResult loader_add_implicit_layers(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters, 42225db71995Sopenharmony_ci struct loader_pointer_layer_list *target_list, 42235db71995Sopenharmony_ci struct loader_pointer_layer_list *expanded_target_list, 42245db71995Sopenharmony_ci const struct loader_layer_list *source_list) { 42255db71995Sopenharmony_ci for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) { 42265db71995Sopenharmony_ci struct loader_layer_properties *prop = &source_list->list[src_layer]; 42275db71995Sopenharmony_ci if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) { 42285db71995Sopenharmony_ci VkResult result = loader_add_implicit_layer(inst, prop, filters, target_list, expanded_target_list, source_list); 42295db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; 42305db71995Sopenharmony_ci } 42315db71995Sopenharmony_ci } 42325db71995Sopenharmony_ci return VK_SUCCESS; 42335db71995Sopenharmony_ci} 42345db71995Sopenharmony_ci 42355db71995Sopenharmony_civoid warn_if_layers_are_older_than_application(struct loader_instance *inst) { 42365db71995Sopenharmony_ci for (uint32_t i = 0; i < inst->expanded_activated_layer_list.count; i++) { 42375db71995Sopenharmony_ci // Verify that the layer api version is at least that of the application's request, if not, throw a warning since 42385db71995Sopenharmony_ci // undefined behavior could occur. 42395db71995Sopenharmony_ci struct loader_layer_properties *prop = inst->expanded_activated_layer_list.list[i]; 42405db71995Sopenharmony_ci loader_api_version prop_spec_version = loader_make_version(prop->info.specVersion); 42415db71995Sopenharmony_ci if (!loader_check_version_meets_required(inst->app_api_version, prop_spec_version)) { 42425db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, 42435db71995Sopenharmony_ci "Layer %s uses API version %u.%u which is older than the application specified " 42445db71995Sopenharmony_ci "API version of %u.%u. May cause issues.", 42455db71995Sopenharmony_ci prop->info.layerName, prop_spec_version.major, prop_spec_version.minor, inst->app_api_version.major, 42465db71995Sopenharmony_ci inst->app_api_version.minor); 42475db71995Sopenharmony_ci } 42485db71995Sopenharmony_ci } 42495db71995Sopenharmony_ci} 42505db71995Sopenharmony_ci 42515db71995Sopenharmony_ciVkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo, 42525db71995Sopenharmony_ci const struct loader_layer_list *instance_layers, 42535db71995Sopenharmony_ci const struct loader_envvar_all_filters *layer_filters) { 42545db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 42555db71995Sopenharmony_ci 42565db71995Sopenharmony_ci assert(inst && "Cannot have null instance"); 42575db71995Sopenharmony_ci 42585db71995Sopenharmony_ci if (!loader_init_pointer_layer_list(inst, &inst->app_activated_layer_list)) { 42595db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 42605db71995Sopenharmony_ci "loader_enable_instance_layers: Failed to initialize application version of the layer list"); 42615db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 42625db71995Sopenharmony_ci goto out; 42635db71995Sopenharmony_ci } 42645db71995Sopenharmony_ci 42655db71995Sopenharmony_ci if (!loader_init_pointer_layer_list(inst, &inst->expanded_activated_layer_list)) { 42665db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 42675db71995Sopenharmony_ci "loader_enable_instance_layers: Failed to initialize expanded version of the layer list"); 42685db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 42695db71995Sopenharmony_ci goto out; 42705db71995Sopenharmony_ci } 42715db71995Sopenharmony_ci 42725db71995Sopenharmony_ci if (inst->settings.settings_active) { 42735db71995Sopenharmony_ci res = enable_correct_layers_from_settings(inst, layer_filters, pCreateInfo->enabledLayerCount, 42745db71995Sopenharmony_ci pCreateInfo->ppEnabledLayerNames, &inst->instance_layer_list, 42755db71995Sopenharmony_ci &inst->app_activated_layer_list, &inst->expanded_activated_layer_list); 42765db71995Sopenharmony_ci warn_if_layers_are_older_than_application(inst); 42775db71995Sopenharmony_ci 42785db71995Sopenharmony_ci goto out; 42795db71995Sopenharmony_ci } 42805db71995Sopenharmony_ci 42815db71995Sopenharmony_ci // Add any implicit layers first 42825db71995Sopenharmony_ci res = loader_add_implicit_layers(inst, layer_filters, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, 42835db71995Sopenharmony_ci instance_layers); 42845db71995Sopenharmony_ci if (res != VK_SUCCESS) { 42855db71995Sopenharmony_ci goto out; 42865db71995Sopenharmony_ci } 42875db71995Sopenharmony_ci 42885db71995Sopenharmony_ci // Add any layers specified via environment variable next 42895db71995Sopenharmony_ci res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, layer_filters, &inst->app_activated_layer_list, 42905db71995Sopenharmony_ci &inst->expanded_activated_layer_list, instance_layers); 42915db71995Sopenharmony_ci if (res != VK_SUCCESS) { 42925db71995Sopenharmony_ci goto out; 42935db71995Sopenharmony_ci } 42945db71995Sopenharmony_ci 42955db71995Sopenharmony_ci // Add layers specified by the application 42965db71995Sopenharmony_ci res = loader_add_layer_names_to_list(inst, layer_filters, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, 42975db71995Sopenharmony_ci pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers); 42985db71995Sopenharmony_ci 42995db71995Sopenharmony_ci warn_if_layers_are_older_than_application(inst); 43005db71995Sopenharmony_ciout: 43015db71995Sopenharmony_ci return res; 43025db71995Sopenharmony_ci} 43035db71995Sopenharmony_ci 43045db71995Sopenharmony_ci// Determine the layer interface version to use. 43055db71995Sopenharmony_cibool loader_get_layer_interface_version(PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version, 43065db71995Sopenharmony_ci VkNegotiateLayerInterface *interface_struct) { 43075db71995Sopenharmony_ci memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface)); 43085db71995Sopenharmony_ci interface_struct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT; 43095db71995Sopenharmony_ci interface_struct->loaderLayerInterfaceVersion = 1; 43105db71995Sopenharmony_ci interface_struct->pNext = NULL; 43115db71995Sopenharmony_ci 43125db71995Sopenharmony_ci if (fp_negotiate_layer_version != NULL) { 43135db71995Sopenharmony_ci // Layer supports the negotiation API, so call it with the loader's 43145db71995Sopenharmony_ci // latest version supported 43155db71995Sopenharmony_ci interface_struct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION; 43165db71995Sopenharmony_ci VkResult result = fp_negotiate_layer_version(interface_struct); 43175db71995Sopenharmony_ci 43185db71995Sopenharmony_ci if (result != VK_SUCCESS) { 43195db71995Sopenharmony_ci // Layer no longer supports the loader's latest interface version so 43205db71995Sopenharmony_ci // fail loading the Layer 43215db71995Sopenharmony_ci return false; 43225db71995Sopenharmony_ci } 43235db71995Sopenharmony_ci } 43245db71995Sopenharmony_ci 43255db71995Sopenharmony_ci if (interface_struct->loaderLayerInterfaceVersion < MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) { 43265db71995Sopenharmony_ci // Loader no longer supports the layer's latest interface version so 43275db71995Sopenharmony_ci // fail loading the layer 43285db71995Sopenharmony_ci return false; 43295db71995Sopenharmony_ci } 43305db71995Sopenharmony_ci 43315db71995Sopenharmony_ci return true; 43325db71995Sopenharmony_ci} 43335db71995Sopenharmony_ci 43345db71995Sopenharmony_ci// Every extension that has a loader-defined trampoline needs to be marked as enabled or disabled so that we know whether or 43355db71995Sopenharmony_ci// not to return that trampoline when vkGetDeviceProcAddr is called 43365db71995Sopenharmony_civoid setup_logical_device_enabled_layer_extensions(const struct loader_instance *inst, struct loader_device *dev, 43375db71995Sopenharmony_ci const struct loader_extension_list *icd_exts, 43385db71995Sopenharmony_ci const VkDeviceCreateInfo *pCreateInfo) { 43395db71995Sopenharmony_ci // Can only setup debug marker as debug utils is an instance extensions. 43405db71995Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; ++i) { 43415db71995Sopenharmony_ci if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { 43425db71995Sopenharmony_ci // Check if its supported by the driver 43435db71995Sopenharmony_ci for (uint32_t j = 0; j < icd_exts->count; ++j) { 43445db71995Sopenharmony_ci if (!strcmp(icd_exts->list[j].extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { 43455db71995Sopenharmony_ci dev->layer_extensions.ext_debug_marker_enabled = true; 43465db71995Sopenharmony_ci } 43475db71995Sopenharmony_ci } 43485db71995Sopenharmony_ci // also check if any layers support it. 43495db71995Sopenharmony_ci for (uint32_t j = 0; j < inst->app_activated_layer_list.count; j++) { 43505db71995Sopenharmony_ci struct loader_layer_properties *layer = inst->app_activated_layer_list.list[j]; 43515db71995Sopenharmony_ci for (uint32_t k = 0; k < layer->device_extension_list.count; k++) { 43525db71995Sopenharmony_ci if (!strcmp(layer->device_extension_list.list[k].props.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { 43535db71995Sopenharmony_ci dev->layer_extensions.ext_debug_marker_enabled = true; 43545db71995Sopenharmony_ci } 43555db71995Sopenharmony_ci } 43565db71995Sopenharmony_ci } 43575db71995Sopenharmony_ci } 43585db71995Sopenharmony_ci } 43595db71995Sopenharmony_ci} 43605db71995Sopenharmony_ci 43615db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL loader_layer_create_device(VkInstance instance, VkPhysicalDevice physicalDevice, 43625db71995Sopenharmony_ci const VkDeviceCreateInfo *pCreateInfo, 43635db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, 43645db71995Sopenharmony_ci PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA) { 43655db71995Sopenharmony_ci VkResult res; 43665db71995Sopenharmony_ci VkPhysicalDevice internal_device = VK_NULL_HANDLE; 43675db71995Sopenharmony_ci struct loader_device *dev = NULL; 43685db71995Sopenharmony_ci struct loader_instance *inst = NULL; 43695db71995Sopenharmony_ci 43705db71995Sopenharmony_ci if (instance != VK_NULL_HANDLE) { 43715db71995Sopenharmony_ci inst = loader_get_instance(instance); 43725db71995Sopenharmony_ci internal_device = physicalDevice; 43735db71995Sopenharmony_ci } else { 43745db71995Sopenharmony_ci struct loader_physical_device_tramp *phys_dev = (struct loader_physical_device_tramp *)physicalDevice; 43755db71995Sopenharmony_ci internal_device = phys_dev->phys_dev; 43765db71995Sopenharmony_ci inst = (struct loader_instance *)phys_dev->this_instance; 43775db71995Sopenharmony_ci } 43785db71995Sopenharmony_ci 43795db71995Sopenharmony_ci // Get the physical device (ICD) extensions 43805db71995Sopenharmony_ci struct loader_extension_list icd_exts = {0}; 43815db71995Sopenharmony_ci icd_exts.list = NULL; 43825db71995Sopenharmony_ci res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties)); 43835db71995Sopenharmony_ci if (VK_SUCCESS != res) { 43845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to create ICD extension list"); 43855db71995Sopenharmony_ci goto out; 43865db71995Sopenharmony_ci } 43875db71995Sopenharmony_ci 43885db71995Sopenharmony_ci PFN_vkEnumerateDeviceExtensionProperties enumDeviceExtensionProperties = NULL; 43895db71995Sopenharmony_ci if (layerGIPA != NULL) { 43905db71995Sopenharmony_ci enumDeviceExtensionProperties = 43915db71995Sopenharmony_ci (PFN_vkEnumerateDeviceExtensionProperties)layerGIPA(instance, "vkEnumerateDeviceExtensionProperties"); 43925db71995Sopenharmony_ci } else { 43935db71995Sopenharmony_ci enumDeviceExtensionProperties = inst->disp->layer_inst_disp.EnumerateDeviceExtensionProperties; 43945db71995Sopenharmony_ci } 43955db71995Sopenharmony_ci res = loader_add_device_extensions(inst, enumDeviceExtensionProperties, internal_device, "Unknown", &icd_exts); 43965db71995Sopenharmony_ci if (res != VK_SUCCESS) { 43975db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to add extensions to list"); 43985db71995Sopenharmony_ci goto out; 43995db71995Sopenharmony_ci } 44005db71995Sopenharmony_ci 44015db71995Sopenharmony_ci // Make sure requested extensions to be enabled are supported 44025db71995Sopenharmony_ci res = loader_validate_device_extensions(inst, &inst->expanded_activated_layer_list, &icd_exts, pCreateInfo); 44035db71995Sopenharmony_ci if (res != VK_SUCCESS) { 44045db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to validate extensions in list"); 44055db71995Sopenharmony_ci goto out; 44065db71995Sopenharmony_ci } 44075db71995Sopenharmony_ci 44085db71995Sopenharmony_ci dev = loader_create_logical_device(inst, pAllocator); 44095db71995Sopenharmony_ci if (dev == NULL) { 44105db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 44115db71995Sopenharmony_ci goto out; 44125db71995Sopenharmony_ci } 44135db71995Sopenharmony_ci 44145db71995Sopenharmony_ci setup_logical_device_enabled_layer_extensions(inst, dev, &icd_exts, pCreateInfo); 44155db71995Sopenharmony_ci 44165db71995Sopenharmony_ci res = loader_create_device_chain(internal_device, pCreateInfo, pAllocator, inst, dev, layerGIPA, nextGDPA); 44175db71995Sopenharmony_ci if (res != VK_SUCCESS) { 44185db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to create device chain."); 44195db71995Sopenharmony_ci goto out; 44205db71995Sopenharmony_ci } 44215db71995Sopenharmony_ci 44225db71995Sopenharmony_ci *pDevice = dev->chain_device; 44235db71995Sopenharmony_ci 44245db71995Sopenharmony_ci // Initialize any device extension dispatch entry's from the instance list 44255db71995Sopenharmony_ci loader_init_dispatch_dev_ext(inst, dev); 44265db71995Sopenharmony_ci 44275db71995Sopenharmony_ci // Initialize WSI device extensions as part of core dispatch since loader 44285db71995Sopenharmony_ci // has dedicated trampoline code for these 44295db71995Sopenharmony_ci loader_init_device_extension_dispatch_table(&dev->loader_dispatch, inst->disp->layer_inst_disp.GetInstanceProcAddr, 44305db71995Sopenharmony_ci dev->loader_dispatch.core_dispatch.GetDeviceProcAddr, inst->instance, *pDevice); 44315db71995Sopenharmony_ci 44325db71995Sopenharmony_ciout: 44335db71995Sopenharmony_ci 44345db71995Sopenharmony_ci // Failure cleanup 44355db71995Sopenharmony_ci if (VK_SUCCESS != res) { 44365db71995Sopenharmony_ci if (NULL != dev) { 44375db71995Sopenharmony_ci // Find the icd_term this device belongs to then remove it from that icd_term. 44385db71995Sopenharmony_ci // Need to iterate the linked lists and remove the device from it. Don't delete 44395db71995Sopenharmony_ci // the device here since it may not have been added to the icd_term and there 44405db71995Sopenharmony_ci // are other allocations attached to it. 44415db71995Sopenharmony_ci struct loader_icd_term *icd_term = inst->icd_terms; 44425db71995Sopenharmony_ci bool found = false; 44435db71995Sopenharmony_ci while (!found && NULL != icd_term) { 44445db71995Sopenharmony_ci struct loader_device *cur_dev = icd_term->logical_device_list; 44455db71995Sopenharmony_ci struct loader_device *prev_dev = NULL; 44465db71995Sopenharmony_ci while (NULL != cur_dev) { 44475db71995Sopenharmony_ci if (cur_dev == dev) { 44485db71995Sopenharmony_ci if (cur_dev == icd_term->logical_device_list) { 44495db71995Sopenharmony_ci icd_term->logical_device_list = cur_dev->next; 44505db71995Sopenharmony_ci } else if (prev_dev) { 44515db71995Sopenharmony_ci prev_dev->next = cur_dev->next; 44525db71995Sopenharmony_ci } 44535db71995Sopenharmony_ci 44545db71995Sopenharmony_ci found = true; 44555db71995Sopenharmony_ci break; 44565db71995Sopenharmony_ci } 44575db71995Sopenharmony_ci prev_dev = cur_dev; 44585db71995Sopenharmony_ci cur_dev = cur_dev->next; 44595db71995Sopenharmony_ci } 44605db71995Sopenharmony_ci icd_term = icd_term->next; 44615db71995Sopenharmony_ci } 44625db71995Sopenharmony_ci // Now destroy the device and the allocations associated with it. 44635db71995Sopenharmony_ci loader_destroy_logical_device(dev, pAllocator); 44645db71995Sopenharmony_ci } 44655db71995Sopenharmony_ci } 44665db71995Sopenharmony_ci 44675db71995Sopenharmony_ci if (NULL != icd_exts.list) { 44685db71995Sopenharmony_ci loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts); 44695db71995Sopenharmony_ci } 44705db71995Sopenharmony_ci return res; 44715db71995Sopenharmony_ci} 44725db71995Sopenharmony_ci 44735db71995Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL loader_layer_destroy_device(VkDevice device, const VkAllocationCallbacks *pAllocator, 44745db71995Sopenharmony_ci PFN_vkDestroyDevice destroyFunction) { 44755db71995Sopenharmony_ci struct loader_device *dev; 44765db71995Sopenharmony_ci 44775db71995Sopenharmony_ci if (device == VK_NULL_HANDLE) { 44785db71995Sopenharmony_ci return; 44795db71995Sopenharmony_ci } 44805db71995Sopenharmony_ci 44815db71995Sopenharmony_ci struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL); 44825db71995Sopenharmony_ci 44835db71995Sopenharmony_ci destroyFunction(device, pAllocator); 44845db71995Sopenharmony_ci if (NULL != dev) { 44855db71995Sopenharmony_ci dev->chain_device = NULL; 44865db71995Sopenharmony_ci dev->icd_device = NULL; 44875db71995Sopenharmony_ci loader_remove_logical_device(icd_term, dev, pAllocator); 44885db71995Sopenharmony_ci } 44895db71995Sopenharmony_ci} 44905db71995Sopenharmony_ci 44915db71995Sopenharmony_ci// Given the list of layers to activate in the loader_instance 44925db71995Sopenharmony_ci// structure. This function will add a VkLayerInstanceCreateInfo 44935db71995Sopenharmony_ci// structure to the VkInstanceCreateInfo.pNext pointer. 44945db71995Sopenharmony_ci// Each activated layer will have it's own VkLayerInstanceLink 44955db71995Sopenharmony_ci// structure that tells the layer what Get*ProcAddr to call to 44965db71995Sopenharmony_ci// get function pointers to the next layer down. 44975db71995Sopenharmony_ci// Once the chain info has been created this function will 44985db71995Sopenharmony_ci// execute the CreateInstance call chain. Each layer will 44995db71995Sopenharmony_ci// then have an opportunity in it's CreateInstance function 45005db71995Sopenharmony_ci// to setup it's dispatch table when the lower layer returns 45015db71995Sopenharmony_ci// successfully. 45025db71995Sopenharmony_ci// Each layer can wrap or not-wrap the returned VkInstance object 45035db71995Sopenharmony_ci// as it sees fit. 45045db71995Sopenharmony_ci// The instance chain is terminated by a loader function 45055db71995Sopenharmony_ci// that will call CreateInstance on all available ICD's and 45065db71995Sopenharmony_ci// cache those VkInstance objects for future use. 45075db71995Sopenharmony_ciVkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, 45085db71995Sopenharmony_ci struct loader_instance *inst, VkInstance *created_instance) { 45095db71995Sopenharmony_ci uint32_t num_activated_layers = 0; 45105db71995Sopenharmony_ci struct activated_layer_info *activated_layers = NULL; 45115db71995Sopenharmony_ci VkLayerInstanceCreateInfo chain_info; 45125db71995Sopenharmony_ci VkLayerInstanceLink *layer_instance_link_info = NULL; 45135db71995Sopenharmony_ci VkInstanceCreateInfo loader_create_info; 45145db71995Sopenharmony_ci VkResult res; 45155db71995Sopenharmony_ci 45165db71995Sopenharmony_ci PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_terminator; 45175db71995Sopenharmony_ci PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_terminator; 45185db71995Sopenharmony_ci PFN_vkGetDeviceProcAddr cur_gdpa = loader_gpa_device_terminator; 45195db71995Sopenharmony_ci PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_terminator; 45205db71995Sopenharmony_ci PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_terminator; 45215db71995Sopenharmony_ci 45225db71995Sopenharmony_ci memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo)); 45235db71995Sopenharmony_ci 45245db71995Sopenharmony_ci if (inst->expanded_activated_layer_list.count > 0) { 45255db71995Sopenharmony_ci chain_info.u.pLayerInfo = NULL; 45265db71995Sopenharmony_ci chain_info.pNext = pCreateInfo->pNext; 45275db71995Sopenharmony_ci chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; 45285db71995Sopenharmony_ci chain_info.function = VK_LAYER_LINK_INFO; 45295db71995Sopenharmony_ci loader_create_info.pNext = &chain_info; 45305db71995Sopenharmony_ci 45315db71995Sopenharmony_ci layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count); 45325db71995Sopenharmony_ci if (!layer_instance_link_info) { 45335db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 45345db71995Sopenharmony_ci "loader_create_instance_chain: Failed to alloc Instance objects for layer"); 45355db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 45365db71995Sopenharmony_ci } 45375db71995Sopenharmony_ci 45385db71995Sopenharmony_ci activated_layers = loader_stack_alloc(sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count); 45395db71995Sopenharmony_ci if (!activated_layers) { 45405db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 45415db71995Sopenharmony_ci "loader_create_instance_chain: Failed to alloc activated layer storage array"); 45425db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 45435db71995Sopenharmony_ci } 45445db71995Sopenharmony_ci 45455db71995Sopenharmony_ci // Create instance chain of enabled layers 45465db71995Sopenharmony_ci for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) { 45475db71995Sopenharmony_ci struct loader_layer_properties *layer_prop = inst->expanded_activated_layer_list.list[i]; 45485db71995Sopenharmony_ci loader_platform_dl_handle lib_handle; 45495db71995Sopenharmony_ci 45505db71995Sopenharmony_ci // Skip it if a Layer with the same name has been already successfully activated 45515db71995Sopenharmony_ci if (loader_names_array_has_layer_property(&layer_prop->info, num_activated_layers, activated_layers)) { 45525db71995Sopenharmony_ci continue; 45535db71995Sopenharmony_ci } 45545db71995Sopenharmony_ci 45555db71995Sopenharmony_ci lib_handle = loader_open_layer_file(inst, layer_prop); 45565db71995Sopenharmony_ci if (layer_prop->lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) { 45575db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 45585db71995Sopenharmony_ci } 45595db71995Sopenharmony_ci if (!lib_handle) { 45605db71995Sopenharmony_ci continue; 45615db71995Sopenharmony_ci } 45625db71995Sopenharmony_ci 45635db71995Sopenharmony_ci if (NULL == layer_prop->functions.negotiate_layer_interface) { 45645db71995Sopenharmony_ci PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL; 45655db71995Sopenharmony_ci bool functions_in_interface = false; 45665db71995Sopenharmony_ci if (!layer_prop->functions.str_negotiate_interface || strlen(layer_prop->functions.str_negotiate_interface) == 0) { 45675db71995Sopenharmony_ci negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address( 45685db71995Sopenharmony_ci lib_handle, "vkNegotiateLoaderLayerInterfaceVersion"); 45695db71995Sopenharmony_ci } else { 45705db71995Sopenharmony_ci negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address( 45715db71995Sopenharmony_ci lib_handle, layer_prop->functions.str_negotiate_interface); 45725db71995Sopenharmony_ci } 45735db71995Sopenharmony_ci 45745db71995Sopenharmony_ci // If we can negotiate an interface version, then we can also 45755db71995Sopenharmony_ci // get everything we need from the one function call, so try 45765db71995Sopenharmony_ci // that first, and see if we can get all the function pointers 45775db71995Sopenharmony_ci // necessary from that one call. 45785db71995Sopenharmony_ci if (NULL != negotiate_interface) { 45795db71995Sopenharmony_ci layer_prop->functions.negotiate_layer_interface = negotiate_interface; 45805db71995Sopenharmony_ci 45815db71995Sopenharmony_ci VkNegotiateLayerInterface interface_struct; 45825db71995Sopenharmony_ci 45835db71995Sopenharmony_ci if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) { 45845db71995Sopenharmony_ci // Go ahead and set the properties version to the 45855db71995Sopenharmony_ci // correct value. 45865db71995Sopenharmony_ci layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion; 45875db71995Sopenharmony_ci 45885db71995Sopenharmony_ci // If the interface is 2 or newer, we have access to the 45895db71995Sopenharmony_ci // new GetPhysicalDeviceProcAddr function, so grab it, 45905db71995Sopenharmony_ci // and the other necessary functions, from the 45915db71995Sopenharmony_ci // structure. 45925db71995Sopenharmony_ci if (interface_struct.loaderLayerInterfaceVersion > 1) { 45935db71995Sopenharmony_ci cur_gipa = interface_struct.pfnGetInstanceProcAddr; 45945db71995Sopenharmony_ci cur_gdpa = interface_struct.pfnGetDeviceProcAddr; 45955db71995Sopenharmony_ci cur_gpdpa = interface_struct.pfnGetPhysicalDeviceProcAddr; 45965db71995Sopenharmony_ci if (cur_gipa != NULL) { 45975db71995Sopenharmony_ci // We've set the functions, so make sure we 45985db71995Sopenharmony_ci // don't do the unnecessary calls later. 45995db71995Sopenharmony_ci functions_in_interface = true; 46005db71995Sopenharmony_ci } 46015db71995Sopenharmony_ci } 46025db71995Sopenharmony_ci } 46035db71995Sopenharmony_ci } 46045db71995Sopenharmony_ci 46055db71995Sopenharmony_ci if (!functions_in_interface) { 46065db71995Sopenharmony_ci if ((cur_gipa = layer_prop->functions.get_instance_proc_addr) == NULL) { 46075db71995Sopenharmony_ci if (layer_prop->functions.str_gipa == NULL || strlen(layer_prop->functions.str_gipa) == 0) { 46085db71995Sopenharmony_ci cur_gipa = 46095db71995Sopenharmony_ci (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr"); 46105db71995Sopenharmony_ci layer_prop->functions.get_instance_proc_addr = cur_gipa; 46115db71995Sopenharmony_ci 46125db71995Sopenharmony_ci if (NULL == cur_gipa) { 46135db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, 46145db71995Sopenharmony_ci "loader_create_instance_chain: Failed to find \'vkGetInstanceProcAddr\' in layer \"%s\"", 46155db71995Sopenharmony_ci layer_prop->lib_name); 46165db71995Sopenharmony_ci continue; 46175db71995Sopenharmony_ci } 46185db71995Sopenharmony_ci } else { 46195db71995Sopenharmony_ci cur_gipa = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, 46205db71995Sopenharmony_ci layer_prop->functions.str_gipa); 46215db71995Sopenharmony_ci 46225db71995Sopenharmony_ci if (NULL == cur_gipa) { 46235db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, 46245db71995Sopenharmony_ci "loader_create_instance_chain: Failed to find \'%s\' in layer \"%s\"", 46255db71995Sopenharmony_ci layer_prop->functions.str_gipa, layer_prop->lib_name); 46265db71995Sopenharmony_ci continue; 46275db71995Sopenharmony_ci } 46285db71995Sopenharmony_ci } 46295db71995Sopenharmony_ci } 46305db71995Sopenharmony_ci } 46315db71995Sopenharmony_ci } 46325db71995Sopenharmony_ci 46335db71995Sopenharmony_ci layer_instance_link_info[num_activated_layers].pNext = chain_info.u.pLayerInfo; 46345db71995Sopenharmony_ci layer_instance_link_info[num_activated_layers].pfnNextGetInstanceProcAddr = next_gipa; 46355db71995Sopenharmony_ci layer_instance_link_info[num_activated_layers].pfnNextGetPhysicalDeviceProcAddr = next_gpdpa; 46365db71995Sopenharmony_ci next_gipa = cur_gipa; 46375db71995Sopenharmony_ci if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) { 46385db71995Sopenharmony_ci layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa; 46395db71995Sopenharmony_ci next_gpdpa = cur_gpdpa; 46405db71995Sopenharmony_ci } 46415db71995Sopenharmony_ci if (layer_prop->interface_version > 1 && cur_gipa != NULL) { 46425db71995Sopenharmony_ci layer_prop->functions.get_instance_proc_addr = cur_gipa; 46435db71995Sopenharmony_ci } 46445db71995Sopenharmony_ci if (layer_prop->interface_version > 1 && cur_gdpa != NULL) { 46455db71995Sopenharmony_ci layer_prop->functions.get_device_proc_addr = cur_gdpa; 46465db71995Sopenharmony_ci } 46475db71995Sopenharmony_ci 46485db71995Sopenharmony_ci chain_info.u.pLayerInfo = &layer_instance_link_info[num_activated_layers]; 46495db71995Sopenharmony_ci 46505db71995Sopenharmony_ci activated_layers[num_activated_layers].name = layer_prop->info.layerName; 46515db71995Sopenharmony_ci activated_layers[num_activated_layers].manifest = layer_prop->manifest_file_name; 46525db71995Sopenharmony_ci activated_layers[num_activated_layers].library = layer_prop->lib_name; 46535db71995Sopenharmony_ci activated_layers[num_activated_layers].is_implicit = !(layer_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER); 46545db71995Sopenharmony_ci if (activated_layers[num_activated_layers].is_implicit) { 46555db71995Sopenharmony_ci activated_layers[num_activated_layers].disable_env = layer_prop->disable_env_var.name; 46565db71995Sopenharmony_ci } 46575db71995Sopenharmony_ci 46585db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Insert instance layer \"%s\" (%s)", 46595db71995Sopenharmony_ci layer_prop->info.layerName, layer_prop->lib_name); 46605db71995Sopenharmony_ci 46615db71995Sopenharmony_ci num_activated_layers++; 46625db71995Sopenharmony_ci } 46635db71995Sopenharmony_ci } 46645db71995Sopenharmony_ci 46655db71995Sopenharmony_ci // Make sure each layer requested by the application was actually loaded 46665db71995Sopenharmony_ci for (uint32_t exp = 0; exp < inst->expanded_activated_layer_list.count; ++exp) { 46675db71995Sopenharmony_ci struct loader_layer_properties *exp_layer_prop = inst->expanded_activated_layer_list.list[exp]; 46685db71995Sopenharmony_ci bool found = false; 46695db71995Sopenharmony_ci for (uint32_t act = 0; act < num_activated_layers; ++act) { 46705db71995Sopenharmony_ci if (!strcmp(activated_layers[act].name, exp_layer_prop->info.layerName)) { 46715db71995Sopenharmony_ci found = true; 46725db71995Sopenharmony_ci break; 46735db71995Sopenharmony_ci } 46745db71995Sopenharmony_ci } 46755db71995Sopenharmony_ci // If it wasn't found, we want to at least log an error. However, if it was enabled by the application directly, 46765db71995Sopenharmony_ci // we want to return a bad layer error. 46775db71995Sopenharmony_ci if (!found) { 46785db71995Sopenharmony_ci bool app_requested = false; 46795db71995Sopenharmony_ci for (uint32_t act = 0; act < pCreateInfo->enabledLayerCount; ++act) { 46805db71995Sopenharmony_ci if (!strcmp(pCreateInfo->ppEnabledLayerNames[act], exp_layer_prop->info.layerName)) { 46815db71995Sopenharmony_ci app_requested = true; 46825db71995Sopenharmony_ci break; 46835db71995Sopenharmony_ci } 46845db71995Sopenharmony_ci } 46855db71995Sopenharmony_ci VkFlags log_flag = VULKAN_LOADER_LAYER_BIT; 46865db71995Sopenharmony_ci char ending = '.'; 46875db71995Sopenharmony_ci if (app_requested) { 46885db71995Sopenharmony_ci log_flag |= VULKAN_LOADER_ERROR_BIT; 46895db71995Sopenharmony_ci ending = '!'; 46905db71995Sopenharmony_ci } else { 46915db71995Sopenharmony_ci log_flag |= VULKAN_LOADER_INFO_BIT; 46925db71995Sopenharmony_ci } 46935db71995Sopenharmony_ci switch (exp_layer_prop->lib_status) { 46945db71995Sopenharmony_ci case LOADER_LAYER_LIB_NOT_LOADED: 46955db71995Sopenharmony_ci loader_log(inst, log_flag, 0, "Requested layer \"%s\" was not loaded%c", exp_layer_prop->info.layerName, 46965db71995Sopenharmony_ci ending); 46975db71995Sopenharmony_ci break; 46985db71995Sopenharmony_ci case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: { 46995db71995Sopenharmony_ci loader_log(inst, log_flag, 0, "Requested layer \"%s\" was wrong bit-type%c", exp_layer_prop->info.layerName, 47005db71995Sopenharmony_ci ending); 47015db71995Sopenharmony_ci break; 47025db71995Sopenharmony_ci } 47035db71995Sopenharmony_ci case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD: 47045db71995Sopenharmony_ci loader_log(inst, log_flag, 0, "Requested layer \"%s\" failed to load%c", exp_layer_prop->info.layerName, 47055db71995Sopenharmony_ci ending); 47065db71995Sopenharmony_ci break; 47075db71995Sopenharmony_ci case LOADER_LAYER_LIB_SUCCESS_LOADED: 47085db71995Sopenharmony_ci case LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY: 47095db71995Sopenharmony_ci // Shouldn't be able to reach this but if it is, best to report a debug 47105db71995Sopenharmony_ci loader_log(inst, log_flag, 0, 47115db71995Sopenharmony_ci "Shouldn't reach this. A valid version of requested layer %s was loaded but was not found in the " 47125db71995Sopenharmony_ci "list of activated layers%c", 47135db71995Sopenharmony_ci exp_layer_prop->info.layerName, ending); 47145db71995Sopenharmony_ci break; 47155db71995Sopenharmony_ci } 47165db71995Sopenharmony_ci if (app_requested) { 47175db71995Sopenharmony_ci return VK_ERROR_LAYER_NOT_PRESENT; 47185db71995Sopenharmony_ci } 47195db71995Sopenharmony_ci } 47205db71995Sopenharmony_ci } 47215db71995Sopenharmony_ci 47225db71995Sopenharmony_ci VkLoaderFeatureFlags feature_flags = 0; 47235db71995Sopenharmony_ci#if defined(_WIN32) 47245db71995Sopenharmony_ci feature_flags = windows_initialize_dxgi(); 47255db71995Sopenharmony_ci#endif 47265db71995Sopenharmony_ci 47275db71995Sopenharmony_ci PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance"); 47285db71995Sopenharmony_ci if (fpCreateInstance) { 47295db71995Sopenharmony_ci VkLayerInstanceCreateInfo instance_dispatch; 47305db71995Sopenharmony_ci instance_dispatch.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; 47315db71995Sopenharmony_ci instance_dispatch.pNext = loader_create_info.pNext; 47325db71995Sopenharmony_ci instance_dispatch.function = VK_LOADER_DATA_CALLBACK; 47335db71995Sopenharmony_ci instance_dispatch.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch; 47345db71995Sopenharmony_ci 47355db71995Sopenharmony_ci VkLayerInstanceCreateInfo device_callback; 47365db71995Sopenharmony_ci device_callback.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; 47375db71995Sopenharmony_ci device_callback.pNext = &instance_dispatch; 47385db71995Sopenharmony_ci device_callback.function = VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK; 47395db71995Sopenharmony_ci device_callback.u.layerDevice.pfnLayerCreateDevice = loader_layer_create_device; 47405db71995Sopenharmony_ci device_callback.u.layerDevice.pfnLayerDestroyDevice = loader_layer_destroy_device; 47415db71995Sopenharmony_ci 47425db71995Sopenharmony_ci VkLayerInstanceCreateInfo loader_features; 47435db71995Sopenharmony_ci loader_features.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO; 47445db71995Sopenharmony_ci loader_features.pNext = &device_callback; 47455db71995Sopenharmony_ci loader_features.function = VK_LOADER_FEATURES; 47465db71995Sopenharmony_ci loader_features.u.loaderFeatures = feature_flags; 47475db71995Sopenharmony_ci 47485db71995Sopenharmony_ci loader_create_info.pNext = &loader_features; 47495db71995Sopenharmony_ci 47505db71995Sopenharmony_ci // If layer debugging is enabled, let's print out the full callstack with layers in their 47515db71995Sopenharmony_ci // defined order. 47525db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "vkCreateInstance layer callstack setup to:"); 47535db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " <Application>"); 47545db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " ||"); 47555db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " <Loader>"); 47565db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " ||"); 47575db71995Sopenharmony_ci for (uint32_t cur_layer = 0; cur_layer < num_activated_layers; ++cur_layer) { 47585db71995Sopenharmony_ci uint32_t index = num_activated_layers - cur_layer - 1; 47595db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " %s", activated_layers[index].name); 47605db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Type: %s", 47615db71995Sopenharmony_ci activated_layers[index].is_implicit ? "Implicit" : "Explicit"); 47625db71995Sopenharmony_ci if (activated_layers[index].is_implicit) { 47635db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Disable Env Var: %s", 47645db71995Sopenharmony_ci activated_layers[index].disable_env); 47655db71995Sopenharmony_ci } 47665db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Manifest: %s", activated_layers[index].manifest); 47675db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Library: %s", activated_layers[index].library); 47685db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " ||"); 47695db71995Sopenharmony_ci } 47705db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " <Drivers>"); 47715db71995Sopenharmony_ci 47725db71995Sopenharmony_ci res = fpCreateInstance(&loader_create_info, pAllocator, created_instance); 47735db71995Sopenharmony_ci } else { 47745db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_instance_chain: Failed to find \'vkCreateInstance\'"); 47755db71995Sopenharmony_ci // Couldn't find CreateInstance function! 47765db71995Sopenharmony_ci res = VK_ERROR_INITIALIZATION_FAILED; 47775db71995Sopenharmony_ci } 47785db71995Sopenharmony_ci 47795db71995Sopenharmony_ci if (res == VK_SUCCESS) { 47805db71995Sopenharmony_ci // Copy the current disp table into the terminator_dispatch table so we can use it in loader_gpa_instance_terminator() 47815db71995Sopenharmony_ci memcpy(&inst->terminator_dispatch, &inst->disp->layer_inst_disp, sizeof(VkLayerInstanceDispatchTable)); 47825db71995Sopenharmony_ci 47835db71995Sopenharmony_ci loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance); 47845db71995Sopenharmony_ci inst->instance = *created_instance; 47855db71995Sopenharmony_ci 47865db71995Sopenharmony_ci if (pCreateInfo->enabledLayerCount > 0 && pCreateInfo->ppEnabledLayerNames != NULL) { 47875db71995Sopenharmony_ci res = create_string_list(inst, pCreateInfo->enabledLayerCount, &inst->enabled_layer_names); 47885db71995Sopenharmony_ci if (res != VK_SUCCESS) { 47895db71995Sopenharmony_ci return res; 47905db71995Sopenharmony_ci } 47915db71995Sopenharmony_ci 47925db71995Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->enabledLayerCount; ++i) { 47935db71995Sopenharmony_ci res = copy_str_to_string_list(inst, &inst->enabled_layer_names, pCreateInfo->ppEnabledLayerNames[i], 47945db71995Sopenharmony_ci strlen(pCreateInfo->ppEnabledLayerNames[i])); 47955db71995Sopenharmony_ci if (res != VK_SUCCESS) return res; 47965db71995Sopenharmony_ci } 47975db71995Sopenharmony_ci } 47985db71995Sopenharmony_ci } 47995db71995Sopenharmony_ci 48005db71995Sopenharmony_ci return res; 48015db71995Sopenharmony_ci} 48025db71995Sopenharmony_ci 48035db71995Sopenharmony_civoid loader_activate_instance_layer_extensions(struct loader_instance *inst, VkInstance created_inst) { 48045db71995Sopenharmony_ci loader_init_instance_extension_dispatch_table(&inst->disp->layer_inst_disp, inst->disp->layer_inst_disp.GetInstanceProcAddr, 48055db71995Sopenharmony_ci created_inst); 48065db71995Sopenharmony_ci} 48075db71995Sopenharmony_ci 48085db71995Sopenharmony_ci#if defined(__APPLE__) 48095db71995Sopenharmony_ciVkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCreateInfo *pCreateInfo, 48105db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst, 48115db71995Sopenharmony_ci struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer, 48125db71995Sopenharmony_ci PFN_vkGetDeviceProcAddr *layerNextGDPA) __attribute__((optnone)) { 48135db71995Sopenharmony_ci#else 48145db71995Sopenharmony_ciVkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCreateInfo *pCreateInfo, 48155db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst, 48165db71995Sopenharmony_ci struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer, 48175db71995Sopenharmony_ci PFN_vkGetDeviceProcAddr *layerNextGDPA) { 48185db71995Sopenharmony_ci#endif 48195db71995Sopenharmony_ci uint32_t num_activated_layers = 0; 48205db71995Sopenharmony_ci struct activated_layer_info *activated_layers = NULL; 48215db71995Sopenharmony_ci VkLayerDeviceLink *layer_device_link_info; 48225db71995Sopenharmony_ci VkLayerDeviceCreateInfo chain_info; 48235db71995Sopenharmony_ci VkDeviceCreateInfo loader_create_info; 48245db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *original_device_group_create_info_struct = NULL; 48255db71995Sopenharmony_ci VkResult res; 48265db71995Sopenharmony_ci 48275db71995Sopenharmony_ci PFN_vkGetDeviceProcAddr fpGDPA = NULL, nextGDPA = loader_gpa_device_terminator; 48285db71995Sopenharmony_ci PFN_vkGetInstanceProcAddr fpGIPA = NULL, nextGIPA = loader_gpa_instance_terminator; 48295db71995Sopenharmony_ci 48305db71995Sopenharmony_ci memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo)); 48315db71995Sopenharmony_ci 48325db71995Sopenharmony_ci if (loader_create_info.enabledLayerCount > 0 && loader_create_info.ppEnabledLayerNames != NULL) { 48335db71995Sopenharmony_ci bool invalid_device_layer_usage = false; 48345db71995Sopenharmony_ci 48355db71995Sopenharmony_ci if (loader_create_info.enabledLayerCount != inst->enabled_layer_names.count && loader_create_info.enabledLayerCount > 0) { 48365db71995Sopenharmony_ci invalid_device_layer_usage = true; 48375db71995Sopenharmony_ci } else if (loader_create_info.enabledLayerCount > 0 && loader_create_info.ppEnabledLayerNames == NULL) { 48385db71995Sopenharmony_ci invalid_device_layer_usage = true; 48395db71995Sopenharmony_ci } else if (loader_create_info.enabledLayerCount == 0 && loader_create_info.ppEnabledLayerNames != NULL) { 48405db71995Sopenharmony_ci invalid_device_layer_usage = true; 48415db71995Sopenharmony_ci } else if (inst->enabled_layer_names.list != NULL) { 48425db71995Sopenharmony_ci for (uint32_t i = 0; i < loader_create_info.enabledLayerCount; i++) { 48435db71995Sopenharmony_ci const char *device_layer_names = loader_create_info.ppEnabledLayerNames[i]; 48445db71995Sopenharmony_ci 48455db71995Sopenharmony_ci if (strcmp(device_layer_names, inst->enabled_layer_names.list[i]) != 0) { 48465db71995Sopenharmony_ci invalid_device_layer_usage = true; 48475db71995Sopenharmony_ci break; 48485db71995Sopenharmony_ci } 48495db71995Sopenharmony_ci } 48505db71995Sopenharmony_ci } 48515db71995Sopenharmony_ci 48525db71995Sopenharmony_ci if (invalid_device_layer_usage) { 48535db71995Sopenharmony_ci loader_log( 48545db71995Sopenharmony_ci inst, VULKAN_LOADER_WARN_BIT, 0, 48555db71995Sopenharmony_ci "loader_create_device_chain: Using deprecated and ignored 'ppEnabledLayerNames' member of 'VkDeviceCreateInfo' " 48565db71995Sopenharmony_ci "when creating a Vulkan device."); 48575db71995Sopenharmony_ci } 48585db71995Sopenharmony_ci } 48595db71995Sopenharmony_ci 48605db71995Sopenharmony_ci // Before we continue, we need to find out if the KHR_device_group extension is in the enabled list. If it is, we then 48615db71995Sopenharmony_ci // need to look for the corresponding VkDeviceGroupDeviceCreateInfo struct in the device list. This is because we 48625db71995Sopenharmony_ci // need to replace all the incoming physical device values (which are really loader trampoline physical device values) 48635db71995Sopenharmony_ci // with the layer/ICD version. 48645db71995Sopenharmony_ci { 48655db71995Sopenharmony_ci VkBaseOutStructure *pNext = (VkBaseOutStructure *)loader_create_info.pNext; 48665db71995Sopenharmony_ci VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&loader_create_info; 48675db71995Sopenharmony_ci while (NULL != pNext) { 48685db71995Sopenharmony_ci if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) { 48695db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext; 48705db71995Sopenharmony_ci if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) { 48715db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo)); 48725db71995Sopenharmony_ci VkPhysicalDevice *phys_dev_array = NULL; 48735db71995Sopenharmony_ci if (NULL == temp_struct) { 48745db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 48755db71995Sopenharmony_ci } 48765db71995Sopenharmony_ci memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo)); 48775db71995Sopenharmony_ci phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount); 48785db71995Sopenharmony_ci if (NULL == phys_dev_array) { 48795db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 48805db71995Sopenharmony_ci } 48815db71995Sopenharmony_ci 48825db71995Sopenharmony_ci // Before calling down, replace the incoming physical device values (which are really loader trampoline 48835db71995Sopenharmony_ci // physical devices) with the next layer (or possibly even the terminator) physical device values. 48845db71995Sopenharmony_ci struct loader_physical_device_tramp *cur_tramp; 48855db71995Sopenharmony_ci for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) { 48865db71995Sopenharmony_ci cur_tramp = (struct loader_physical_device_tramp *)cur_struct->pPhysicalDevices[phys_dev]; 48875db71995Sopenharmony_ci phys_dev_array[phys_dev] = cur_tramp->phys_dev; 48885db71995Sopenharmony_ci } 48895db71995Sopenharmony_ci temp_struct->pPhysicalDevices = phys_dev_array; 48905db71995Sopenharmony_ci 48915db71995Sopenharmony_ci original_device_group_create_info_struct = (VkDeviceGroupDeviceCreateInfo *)pPrev->pNext; 48925db71995Sopenharmony_ci 48935db71995Sopenharmony_ci // Replace the old struct in the pNext chain with this one. 48945db71995Sopenharmony_ci pPrev->pNext = (VkBaseOutStructure *)temp_struct; 48955db71995Sopenharmony_ci } 48965db71995Sopenharmony_ci break; 48975db71995Sopenharmony_ci } 48985db71995Sopenharmony_ci 48995db71995Sopenharmony_ci pPrev = pNext; 49005db71995Sopenharmony_ci pNext = pNext->pNext; 49015db71995Sopenharmony_ci } 49025db71995Sopenharmony_ci } 49035db71995Sopenharmony_ci if (inst->expanded_activated_layer_list.count > 0) { 49045db71995Sopenharmony_ci layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * inst->expanded_activated_layer_list.count); 49055db71995Sopenharmony_ci if (!layer_device_link_info) { 49065db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 49075db71995Sopenharmony_ci "loader_create_device_chain: Failed to alloc Device objects for layer. Skipping Layer."); 49085db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 49095db71995Sopenharmony_ci } 49105db71995Sopenharmony_ci 49115db71995Sopenharmony_ci activated_layers = loader_stack_alloc(sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count); 49125db71995Sopenharmony_ci if (!activated_layers) { 49135db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 49145db71995Sopenharmony_ci "loader_create_device_chain: Failed to alloc activated layer storage array"); 49155db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 49165db71995Sopenharmony_ci } 49175db71995Sopenharmony_ci 49185db71995Sopenharmony_ci chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; 49195db71995Sopenharmony_ci chain_info.function = VK_LAYER_LINK_INFO; 49205db71995Sopenharmony_ci chain_info.u.pLayerInfo = NULL; 49215db71995Sopenharmony_ci chain_info.pNext = loader_create_info.pNext; 49225db71995Sopenharmony_ci loader_create_info.pNext = &chain_info; 49235db71995Sopenharmony_ci 49245db71995Sopenharmony_ci // Create instance chain of enabled layers 49255db71995Sopenharmony_ci for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) { 49265db71995Sopenharmony_ci struct loader_layer_properties *layer_prop = inst->expanded_activated_layer_list.list[i]; 49275db71995Sopenharmony_ci loader_platform_dl_handle lib_handle = layer_prop->lib_handle; 49285db71995Sopenharmony_ci 49295db71995Sopenharmony_ci // Skip it if a Layer with the same name has been already successfully activated 49305db71995Sopenharmony_ci if (loader_names_array_has_layer_property(&layer_prop->info, num_activated_layers, activated_layers)) { 49315db71995Sopenharmony_ci continue; 49325db71995Sopenharmony_ci } 49335db71995Sopenharmony_ci 49345db71995Sopenharmony_ci // Skip the layer if the handle is NULL - this is likely because the library failed to load but wasn't removed from 49355db71995Sopenharmony_ci // the list. 49365db71995Sopenharmony_ci if (!lib_handle) { 49375db71995Sopenharmony_ci continue; 49385db71995Sopenharmony_ci } 49395db71995Sopenharmony_ci 49405db71995Sopenharmony_ci // The Get*ProcAddr pointers will already be filled in if they were received from either the json file or the 49415db71995Sopenharmony_ci // version negotiation 49425db71995Sopenharmony_ci if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) == NULL) { 49435db71995Sopenharmony_ci if (layer_prop->functions.str_gipa == NULL || strlen(layer_prop->functions.str_gipa) == 0) { 49445db71995Sopenharmony_ci fpGIPA = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr"); 49455db71995Sopenharmony_ci layer_prop->functions.get_instance_proc_addr = fpGIPA; 49465db71995Sopenharmony_ci } else 49475db71995Sopenharmony_ci fpGIPA = 49485db71995Sopenharmony_ci (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa); 49495db71995Sopenharmony_ci if (!fpGIPA) { 49505db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, 49515db71995Sopenharmony_ci "loader_create_device_chain: Failed to find \'vkGetInstanceProcAddr\' in layer \"%s\". " 49525db71995Sopenharmony_ci "Skipping layer.", 49535db71995Sopenharmony_ci layer_prop->lib_name); 49545db71995Sopenharmony_ci continue; 49555db71995Sopenharmony_ci } 49565db71995Sopenharmony_ci } 49575db71995Sopenharmony_ci 49585db71995Sopenharmony_ci if (fpGIPA == callingLayer) { 49595db71995Sopenharmony_ci if (layerNextGDPA != NULL) { 49605db71995Sopenharmony_ci *layerNextGDPA = nextGDPA; 49615db71995Sopenharmony_ci } 49625db71995Sopenharmony_ci // Break here because if fpGIPA is the same as callingLayer, that means a layer is trying to create a device, 49635db71995Sopenharmony_ci // and once we don't want to continue any further as the next layer will be the calling layer 49645db71995Sopenharmony_ci break; 49655db71995Sopenharmony_ci } 49665db71995Sopenharmony_ci 49675db71995Sopenharmony_ci if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) { 49685db71995Sopenharmony_ci if (layer_prop->functions.str_gdpa == NULL || strlen(layer_prop->functions.str_gdpa) == 0) { 49695db71995Sopenharmony_ci fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr"); 49705db71995Sopenharmony_ci layer_prop->functions.get_device_proc_addr = fpGDPA; 49715db71995Sopenharmony_ci } else 49725db71995Sopenharmony_ci fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa); 49735db71995Sopenharmony_ci if (!fpGDPA) { 49745db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, 49755db71995Sopenharmony_ci "Failed to find vkGetDeviceProcAddr in layer \"%s\"", layer_prop->lib_name); 49765db71995Sopenharmony_ci continue; 49775db71995Sopenharmony_ci } 49785db71995Sopenharmony_ci } 49795db71995Sopenharmony_ci 49805db71995Sopenharmony_ci layer_device_link_info[num_activated_layers].pNext = chain_info.u.pLayerInfo; 49815db71995Sopenharmony_ci layer_device_link_info[num_activated_layers].pfnNextGetInstanceProcAddr = nextGIPA; 49825db71995Sopenharmony_ci layer_device_link_info[num_activated_layers].pfnNextGetDeviceProcAddr = nextGDPA; 49835db71995Sopenharmony_ci chain_info.u.pLayerInfo = &layer_device_link_info[num_activated_layers]; 49845db71995Sopenharmony_ci nextGIPA = fpGIPA; 49855db71995Sopenharmony_ci nextGDPA = fpGDPA; 49865db71995Sopenharmony_ci 49875db71995Sopenharmony_ci activated_layers[num_activated_layers].name = layer_prop->info.layerName; 49885db71995Sopenharmony_ci activated_layers[num_activated_layers].manifest = layer_prop->manifest_file_name; 49895db71995Sopenharmony_ci activated_layers[num_activated_layers].library = layer_prop->lib_name; 49905db71995Sopenharmony_ci activated_layers[num_activated_layers].is_implicit = !(layer_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER); 49915db71995Sopenharmony_ci if (activated_layers[num_activated_layers].is_implicit) { 49925db71995Sopenharmony_ci activated_layers[num_activated_layers].disable_env = layer_prop->disable_env_var.name; 49935db71995Sopenharmony_ci } 49945db71995Sopenharmony_ci 49955db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Inserted device layer \"%s\" (%s)", 49965db71995Sopenharmony_ci layer_prop->info.layerName, layer_prop->lib_name); 49975db71995Sopenharmony_ci 49985db71995Sopenharmony_ci num_activated_layers++; 49995db71995Sopenharmony_ci } 50005db71995Sopenharmony_ci } 50015db71995Sopenharmony_ci 50025db71995Sopenharmony_ci VkDevice created_device = (VkDevice)dev; 50035db71995Sopenharmony_ci PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice"); 50045db71995Sopenharmony_ci if (fpCreateDevice) { 50055db71995Sopenharmony_ci VkLayerDeviceCreateInfo create_info_disp; 50065db71995Sopenharmony_ci 50075db71995Sopenharmony_ci create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; 50085db71995Sopenharmony_ci create_info_disp.function = VK_LOADER_DATA_CALLBACK; 50095db71995Sopenharmony_ci 50105db71995Sopenharmony_ci create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch; 50115db71995Sopenharmony_ci 50125db71995Sopenharmony_ci // If layer debugging is enabled, let's print out the full callstack with layers in their 50135db71995Sopenharmony_ci // defined order. 50145db71995Sopenharmony_ci uint32_t layer_driver_bits = VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT; 50155db71995Sopenharmony_ci loader_log(inst, layer_driver_bits, 0, "vkCreateDevice layer callstack setup to:"); 50165db71995Sopenharmony_ci loader_log(inst, layer_driver_bits, 0, " <Application>"); 50175db71995Sopenharmony_ci loader_log(inst, layer_driver_bits, 0, " ||"); 50185db71995Sopenharmony_ci loader_log(inst, layer_driver_bits, 0, " <Loader>"); 50195db71995Sopenharmony_ci loader_log(inst, layer_driver_bits, 0, " ||"); 50205db71995Sopenharmony_ci for (uint32_t cur_layer = 0; cur_layer < num_activated_layers; ++cur_layer) { 50215db71995Sopenharmony_ci uint32_t index = num_activated_layers - cur_layer - 1; 50225db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " %s", activated_layers[index].name); 50235db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Type: %s", 50245db71995Sopenharmony_ci activated_layers[index].is_implicit ? "Implicit" : "Explicit"); 50255db71995Sopenharmony_ci if (activated_layers[index].is_implicit) { 50265db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Disable Env Var: %s", 50275db71995Sopenharmony_ci activated_layers[index].disable_env); 50285db71995Sopenharmony_ci } 50295db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Manifest: %s", activated_layers[index].manifest); 50305db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " Library: %s", activated_layers[index].library); 50315db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, " ||"); 50325db71995Sopenharmony_ci } 50335db71995Sopenharmony_ci loader_log(inst, layer_driver_bits, 0, " <Device>"); 50345db71995Sopenharmony_ci create_info_disp.pNext = loader_create_info.pNext; 50355db71995Sopenharmony_ci loader_create_info.pNext = &create_info_disp; 50365db71995Sopenharmony_ci res = fpCreateDevice(pd, &loader_create_info, pAllocator, &created_device); 50375db71995Sopenharmony_ci if (res != VK_SUCCESS) { 50385db71995Sopenharmony_ci return res; 50395db71995Sopenharmony_ci } 50405db71995Sopenharmony_ci dev->chain_device = created_device; 50415db71995Sopenharmony_ci 50425db71995Sopenharmony_ci // Because we changed the pNext chain to use our own VkDeviceGroupDeviceCreateInfo, we need to fixup the chain to 50435db71995Sopenharmony_ci // point back at the original VkDeviceGroupDeviceCreateInfo. 50445db71995Sopenharmony_ci VkBaseOutStructure *pNext = (VkBaseOutStructure *)loader_create_info.pNext; 50455db71995Sopenharmony_ci VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&loader_create_info; 50465db71995Sopenharmony_ci while (NULL != pNext) { 50475db71995Sopenharmony_ci if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) { 50485db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext; 50495db71995Sopenharmony_ci if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) { 50505db71995Sopenharmony_ci pPrev->pNext = (VkBaseOutStructure *)original_device_group_create_info_struct; 50515db71995Sopenharmony_ci } 50525db71995Sopenharmony_ci break; 50535db71995Sopenharmony_ci } 50545db71995Sopenharmony_ci 50555db71995Sopenharmony_ci pPrev = pNext; 50565db71995Sopenharmony_ci pNext = pNext->pNext; 50575db71995Sopenharmony_ci } 50585db71995Sopenharmony_ci 50595db71995Sopenharmony_ci } else { 50605db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 50615db71995Sopenharmony_ci "loader_create_device_chain: Failed to find \'vkCreateDevice\' in layers or ICD"); 50625db71995Sopenharmony_ci // Couldn't find CreateDevice function! 50635db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 50645db71995Sopenharmony_ci } 50655db71995Sopenharmony_ci 50665db71995Sopenharmony_ci // Initialize device dispatch table 50675db71995Sopenharmony_ci loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device); 50685db71995Sopenharmony_ci // Initialize the dispatch table to functions which need terminators 50695db71995Sopenharmony_ci // These functions point directly to the driver, not the terminator functions 50705db71995Sopenharmony_ci init_extension_device_proc_terminator_dispatch(dev); 50715db71995Sopenharmony_ci 50725db71995Sopenharmony_ci return res; 50735db71995Sopenharmony_ci} 50745db71995Sopenharmony_ci 50755db71995Sopenharmony_ciVkResult loader_validate_layers(const struct loader_instance *inst, const uint32_t layer_count, 50765db71995Sopenharmony_ci const char *const *ppEnabledLayerNames, const struct loader_layer_list *list) { 50775db71995Sopenharmony_ci struct loader_layer_properties *prop; 50785db71995Sopenharmony_ci 50795db71995Sopenharmony_ci if (layer_count > 0 && ppEnabledLayerNames == NULL) { 50805db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 50815db71995Sopenharmony_ci "loader_validate_layers: ppEnabledLayerNames is NULL but enabledLayerCount is greater than zero"); 50825db71995Sopenharmony_ci return VK_ERROR_LAYER_NOT_PRESENT; 50835db71995Sopenharmony_ci } 50845db71995Sopenharmony_ci 50855db71995Sopenharmony_ci for (uint32_t i = 0; i < layer_count; i++) { 50865db71995Sopenharmony_ci VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]); 50875db71995Sopenharmony_ci if (result != VK_STRING_ERROR_NONE) { 50885db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 50895db71995Sopenharmony_ci "loader_validate_layers: ppEnabledLayerNames contains string that is too long or is badly formed"); 50905db71995Sopenharmony_ci return VK_ERROR_LAYER_NOT_PRESENT; 50915db71995Sopenharmony_ci } 50925db71995Sopenharmony_ci 50935db71995Sopenharmony_ci prop = loader_find_layer_property(ppEnabledLayerNames[i], list); 50945db71995Sopenharmony_ci if (NULL == prop) { 50955db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 50965db71995Sopenharmony_ci "loader_validate_layers: Layer %d does not exist in the list of available layers", i); 50975db71995Sopenharmony_ci return VK_ERROR_LAYER_NOT_PRESENT; 50985db71995Sopenharmony_ci } 50995db71995Sopenharmony_ci if (inst->settings.settings_active && prop->settings_control_value != LOADER_SETTINGS_LAYER_CONTROL_ON && 51005db71995Sopenharmony_ci prop->settings_control_value != LOADER_SETTINGS_LAYER_CONTROL_DEFAULT) { 51015db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 51025db71995Sopenharmony_ci "loader_validate_layers: Layer %d was explicitly prevented from being enabled by the loader settings file", 51035db71995Sopenharmony_ci i); 51045db71995Sopenharmony_ci return VK_ERROR_LAYER_NOT_PRESENT; 51055db71995Sopenharmony_ci } 51065db71995Sopenharmony_ci } 51075db71995Sopenharmony_ci return VK_SUCCESS; 51085db71995Sopenharmony_ci} 51095db71995Sopenharmony_ci 51105db71995Sopenharmony_ciVkResult loader_validate_instance_extensions(struct loader_instance *inst, const struct loader_extension_list *icd_exts, 51115db71995Sopenharmony_ci const struct loader_layer_list *instance_layers, 51125db71995Sopenharmony_ci const struct loader_envvar_all_filters *layer_filters, 51135db71995Sopenharmony_ci const VkInstanceCreateInfo *pCreateInfo) { 51145db71995Sopenharmony_ci VkExtensionProperties *extension_prop; 51155db71995Sopenharmony_ci char *env_value; 51165db71995Sopenharmony_ci bool check_if_known = true; 51175db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 51185db71995Sopenharmony_ci 51195db71995Sopenharmony_ci struct loader_pointer_layer_list active_layers = {0}; 51205db71995Sopenharmony_ci struct loader_pointer_layer_list expanded_layers = {0}; 51215db71995Sopenharmony_ci 51225db71995Sopenharmony_ci if (pCreateInfo->enabledExtensionCount > 0 && pCreateInfo->ppEnabledExtensionNames == NULL) { 51235db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 51245db71995Sopenharmony_ci "loader_validate_instance_extensions: Instance ppEnabledExtensionNames is NULL but enabledExtensionCount is " 51255db71995Sopenharmony_ci "greater than zero"); 51265db71995Sopenharmony_ci return VK_ERROR_EXTENSION_NOT_PRESENT; 51275db71995Sopenharmony_ci } 51285db71995Sopenharmony_ci if (!loader_init_pointer_layer_list(inst, &active_layers)) { 51295db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 51305db71995Sopenharmony_ci goto out; 51315db71995Sopenharmony_ci } 51325db71995Sopenharmony_ci if (!loader_init_pointer_layer_list(inst, &expanded_layers)) { 51335db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 51345db71995Sopenharmony_ci goto out; 51355db71995Sopenharmony_ci } 51365db71995Sopenharmony_ci 51375db71995Sopenharmony_ci if (inst->settings.settings_active) { 51385db71995Sopenharmony_ci res = enable_correct_layers_from_settings(inst, layer_filters, pCreateInfo->enabledLayerCount, 51395db71995Sopenharmony_ci pCreateInfo->ppEnabledLayerNames, instance_layers, &active_layers, 51405db71995Sopenharmony_ci &expanded_layers); 51415db71995Sopenharmony_ci if (res != VK_SUCCESS) { 51425db71995Sopenharmony_ci goto out; 51435db71995Sopenharmony_ci } 51445db71995Sopenharmony_ci } else { 51455db71995Sopenharmony_ci // Build the lists of active layers (including meta layers) and expanded layers (with meta layers resolved to their 51465db71995Sopenharmony_ci // components) 51475db71995Sopenharmony_ci res = loader_add_implicit_layers(inst, layer_filters, &active_layers, &expanded_layers, instance_layers); 51485db71995Sopenharmony_ci if (res != VK_SUCCESS) { 51495db71995Sopenharmony_ci goto out; 51505db71995Sopenharmony_ci } 51515db71995Sopenharmony_ci res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, layer_filters, &active_layers, 51525db71995Sopenharmony_ci &expanded_layers, instance_layers); 51535db71995Sopenharmony_ci if (res != VK_SUCCESS) { 51545db71995Sopenharmony_ci goto out; 51555db71995Sopenharmony_ci } 51565db71995Sopenharmony_ci res = loader_add_layer_names_to_list(inst, layer_filters, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount, 51575db71995Sopenharmony_ci pCreateInfo->ppEnabledLayerNames, instance_layers); 51585db71995Sopenharmony_ci if (VK_SUCCESS != res) { 51595db71995Sopenharmony_ci goto out; 51605db71995Sopenharmony_ci } 51615db71995Sopenharmony_ci } 51625db71995Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 51635db71995Sopenharmony_ci VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]); 51645db71995Sopenharmony_ci if (result != VK_STRING_ERROR_NONE) { 51655db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 51665db71995Sopenharmony_ci "loader_validate_instance_extensions: Instance ppEnabledExtensionNames contains " 51675db71995Sopenharmony_ci "string that is too long or is badly formed"); 51685db71995Sopenharmony_ci res = VK_ERROR_EXTENSION_NOT_PRESENT; 51695db71995Sopenharmony_ci goto out; 51705db71995Sopenharmony_ci } 51715db71995Sopenharmony_ci 51725db71995Sopenharmony_ci // Check if a user wants to disable the instance extension filtering behavior 51735db71995Sopenharmony_ci env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst); 51745db71995Sopenharmony_ci if (NULL != env_value && atoi(env_value) != 0) { 51755db71995Sopenharmony_ci check_if_known = false; 51765db71995Sopenharmony_ci } 51775db71995Sopenharmony_ci loader_free_getenv(env_value, inst); 51785db71995Sopenharmony_ci 51795db71995Sopenharmony_ci if (check_if_known) { 51805db71995Sopenharmony_ci // See if the extension is in the list of supported extensions 51815db71995Sopenharmony_ci bool found = false; 51825db71995Sopenharmony_ci for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) { 51835db71995Sopenharmony_ci if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], LOADER_INSTANCE_EXTENSIONS[j]) == 0) { 51845db71995Sopenharmony_ci found = true; 51855db71995Sopenharmony_ci break; 51865db71995Sopenharmony_ci } 51875db71995Sopenharmony_ci } 51885db71995Sopenharmony_ci 51895db71995Sopenharmony_ci // If it isn't in the list, return an error 51905db71995Sopenharmony_ci if (!found) { 51915db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 51925db71995Sopenharmony_ci "loader_validate_instance_extensions: Extension %s not found in list of known instance extensions.", 51935db71995Sopenharmony_ci pCreateInfo->ppEnabledExtensionNames[i]); 51945db71995Sopenharmony_ci res = VK_ERROR_EXTENSION_NOT_PRESENT; 51955db71995Sopenharmony_ci goto out; 51965db71995Sopenharmony_ci } 51975db71995Sopenharmony_ci } 51985db71995Sopenharmony_ci 51995db71995Sopenharmony_ci extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], icd_exts); 52005db71995Sopenharmony_ci 52015db71995Sopenharmony_ci if (extension_prop) { 52025db71995Sopenharmony_ci continue; 52035db71995Sopenharmony_ci } 52045db71995Sopenharmony_ci 52055db71995Sopenharmony_ci extension_prop = NULL; 52065db71995Sopenharmony_ci 52075db71995Sopenharmony_ci // Not in global list, search layer extension lists 52085db71995Sopenharmony_ci for (uint32_t j = 0; NULL == extension_prop && j < expanded_layers.count; ++j) { 52095db71995Sopenharmony_ci extension_prop = 52105db71995Sopenharmony_ci get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], &expanded_layers.list[j]->instance_extension_list); 52115db71995Sopenharmony_ci if (extension_prop) { 52125db71995Sopenharmony_ci // Found the extension in one of the layers enabled by the app. 52135db71995Sopenharmony_ci break; 52145db71995Sopenharmony_ci } 52155db71995Sopenharmony_ci 52165db71995Sopenharmony_ci struct loader_layer_properties *layer_prop = 52175db71995Sopenharmony_ci loader_find_layer_property(expanded_layers.list[j]->info.layerName, instance_layers); 52185db71995Sopenharmony_ci if (NULL == layer_prop) { 52195db71995Sopenharmony_ci // Should NOT get here, loader_validate_layers should have already filtered this case out. 52205db71995Sopenharmony_ci continue; 52215db71995Sopenharmony_ci } 52225db71995Sopenharmony_ci } 52235db71995Sopenharmony_ci 52245db71995Sopenharmony_ci if (!extension_prop) { 52255db71995Sopenharmony_ci // Didn't find extension name in any of the global layers, error out 52265db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 52275db71995Sopenharmony_ci "loader_validate_instance_extensions: Instance extension %s not supported by available ICDs or enabled " 52285db71995Sopenharmony_ci "layers.", 52295db71995Sopenharmony_ci pCreateInfo->ppEnabledExtensionNames[i]); 52305db71995Sopenharmony_ci res = VK_ERROR_EXTENSION_NOT_PRESENT; 52315db71995Sopenharmony_ci goto out; 52325db71995Sopenharmony_ci } 52335db71995Sopenharmony_ci } 52345db71995Sopenharmony_ci 52355db71995Sopenharmony_ciout: 52365db71995Sopenharmony_ci loader_destroy_pointer_layer_list(inst, &active_layers); 52375db71995Sopenharmony_ci loader_destroy_pointer_layer_list(inst, &expanded_layers); 52385db71995Sopenharmony_ci return res; 52395db71995Sopenharmony_ci} 52405db71995Sopenharmony_ci 52415db71995Sopenharmony_ciVkResult loader_validate_device_extensions(struct loader_instance *this_instance, 52425db71995Sopenharmony_ci const struct loader_pointer_layer_list *activated_device_layers, 52435db71995Sopenharmony_ci const struct loader_extension_list *icd_exts, const VkDeviceCreateInfo *pCreateInfo) { 52445db71995Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 52455db71995Sopenharmony_ci VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]); 52465db71995Sopenharmony_ci if (result != VK_STRING_ERROR_NONE) { 52475db71995Sopenharmony_ci loader_log(this_instance, VULKAN_LOADER_ERROR_BIT, 0, 52485db71995Sopenharmony_ci "loader_validate_device_extensions: Device ppEnabledExtensionNames contains " 52495db71995Sopenharmony_ci "string that is too long or is badly formed"); 52505db71995Sopenharmony_ci return VK_ERROR_EXTENSION_NOT_PRESENT; 52515db71995Sopenharmony_ci } 52525db71995Sopenharmony_ci 52535db71995Sopenharmony_ci const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i]; 52545db71995Sopenharmony_ci VkExtensionProperties *extension_prop = get_extension_property(extension_name, icd_exts); 52555db71995Sopenharmony_ci 52565db71995Sopenharmony_ci if (extension_prop) { 52575db71995Sopenharmony_ci continue; 52585db71995Sopenharmony_ci } 52595db71995Sopenharmony_ci 52605db71995Sopenharmony_ci // Not in global list, search activated layer extension lists 52615db71995Sopenharmony_ci for (uint32_t j = 0; j < activated_device_layers->count; j++) { 52625db71995Sopenharmony_ci struct loader_layer_properties *layer_prop = activated_device_layers->list[j]; 52635db71995Sopenharmony_ci 52645db71995Sopenharmony_ci extension_prop = get_dev_extension_property(extension_name, &layer_prop->device_extension_list); 52655db71995Sopenharmony_ci if (extension_prop) { 52665db71995Sopenharmony_ci // Found the extension in one of the layers enabled by the app. 52675db71995Sopenharmony_ci break; 52685db71995Sopenharmony_ci } 52695db71995Sopenharmony_ci } 52705db71995Sopenharmony_ci 52715db71995Sopenharmony_ci if (!extension_prop) { 52725db71995Sopenharmony_ci // Didn't find extension name in any of the device layers, error out 52735db71995Sopenharmony_ci loader_log(this_instance, VULKAN_LOADER_ERROR_BIT, 0, 52745db71995Sopenharmony_ci "loader_validate_device_extensions: Device extension %s not supported by selected physical device " 52755db71995Sopenharmony_ci "or enabled layers.", 52765db71995Sopenharmony_ci pCreateInfo->ppEnabledExtensionNames[i]); 52775db71995Sopenharmony_ci return VK_ERROR_EXTENSION_NOT_PRESENT; 52785db71995Sopenharmony_ci } 52795db71995Sopenharmony_ci } 52805db71995Sopenharmony_ci return VK_SUCCESS; 52815db71995Sopenharmony_ci} 52825db71995Sopenharmony_ci 52835db71995Sopenharmony_ci// Terminator functions for the Instance chain 52845db71995Sopenharmony_ci// All named terminator_<Vulkan API name> 52855db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, 52865db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { 52875db71995Sopenharmony_ci struct loader_icd_term *icd_term; 52885db71995Sopenharmony_ci VkExtensionProperties *prop; 52895db71995Sopenharmony_ci char **filtered_extension_names = NULL; 52905db71995Sopenharmony_ci VkInstanceCreateInfo icd_create_info; 52915db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 52925db71995Sopenharmony_ci bool one_icd_successful = false; 52935db71995Sopenharmony_ci 52945db71995Sopenharmony_ci struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance; 52955db71995Sopenharmony_ci if (NULL == ptr_instance) { 52965db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0, 52975db71995Sopenharmony_ci "terminator_CreateInstance: Loader instance pointer null encountered. Possibly set by active layer. (Policy " 52985db71995Sopenharmony_ci "#LLP_LAYER_21)"); 52995db71995Sopenharmony_ci } else if (LOADER_MAGIC_NUMBER != ptr_instance->magic) { 53005db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0, 53015db71995Sopenharmony_ci "terminator_CreateInstance: Instance pointer (%p) has invalid MAGIC value 0x%08lx. Instance value possibly " 53025db71995Sopenharmony_ci "corrupted by active layer (Policy #LLP_LAYER_21). ", 53035db71995Sopenharmony_ci ptr_instance, ptr_instance->magic); 53045db71995Sopenharmony_ci } 53055db71995Sopenharmony_ci 53065db71995Sopenharmony_ci // Save the application version if it has been modified - layers sometimes needs features in newer API versions than 53075db71995Sopenharmony_ci // what the application requested, and thus will increase the instance version to a level that suites their needs. 53085db71995Sopenharmony_ci if (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion) { 53095db71995Sopenharmony_ci loader_api_version altered_version = loader_make_version(pCreateInfo->pApplicationInfo->apiVersion); 53105db71995Sopenharmony_ci if (altered_version.major != ptr_instance->app_api_version.major || 53115db71995Sopenharmony_ci altered_version.minor != ptr_instance->app_api_version.minor) { 53125db71995Sopenharmony_ci ptr_instance->app_api_version = altered_version; 53135db71995Sopenharmony_ci } 53145db71995Sopenharmony_ci } 53155db71995Sopenharmony_ci 53165db71995Sopenharmony_ci memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info)); 53175db71995Sopenharmony_ci 53185db71995Sopenharmony_ci icd_create_info.enabledLayerCount = 0; 53195db71995Sopenharmony_ci icd_create_info.ppEnabledLayerNames = NULL; 53205db71995Sopenharmony_ci 53215db71995Sopenharmony_ci // NOTE: Need to filter the extensions to only those supported by the ICD. 53225db71995Sopenharmony_ci // No ICD will advertise support for layers. An ICD library could 53235db71995Sopenharmony_ci // support a layer, but it would be independent of the actual ICD, 53245db71995Sopenharmony_ci // just in the same library. 53255db71995Sopenharmony_ci uint32_t extension_count = pCreateInfo->enabledExtensionCount; 53265db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 53275db71995Sopenharmony_ci extension_count += 1; 53285db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 53295db71995Sopenharmony_ci filtered_extension_names = loader_stack_alloc(extension_count * sizeof(char *)); 53305db71995Sopenharmony_ci if (!filtered_extension_names) { 53315db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT, 0, 53325db71995Sopenharmony_ci "terminator_CreateInstance: Failed create extension name array for %d extensions", extension_count); 53335db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 53345db71995Sopenharmony_ci goto out; 53355db71995Sopenharmony_ci } 53365db71995Sopenharmony_ci icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names; 53375db71995Sopenharmony_ci 53385db71995Sopenharmony_ci // Determine if Get Physical Device Properties 2 is available to this Instance 53395db71995Sopenharmony_ci if (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion >= VK_API_VERSION_1_1) { 53405db71995Sopenharmony_ci ptr_instance->supports_get_dev_prop_2 = true; 53415db71995Sopenharmony_ci } else { 53425db71995Sopenharmony_ci for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) { 53435db71995Sopenharmony_ci if (!strcmp(pCreateInfo->ppEnabledExtensionNames[j], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { 53445db71995Sopenharmony_ci ptr_instance->supports_get_dev_prop_2 = true; 53455db71995Sopenharmony_ci break; 53465db71995Sopenharmony_ci } 53475db71995Sopenharmony_ci } 53485db71995Sopenharmony_ci } 53495db71995Sopenharmony_ci 53505db71995Sopenharmony_ci for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) { 53515db71995Sopenharmony_ci icd_term = loader_icd_add(ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]); 53525db71995Sopenharmony_ci if (NULL == icd_term) { 53535db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT, 0, 53545db71995Sopenharmony_ci "terminator_CreateInstance: Failed to add ICD %d to ICD trampoline list.", i); 53555db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 53565db71995Sopenharmony_ci goto out; 53575db71995Sopenharmony_ci } 53585db71995Sopenharmony_ci 53595db71995Sopenharmony_ci // If any error happens after here, we need to remove the ICD from the list, 53605db71995Sopenharmony_ci // because we've already added it, but haven't validated it 53615db71995Sopenharmony_ci 53625db71995Sopenharmony_ci // Make sure that we reset the pApplicationInfo so we don't get an old pointer 53635db71995Sopenharmony_ci icd_create_info.pApplicationInfo = pCreateInfo->pApplicationInfo; 53645db71995Sopenharmony_ci icd_create_info.enabledExtensionCount = 0; 53655db71995Sopenharmony_ci struct loader_extension_list icd_exts = {0}; 53665db71995Sopenharmony_ci 53675db71995Sopenharmony_ci // traverse scanned icd list adding non-duplicate extensions to the list 53685db71995Sopenharmony_ci res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties)); 53695db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 53705db71995Sopenharmony_ci // If out of memory, bail immediately. 53715db71995Sopenharmony_ci goto out; 53725db71995Sopenharmony_ci } else if (VK_SUCCESS != res) { 53735db71995Sopenharmony_ci // Something bad happened with this ICD, so free it and try the 53745db71995Sopenharmony_ci // next. 53755db71995Sopenharmony_ci ptr_instance->icd_terms = icd_term->next; 53765db71995Sopenharmony_ci icd_term->next = NULL; 53775db71995Sopenharmony_ci loader_icd_destroy(ptr_instance, icd_term, pAllocator); 53785db71995Sopenharmony_ci continue; 53795db71995Sopenharmony_ci } 53805db71995Sopenharmony_ci 53815db71995Sopenharmony_ci res = loader_add_instance_extensions(ptr_instance, icd_term->scanned_icd->EnumerateInstanceExtensionProperties, 53825db71995Sopenharmony_ci icd_term->scanned_icd->lib_name, &icd_exts); 53835db71995Sopenharmony_ci if (VK_SUCCESS != res) { 53845db71995Sopenharmony_ci loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts); 53855db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 53865db71995Sopenharmony_ci // If out of memory, bail immediately. 53875db71995Sopenharmony_ci goto out; 53885db71995Sopenharmony_ci } else { 53895db71995Sopenharmony_ci // Something bad happened with this ICD, so free it and try the next. 53905db71995Sopenharmony_ci ptr_instance->icd_terms = icd_term->next; 53915db71995Sopenharmony_ci icd_term->next = NULL; 53925db71995Sopenharmony_ci loader_icd_destroy(ptr_instance, icd_term, pAllocator); 53935db71995Sopenharmony_ci continue; 53945db71995Sopenharmony_ci } 53955db71995Sopenharmony_ci } 53965db71995Sopenharmony_ci 53975db71995Sopenharmony_ci for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) { 53985db71995Sopenharmony_ci prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts); 53995db71995Sopenharmony_ci if (prop) { 54005db71995Sopenharmony_ci filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j]; 54015db71995Sopenharmony_ci icd_create_info.enabledExtensionCount++; 54025db71995Sopenharmony_ci } 54035db71995Sopenharmony_ci } 54045db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 54055db71995Sopenharmony_ci // Force on "VK_KHR_get_physical_device_properties2" for Linux as we use it for GPU sorting. This 54065db71995Sopenharmony_ci // should be done if the API version of either the application or the driver does not natively support 54075db71995Sopenharmony_ci // the core version of vkGetPhysicalDeviceProperties2 entrypoint. 54085db71995Sopenharmony_ci if ((ptr_instance->app_api_version.major == 1 && ptr_instance->app_api_version.minor == 0) || 54095db71995Sopenharmony_ci (VK_API_VERSION_MAJOR(icd_term->scanned_icd->api_version) == 1 && 54105db71995Sopenharmony_ci VK_API_VERSION_MINOR(icd_term->scanned_icd->api_version) == 0)) { 54115db71995Sopenharmony_ci prop = get_extension_property(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, &icd_exts); 54125db71995Sopenharmony_ci if (prop) { 54135db71995Sopenharmony_ci filtered_extension_names[icd_create_info.enabledExtensionCount] = 54145db71995Sopenharmony_ci (char *)VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; 54155db71995Sopenharmony_ci icd_create_info.enabledExtensionCount++; 54165db71995Sopenharmony_ci 54175db71995Sopenharmony_ci // At least one ICD supports this, so the instance should be able to support it 54185db71995Sopenharmony_ci ptr_instance->supports_get_dev_prop_2 = true; 54195db71995Sopenharmony_ci } 54205db71995Sopenharmony_ci } 54215db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 54225db71995Sopenharmony_ci 54235db71995Sopenharmony_ci // Determine if vkGetPhysicalDeviceProperties2 is available to this Instance 54245db71995Sopenharmony_ci if (icd_term->scanned_icd->api_version >= VK_API_VERSION_1_1) { 54255db71995Sopenharmony_ci icd_term->supports_get_dev_prop_2 = true; 54265db71995Sopenharmony_ci } else { 54275db71995Sopenharmony_ci for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) { 54285db71995Sopenharmony_ci if (!strcmp(filtered_extension_names[j], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { 54295db71995Sopenharmony_ci icd_term->supports_get_dev_prop_2 = true; 54305db71995Sopenharmony_ci break; 54315db71995Sopenharmony_ci } 54325db71995Sopenharmony_ci } 54335db71995Sopenharmony_ci } 54345db71995Sopenharmony_ci 54355db71995Sopenharmony_ci loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts); 54365db71995Sopenharmony_ci 54375db71995Sopenharmony_ci // Get the driver version from vkEnumerateInstanceVersion 54385db71995Sopenharmony_ci uint32_t icd_version = VK_API_VERSION_1_0; 54395db71995Sopenharmony_ci VkResult icd_result = VK_SUCCESS; 54405db71995Sopenharmony_ci if (icd_term->scanned_icd->api_version >= VK_API_VERSION_1_1) { 54415db71995Sopenharmony_ci PFN_vkEnumerateInstanceVersion icd_enumerate_instance_version = 54425db71995Sopenharmony_ci (PFN_vkEnumerateInstanceVersion)icd_term->scanned_icd->GetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion"); 54435db71995Sopenharmony_ci if (icd_enumerate_instance_version != NULL) { 54445db71995Sopenharmony_ci icd_result = icd_enumerate_instance_version(&icd_version); 54455db71995Sopenharmony_ci if (icd_result != VK_SUCCESS) { 54465db71995Sopenharmony_ci icd_version = VK_API_VERSION_1_0; 54475db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 54485db71995Sopenharmony_ci "terminator_CreateInstance: ICD \"%s\" vkEnumerateInstanceVersion returned error. The ICD will be " 54495db71995Sopenharmony_ci "treated as a 1.0 ICD", 54505db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 54515db71995Sopenharmony_ci } else if (VK_API_VERSION_MINOR(icd_version) == 0) { 54525db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 54535db71995Sopenharmony_ci "terminator_CreateInstance: Manifest ICD for \"%s\" contained a 1.1 or greater API version, but " 54545db71995Sopenharmony_ci "vkEnumerateInstanceVersion returned 1.0, treating as a 1.0 ICD", 54555db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 54565db71995Sopenharmony_ci } 54575db71995Sopenharmony_ci } else { 54585db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 54595db71995Sopenharmony_ci "terminator_CreateInstance: Manifest ICD for \"%s\" contained a 1.1 or greater API version, but does " 54605db71995Sopenharmony_ci "not support vkEnumerateInstanceVersion, treating as a 1.0 ICD", 54615db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 54625db71995Sopenharmony_ci } 54635db71995Sopenharmony_ci } 54645db71995Sopenharmony_ci 54655db71995Sopenharmony_ci // Remove the portability enumeration flag bit if the ICD doesn't support the extension 54665db71995Sopenharmony_ci if ((pCreateInfo->flags & VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) == 1) { 54675db71995Sopenharmony_ci bool supports_portability_enumeration = false; 54685db71995Sopenharmony_ci for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) { 54695db71995Sopenharmony_ci if (strcmp(filtered_extension_names[j], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) { 54705db71995Sopenharmony_ci supports_portability_enumeration = true; 54715db71995Sopenharmony_ci break; 54725db71995Sopenharmony_ci } 54735db71995Sopenharmony_ci } 54745db71995Sopenharmony_ci // If the icd supports the extension, use the flags as given, otherwise remove the portability bit 54755db71995Sopenharmony_ci icd_create_info.flags = supports_portability_enumeration 54765db71995Sopenharmony_ci ? pCreateInfo->flags 54775db71995Sopenharmony_ci : pCreateInfo->flags & (~VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR); 54785db71995Sopenharmony_ci } 54795db71995Sopenharmony_ci 54805db71995Sopenharmony_ci // Create an instance, substituting the version to 1.0 if necessary 54815db71995Sopenharmony_ci VkApplicationInfo icd_app_info; 54825db71995Sopenharmony_ci const uint32_t api_variant = 0; 54835db71995Sopenharmony_ci const uint32_t api_version_1_0 = VK_API_VERSION_1_0; 54845db71995Sopenharmony_ci uint32_t icd_version_nopatch = 54855db71995Sopenharmony_ci VK_MAKE_API_VERSION(api_variant, VK_API_VERSION_MAJOR(icd_version), VK_API_VERSION_MINOR(icd_version), 0); 54865db71995Sopenharmony_ci uint32_t requested_version = (pCreateInfo == NULL || pCreateInfo->pApplicationInfo == NULL) 54875db71995Sopenharmony_ci ? api_version_1_0 54885db71995Sopenharmony_ci : pCreateInfo->pApplicationInfo->apiVersion; 54895db71995Sopenharmony_ci if ((requested_version != 0) && (icd_version_nopatch == api_version_1_0)) { 54905db71995Sopenharmony_ci if (icd_create_info.pApplicationInfo == NULL) { 54915db71995Sopenharmony_ci memset(&icd_app_info, 0, sizeof(icd_app_info)); 54925db71995Sopenharmony_ci } else { 54935db71995Sopenharmony_ci memmove(&icd_app_info, icd_create_info.pApplicationInfo, sizeof(icd_app_info)); 54945db71995Sopenharmony_ci } 54955db71995Sopenharmony_ci icd_app_info.apiVersion = icd_version; 54965db71995Sopenharmony_ci icd_create_info.pApplicationInfo = &icd_app_info; 54975db71995Sopenharmony_ci } 54985db71995Sopenharmony_ci icd_result = 54995db71995Sopenharmony_ci ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(&icd_create_info, pAllocator, &(icd_term->instance)); 55005db71995Sopenharmony_ci if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) { 55015db71995Sopenharmony_ci // If out of memory, bail immediately. 55025db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 55035db71995Sopenharmony_ci goto out; 55045db71995Sopenharmony_ci } else if (VK_SUCCESS != icd_result) { 55055db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0, 55065db71995Sopenharmony_ci "terminator_CreateInstance: Received return code %i from call to vkCreateInstance in ICD %s. Skipping " 55075db71995Sopenharmony_ci "this driver.", 55085db71995Sopenharmony_ci icd_result, icd_term->scanned_icd->lib_name); 55095db71995Sopenharmony_ci ptr_instance->icd_terms = icd_term->next; 55105db71995Sopenharmony_ci icd_term->next = NULL; 55115db71995Sopenharmony_ci loader_icd_destroy(ptr_instance, icd_term, pAllocator); 55125db71995Sopenharmony_ci continue; 55135db71995Sopenharmony_ci } 55145db71995Sopenharmony_ci 55155db71995Sopenharmony_ci if (!loader_icd_init_entries(ptr_instance, icd_term)) { 55165db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0, 55175db71995Sopenharmony_ci "terminator_CreateInstance: Failed to find required entrypoints in ICD %s. Skipping this driver.", 55185db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 55195db71995Sopenharmony_ci ptr_instance->icd_terms = icd_term->next; 55205db71995Sopenharmony_ci icd_term->next = NULL; 55215db71995Sopenharmony_ci loader_icd_destroy(ptr_instance, icd_term, pAllocator); 55225db71995Sopenharmony_ci continue; 55235db71995Sopenharmony_ci } 55245db71995Sopenharmony_ci 55255db71995Sopenharmony_ci if (ptr_instance->icd_tramp_list.scanned_list[i].interface_version < 3 && 55265db71995Sopenharmony_ci ( 55275db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_XLIB_KHR) 55285db71995Sopenharmony_ci NULL != icd_term->dispatch.CreateXlibSurfaceKHR || 55295db71995Sopenharmony_ci#endif // VK_USE_PLATFORM_XLIB_KHR 55305db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_XCB_KHR) 55315db71995Sopenharmony_ci NULL != icd_term->dispatch.CreateXcbSurfaceKHR || 55325db71995Sopenharmony_ci#endif // VK_USE_PLATFORM_XCB_KHR 55335db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WAYLAND_KHR) 55345db71995Sopenharmony_ci NULL != icd_term->dispatch.CreateWaylandSurfaceKHR || 55355db71995Sopenharmony_ci#endif // VK_USE_PLATFORM_WAYLAND_KHR 55365db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_ANDROID_KHR) 55375db71995Sopenharmony_ci NULL != icd_term->dispatch.CreateAndroidSurfaceKHR || 55385db71995Sopenharmony_ci#endif // VK_USE_PLATFORM_ANDROID_KHR 55395db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_OHOS) 55405db71995Sopenharmony_ci NULL != icd_term->dispatch.CreateSurfaceOHOS || 55415db71995Sopenharmony_ci#endif // VK_USE_PLATFORM_OHOS 55425db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WIN32_KHR) 55435db71995Sopenharmony_ci NULL != icd_term->dispatch.CreateWin32SurfaceKHR || 55445db71995Sopenharmony_ci#endif // VK_USE_PLATFORM_WIN32_KHR 55455db71995Sopenharmony_ci NULL != icd_term->dispatch.DestroySurfaceKHR)) { 55465db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0, 55475db71995Sopenharmony_ci "terminator_CreateInstance: Driver %s supports interface version %u but still exposes VkSurfaceKHR" 55485db71995Sopenharmony_ci " create/destroy entrypoints (Policy #LDP_DRIVER_8)", 55495db71995Sopenharmony_ci ptr_instance->icd_tramp_list.scanned_list[i].lib_name, 55505db71995Sopenharmony_ci ptr_instance->icd_tramp_list.scanned_list[i].interface_version); 55515db71995Sopenharmony_ci } 55525db71995Sopenharmony_ci 55535db71995Sopenharmony_ci // If we made it this far, at least one ICD was successful 55545db71995Sopenharmony_ci one_icd_successful = true; 55555db71995Sopenharmony_ci } 55565db71995Sopenharmony_ci 55575db71995Sopenharmony_ci // For vkGetPhysicalDeviceProperties2, at least one ICD needs to support the extension for the 55585db71995Sopenharmony_ci // instance to have it 55595db71995Sopenharmony_ci if (ptr_instance->supports_get_dev_prop_2) { 55605db71995Sopenharmony_ci bool at_least_one_supports = false; 55615db71995Sopenharmony_ci icd_term = ptr_instance->icd_terms; 55625db71995Sopenharmony_ci while (icd_term != NULL) { 55635db71995Sopenharmony_ci if (icd_term->supports_get_dev_prop_2) { 55645db71995Sopenharmony_ci at_least_one_supports = true; 55655db71995Sopenharmony_ci break; 55665db71995Sopenharmony_ci } 55675db71995Sopenharmony_ci icd_term = icd_term->next; 55685db71995Sopenharmony_ci } 55695db71995Sopenharmony_ci if (!at_least_one_supports) { 55705db71995Sopenharmony_ci ptr_instance->supports_get_dev_prop_2 = false; 55715db71995Sopenharmony_ci } 55725db71995Sopenharmony_ci } 55735db71995Sopenharmony_ci 55745db71995Sopenharmony_ci // If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to 55755db71995Sopenharmony_ci // find a suitable ICD. 55765db71995Sopenharmony_ci if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) { 55775db71995Sopenharmony_ci loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 55785db71995Sopenharmony_ci "terminator_CreateInstance: Found no drivers!"); 55795db71995Sopenharmony_ci res = VK_ERROR_INCOMPATIBLE_DRIVER; 55805db71995Sopenharmony_ci } 55815db71995Sopenharmony_ci 55825db71995Sopenharmony_ciout: 55835db71995Sopenharmony_ci 55845db71995Sopenharmony_ci ptr_instance->create_terminator_invalid_extension = false; 55855db71995Sopenharmony_ci 55865db71995Sopenharmony_ci if (VK_SUCCESS != res) { 55875db71995Sopenharmony_ci if (VK_ERROR_EXTENSION_NOT_PRESENT == res) { 55885db71995Sopenharmony_ci ptr_instance->create_terminator_invalid_extension = true; 55895db71995Sopenharmony_ci } 55905db71995Sopenharmony_ci 55915db71995Sopenharmony_ci while (NULL != ptr_instance->icd_terms) { 55925db71995Sopenharmony_ci icd_term = ptr_instance->icd_terms; 55935db71995Sopenharmony_ci ptr_instance->icd_terms = icd_term->next; 55945db71995Sopenharmony_ci if (NULL != icd_term->instance) { 55955db71995Sopenharmony_ci icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator); 55965db71995Sopenharmony_ci } 55975db71995Sopenharmony_ci loader_icd_destroy(ptr_instance, icd_term, pAllocator); 55985db71995Sopenharmony_ci } 55995db71995Sopenharmony_ci } else { 56005db71995Sopenharmony_ci // Check for enabled extensions here to setup the loader structures so the loader knows what extensions 56015db71995Sopenharmony_ci // it needs to worry about. 56025db71995Sopenharmony_ci // We do it here and again above the layers in the trampoline function since the trampoline function 56035db71995Sopenharmony_ci // may think different extensions are enabled than what's down here. 56045db71995Sopenharmony_ci // This is why we don't clear inside of these function calls. 56055db71995Sopenharmony_ci // The clearing should actually be handled by the overall memset of the pInstance structure in the 56065db71995Sopenharmony_ci // trampoline. 56075db71995Sopenharmony_ci wsi_create_instance(ptr_instance, pCreateInfo); 56085db71995Sopenharmony_ci check_for_enabled_debug_extensions(ptr_instance, pCreateInfo); 56095db71995Sopenharmony_ci extensions_create_instance(ptr_instance, pCreateInfo); 56105db71995Sopenharmony_ci } 56115db71995Sopenharmony_ci 56125db71995Sopenharmony_ci return res; 56135db71995Sopenharmony_ci} 56145db71995Sopenharmony_ci 56155db71995Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) { 56165db71995Sopenharmony_ci struct loader_instance *ptr_instance = loader_get_instance(instance); 56175db71995Sopenharmony_ci if (NULL == ptr_instance) { 56185db71995Sopenharmony_ci return; 56195db71995Sopenharmony_ci } 56205db71995Sopenharmony_ci struct loader_icd_term *icd_terms = ptr_instance->icd_terms; 56215db71995Sopenharmony_ci struct loader_icd_term *next_icd_term; 56225db71995Sopenharmony_ci 56235db71995Sopenharmony_ci // Remove this instance from the list of instances: 56245db71995Sopenharmony_ci struct loader_instance *prev = NULL; 56255db71995Sopenharmony_ci loader_platform_thread_lock_mutex(&loader_global_instance_list_lock); 56265db71995Sopenharmony_ci struct loader_instance *next = loader.instances; 56275db71995Sopenharmony_ci while (next != NULL) { 56285db71995Sopenharmony_ci if (next == ptr_instance) { 56295db71995Sopenharmony_ci // Remove this instance from the list: 56305db71995Sopenharmony_ci if (prev) 56315db71995Sopenharmony_ci prev->next = next->next; 56325db71995Sopenharmony_ci else 56335db71995Sopenharmony_ci loader.instances = next->next; 56345db71995Sopenharmony_ci break; 56355db71995Sopenharmony_ci } 56365db71995Sopenharmony_ci prev = next; 56375db71995Sopenharmony_ci next = next->next; 56385db71995Sopenharmony_ci } 56395db71995Sopenharmony_ci loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock); 56405db71995Sopenharmony_ci 56415db71995Sopenharmony_ci while (NULL != icd_terms) { 56425db71995Sopenharmony_ci if (icd_terms->instance) { 56435db71995Sopenharmony_ci icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator); 56445db71995Sopenharmony_ci } 56455db71995Sopenharmony_ci next_icd_term = icd_terms->next; 56465db71995Sopenharmony_ci icd_terms->instance = VK_NULL_HANDLE; 56475db71995Sopenharmony_ci loader_icd_destroy(ptr_instance, icd_terms, pAllocator); 56485db71995Sopenharmony_ci 56495db71995Sopenharmony_ci icd_terms = next_icd_term; 56505db71995Sopenharmony_ci } 56515db71995Sopenharmony_ci 56525db71995Sopenharmony_ci loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list); 56535db71995Sopenharmony_ci loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list); 56545db71995Sopenharmony_ci if (NULL != ptr_instance->phys_devs_term) { 56555db71995Sopenharmony_ci for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) { 56565db71995Sopenharmony_ci for (uint32_t j = i + 1; j < ptr_instance->phys_dev_count_term; j++) { 56575db71995Sopenharmony_ci if (ptr_instance->phys_devs_term[i] == ptr_instance->phys_devs_term[j]) { 56585db71995Sopenharmony_ci ptr_instance->phys_devs_term[j] = NULL; 56595db71995Sopenharmony_ci } 56605db71995Sopenharmony_ci } 56615db71995Sopenharmony_ci } 56625db71995Sopenharmony_ci for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) { 56635db71995Sopenharmony_ci loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term[i]); 56645db71995Sopenharmony_ci } 56655db71995Sopenharmony_ci loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term); 56665db71995Sopenharmony_ci } 56675db71995Sopenharmony_ci if (NULL != ptr_instance->phys_dev_groups_term) { 56685db71995Sopenharmony_ci for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) { 56695db71995Sopenharmony_ci loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]); 56705db71995Sopenharmony_ci } 56715db71995Sopenharmony_ci loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term); 56725db71995Sopenharmony_ci } 56735db71995Sopenharmony_ci loader_free_dev_ext_table(ptr_instance); 56745db71995Sopenharmony_ci loader_free_phys_dev_ext_table(ptr_instance); 56755db71995Sopenharmony_ci 56765db71995Sopenharmony_ci free_string_list(ptr_instance, &ptr_instance->enabled_layer_names); 56775db71995Sopenharmony_ci} 56785db71995Sopenharmony_ci 56795db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, 56805db71995Sopenharmony_ci const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { 56815db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 56825db71995Sopenharmony_ci struct loader_physical_device_term *phys_dev_term; 56835db71995Sopenharmony_ci phys_dev_term = (struct loader_physical_device_term *)physicalDevice; 56845db71995Sopenharmony_ci struct loader_icd_term *icd_term = phys_dev_term->this_icd_term; 56855db71995Sopenharmony_ci 56865db71995Sopenharmony_ci struct loader_device *dev = (struct loader_device *)*pDevice; 56875db71995Sopenharmony_ci PFN_vkCreateDevice fpCreateDevice = icd_term->dispatch.CreateDevice; 56885db71995Sopenharmony_ci struct loader_extension_list icd_exts; 56895db71995Sopenharmony_ci 56905db71995Sopenharmony_ci VkBaseOutStructure *caller_dgci_container = NULL; 56915db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *caller_dgci = NULL; 56925db71995Sopenharmony_ci 56935db71995Sopenharmony_ci if (NULL == dev) { 56945db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0, 56955db71995Sopenharmony_ci "terminator_CreateDevice: Loader device pointer null encountered. Possibly set by active layer. (Policy " 56965db71995Sopenharmony_ci "#LLP_LAYER_22)"); 56975db71995Sopenharmony_ci } else if (DEVICE_DISP_TABLE_MAGIC_NUMBER != dev->loader_dispatch.core_dispatch.magic) { 56985db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0, 56995db71995Sopenharmony_ci "terminator_CreateDevice: Device pointer (%p) has invalid MAGIC value 0x%08lx. The expected value is " 57005db71995Sopenharmony_ci "0x10ADED040410ADED. Device value possibly " 57015db71995Sopenharmony_ci "corrupted by active layer (Policy #LLP_LAYER_22). ", 57025db71995Sopenharmony_ci dev, dev->loader_dispatch.core_dispatch.magic); 57035db71995Sopenharmony_ci } 57045db71995Sopenharmony_ci 57055db71995Sopenharmony_ci dev->phys_dev_term = phys_dev_term; 57065db71995Sopenharmony_ci 57075db71995Sopenharmony_ci icd_exts.list = NULL; 57085db71995Sopenharmony_ci 57095db71995Sopenharmony_ci if (fpCreateDevice == NULL) { 57105db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 57115db71995Sopenharmony_ci "terminator_CreateDevice: No vkCreateDevice command exposed by ICD %s", icd_term->scanned_icd->lib_name); 57125db71995Sopenharmony_ci res = VK_ERROR_INITIALIZATION_FAILED; 57135db71995Sopenharmony_ci goto out; 57145db71995Sopenharmony_ci } 57155db71995Sopenharmony_ci 57165db71995Sopenharmony_ci VkDeviceCreateInfo localCreateInfo; 57175db71995Sopenharmony_ci memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo)); 57185db71995Sopenharmony_ci 57195db71995Sopenharmony_ci // NOTE: Need to filter the extensions to only those supported by the ICD. 57205db71995Sopenharmony_ci // No ICD will advertise support for layers. An ICD library could support a layer, 57215db71995Sopenharmony_ci // but it would be independent of the actual ICD, just in the same library. 57225db71995Sopenharmony_ci char **filtered_extension_names = NULL; 57235db71995Sopenharmony_ci if (0 < pCreateInfo->enabledExtensionCount) { 57245db71995Sopenharmony_ci filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *)); 57255db71995Sopenharmony_ci if (NULL == filtered_extension_names) { 57265db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0, 57275db71995Sopenharmony_ci "terminator_CreateDevice: Failed to create extension name storage for %d extensions", 57285db71995Sopenharmony_ci pCreateInfo->enabledExtensionCount); 57295db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 57305db71995Sopenharmony_ci } 57315db71995Sopenharmony_ci } 57325db71995Sopenharmony_ci 57335db71995Sopenharmony_ci localCreateInfo.enabledLayerCount = 0; 57345db71995Sopenharmony_ci localCreateInfo.ppEnabledLayerNames = NULL; 57355db71995Sopenharmony_ci 57365db71995Sopenharmony_ci localCreateInfo.enabledExtensionCount = 0; 57375db71995Sopenharmony_ci localCreateInfo.ppEnabledExtensionNames = (const char *const *)filtered_extension_names; 57385db71995Sopenharmony_ci 57395db71995Sopenharmony_ci // Get the physical device (ICD) extensions 57405db71995Sopenharmony_ci res = loader_init_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties)); 57415db71995Sopenharmony_ci if (VK_SUCCESS != res) { 57425db71995Sopenharmony_ci goto out; 57435db71995Sopenharmony_ci } 57445db71995Sopenharmony_ci 57455db71995Sopenharmony_ci res = loader_add_device_extensions(icd_term->this_instance, icd_term->dispatch.EnumerateDeviceExtensionProperties, 57465db71995Sopenharmony_ci phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts); 57475db71995Sopenharmony_ci if (res != VK_SUCCESS) { 57485db71995Sopenharmony_ci goto out; 57495db71995Sopenharmony_ci } 57505db71995Sopenharmony_ci 57515db71995Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 57525db71995Sopenharmony_ci const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i]; 57535db71995Sopenharmony_ci VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts); 57545db71995Sopenharmony_ci if (prop) { 57555db71995Sopenharmony_ci filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name; 57565db71995Sopenharmony_ci localCreateInfo.enabledExtensionCount++; 57575db71995Sopenharmony_ci } else { 57585db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 57595db71995Sopenharmony_ci "vkCreateDevice extension %s not available for devices associated with ICD %s", extension_name, 57605db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 57615db71995Sopenharmony_ci } 57625db71995Sopenharmony_ci } 57635db71995Sopenharmony_ci 57645db71995Sopenharmony_ci // Before we continue, If KHX_device_group is the list of enabled and viable extensions, then we then need to look for the 57655db71995Sopenharmony_ci // corresponding VkDeviceGroupDeviceCreateInfo struct in the device list and replace all the physical device values (which 57665db71995Sopenharmony_ci // are really loader physical device terminator values) with the ICD versions. 57675db71995Sopenharmony_ci // if (icd_term->this_instance->enabled_known_extensions.khr_device_group_creation == 1) { 57685db71995Sopenharmony_ci { 57695db71995Sopenharmony_ci VkBaseOutStructure *pNext = (VkBaseOutStructure *)localCreateInfo.pNext; 57705db71995Sopenharmony_ci VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&localCreateInfo; 57715db71995Sopenharmony_ci while (NULL != pNext) { 57725db71995Sopenharmony_ci if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) { 57735db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext; 57745db71995Sopenharmony_ci if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) { 57755db71995Sopenharmony_ci VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo)); 57765db71995Sopenharmony_ci VkPhysicalDevice *phys_dev_array = NULL; 57775db71995Sopenharmony_ci if (NULL == temp_struct) { 57785db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 57795db71995Sopenharmony_ci } 57805db71995Sopenharmony_ci memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo)); 57815db71995Sopenharmony_ci phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount); 57825db71995Sopenharmony_ci if (NULL == phys_dev_array) { 57835db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 57845db71995Sopenharmony_ci } 57855db71995Sopenharmony_ci 57865db71995Sopenharmony_ci // Before calling down, replace the incoming physical device values (which are really loader terminator 57875db71995Sopenharmony_ci // physical devices) with the ICDs physical device values. 57885db71995Sopenharmony_ci struct loader_physical_device_term *cur_term; 57895db71995Sopenharmony_ci for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) { 57905db71995Sopenharmony_ci cur_term = (struct loader_physical_device_term *)cur_struct->pPhysicalDevices[phys_dev]; 57915db71995Sopenharmony_ci phys_dev_array[phys_dev] = cur_term->phys_dev; 57925db71995Sopenharmony_ci } 57935db71995Sopenharmony_ci temp_struct->pPhysicalDevices = phys_dev_array; 57945db71995Sopenharmony_ci 57955db71995Sopenharmony_ci // Keep track of pointers to restore pNext chain before returning 57965db71995Sopenharmony_ci caller_dgci_container = pPrev; 57975db71995Sopenharmony_ci caller_dgci = cur_struct; 57985db71995Sopenharmony_ci 57995db71995Sopenharmony_ci // Replace the old struct in the pNext chain with this one. 58005db71995Sopenharmony_ci pPrev->pNext = (VkBaseOutStructure *)temp_struct; 58015db71995Sopenharmony_ci } 58025db71995Sopenharmony_ci break; 58035db71995Sopenharmony_ci } 58045db71995Sopenharmony_ci 58055db71995Sopenharmony_ci pPrev = pNext; 58065db71995Sopenharmony_ci pNext = pNext->pNext; 58075db71995Sopenharmony_ci } 58085db71995Sopenharmony_ci } 58095db71995Sopenharmony_ci 58105db71995Sopenharmony_ci // Handle loader emulation for structs that are not supported by the ICD: 58115db71995Sopenharmony_ci // Presently, the emulation leaves the pNext chain alone. This means that the ICD will receive items in the chain which 58125db71995Sopenharmony_ci // are not recognized by the ICD. If this causes the ICD to fail, then the items would have to be removed here. The current 58135db71995Sopenharmony_ci // implementation does not remove them because copying the pNext chain would be impossible if the loader does not recognize 58145db71995Sopenharmony_ci // the any of the struct types, as the loader would not know the size to allocate and copy. 58155db71995Sopenharmony_ci // if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) { 58165db71995Sopenharmony_ci { 58175db71995Sopenharmony_ci const void *pNext = localCreateInfo.pNext; 58185db71995Sopenharmony_ci while (pNext != NULL) { 58195db71995Sopenharmony_ci switch (*(VkStructureType *)pNext) { 58205db71995Sopenharmony_ci case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: { 58215db71995Sopenharmony_ci const VkPhysicalDeviceFeatures2KHR *features = pNext; 58225db71995Sopenharmony_ci 58235db71995Sopenharmony_ci if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && 58245db71995Sopenharmony_ci icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) { 58255db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0, 58265db71995Sopenharmony_ci "vkCreateDevice: Emulating handling of VkPhysicalDeviceFeatures2 in pNext chain for ICD \"%s\"", 58275db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 58285db71995Sopenharmony_ci 58295db71995Sopenharmony_ci // Verify that VK_KHR_get_physical_device_properties2 is enabled 58305db71995Sopenharmony_ci if (icd_term->this_instance->enabled_known_extensions.khr_get_physical_device_properties2) { 58315db71995Sopenharmony_ci localCreateInfo.pEnabledFeatures = &features->features; 58325db71995Sopenharmony_ci } 58335db71995Sopenharmony_ci } 58345db71995Sopenharmony_ci 58355db71995Sopenharmony_ci // Leave this item in the pNext chain for now 58365db71995Sopenharmony_ci 58375db71995Sopenharmony_ci pNext = features->pNext; 58385db71995Sopenharmony_ci break; 58395db71995Sopenharmony_ci } 58405db71995Sopenharmony_ci 58415db71995Sopenharmony_ci case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: { 58425db71995Sopenharmony_ci const VkDeviceGroupDeviceCreateInfo *group_info = pNext; 58435db71995Sopenharmony_ci 58445db71995Sopenharmony_ci if (icd_term->dispatch.EnumeratePhysicalDeviceGroups == NULL && 58455db71995Sopenharmony_ci icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR == NULL) { 58465db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0, 58475db71995Sopenharmony_ci "vkCreateDevice: Emulating handling of VkPhysicalDeviceGroupProperties in pNext chain for " 58485db71995Sopenharmony_ci "ICD \"%s\"", 58495db71995Sopenharmony_ci icd_term->scanned_icd->lib_name); 58505db71995Sopenharmony_ci 58515db71995Sopenharmony_ci // The group must contain only this one device, since physical device groups aren't actually supported 58525db71995Sopenharmony_ci if (group_info->physicalDeviceCount != 1) { 58535db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0, 58545db71995Sopenharmony_ci "vkCreateDevice: Emulation failed to create device from device group info"); 58555db71995Sopenharmony_ci res = VK_ERROR_INITIALIZATION_FAILED; 58565db71995Sopenharmony_ci goto out; 58575db71995Sopenharmony_ci } 58585db71995Sopenharmony_ci } 58595db71995Sopenharmony_ci 58605db71995Sopenharmony_ci // Nothing needs to be done here because we're leaving the item in the pNext chain and because the spec 58615db71995Sopenharmony_ci // states that the physicalDevice argument must be included in the device group, and we've already checked 58625db71995Sopenharmony_ci // that it is 58635db71995Sopenharmony_ci 58645db71995Sopenharmony_ci pNext = group_info->pNext; 58655db71995Sopenharmony_ci break; 58665db71995Sopenharmony_ci } 58675db71995Sopenharmony_ci 58685db71995Sopenharmony_ci // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the 58695db71995Sopenharmony_ci // ICD handle that error when the user enables the extension here 58705db71995Sopenharmony_ci default: { 58715db71995Sopenharmony_ci const VkBaseInStructure *header = pNext; 58725db71995Sopenharmony_ci pNext = header->pNext; 58735db71995Sopenharmony_ci break; 58745db71995Sopenharmony_ci } 58755db71995Sopenharmony_ci } 58765db71995Sopenharmony_ci } 58775db71995Sopenharmony_ci } 58785db71995Sopenharmony_ci 58795db71995Sopenharmony_ci VkBool32 maintenance5_feature_enabled = false; 58805db71995Sopenharmony_ci // Look for the VkPhysicalDeviceMaintenance5FeaturesKHR struct to see if the feature was enabled 58815db71995Sopenharmony_ci { 58825db71995Sopenharmony_ci const void *pNext = localCreateInfo.pNext; 58835db71995Sopenharmony_ci while (pNext != NULL) { 58845db71995Sopenharmony_ci switch (*(VkStructureType *)pNext) { 58855db71995Sopenharmony_ci case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR: { 58865db71995Sopenharmony_ci const VkPhysicalDeviceMaintenance5FeaturesKHR *maintenance_features = pNext; 58875db71995Sopenharmony_ci if (maintenance_features->maintenance5 == VK_TRUE) { 58885db71995Sopenharmony_ci maintenance5_feature_enabled = true; 58895db71995Sopenharmony_ci } 58905db71995Sopenharmony_ci pNext = maintenance_features->pNext; 58915db71995Sopenharmony_ci break; 58925db71995Sopenharmony_ci } 58935db71995Sopenharmony_ci 58945db71995Sopenharmony_ci default: { 58955db71995Sopenharmony_ci const VkBaseInStructure *header = pNext; 58965db71995Sopenharmony_ci pNext = header->pNext; 58975db71995Sopenharmony_ci break; 58985db71995Sopenharmony_ci } 58995db71995Sopenharmony_ci } 59005db71995Sopenharmony_ci } 59015db71995Sopenharmony_ci } 59025db71995Sopenharmony_ci 59035db71995Sopenharmony_ci // Every extension that has a loader-defined terminator needs to be marked as enabled or disabled so that we know whether or 59045db71995Sopenharmony_ci // not to return that terminator when vkGetDeviceProcAddr is called 59055db71995Sopenharmony_ci for (uint32_t i = 0; i < localCreateInfo.enabledExtensionCount; ++i) { 59065db71995Sopenharmony_ci if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { 59075db71995Sopenharmony_ci dev->driver_extensions.khr_swapchain_enabled = true; 59085db71995Sopenharmony_ci } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME)) { 59095db71995Sopenharmony_ci dev->driver_extensions.khr_display_swapchain_enabled = true; 59105db71995Sopenharmony_ci } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_DEVICE_GROUP_EXTENSION_NAME)) { 59115db71995Sopenharmony_ci dev->driver_extensions.khr_device_group_enabled = true; 59125db71995Sopenharmony_ci } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { 59135db71995Sopenharmony_ci dev->driver_extensions.ext_debug_marker_enabled = true; 59145db71995Sopenharmony_ci } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], "VK_EXT_full_screen_exclusive")) { 59155db71995Sopenharmony_ci dev->driver_extensions.ext_full_screen_exclusive_enabled = true; 59165db71995Sopenharmony_ci } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_MAINTENANCE_5_EXTENSION_NAME) && 59175db71995Sopenharmony_ci maintenance5_feature_enabled) { 59185db71995Sopenharmony_ci dev->should_ignore_device_commands_from_newer_version = true; 59195db71995Sopenharmony_ci } 59205db71995Sopenharmony_ci } 59215db71995Sopenharmony_ci dev->layer_extensions.ext_debug_utils_enabled = icd_term->this_instance->enabled_known_extensions.ext_debug_utils; 59225db71995Sopenharmony_ci dev->driver_extensions.ext_debug_utils_enabled = icd_term->this_instance->enabled_known_extensions.ext_debug_utils; 59235db71995Sopenharmony_ci 59245db71995Sopenharmony_ci VkPhysicalDeviceProperties properties; 59255db71995Sopenharmony_ci icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &properties); 59265db71995Sopenharmony_ci if (!dev->driver_extensions.khr_device_group_enabled) { 59275db71995Sopenharmony_ci if (properties.apiVersion >= VK_API_VERSION_1_1) { 59285db71995Sopenharmony_ci dev->driver_extensions.khr_device_group_enabled = true; 59295db71995Sopenharmony_ci } 59305db71995Sopenharmony_ci } 59315db71995Sopenharmony_ci 59325db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 59335db71995Sopenharmony_ci " Using \"%s\" with driver: \"%s\"", properties.deviceName, icd_term->scanned_icd->lib_name); 59345db71995Sopenharmony_ci 59355db71995Sopenharmony_ci res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator, &dev->icd_device); 59365db71995Sopenharmony_ci if (res != VK_SUCCESS) { 59375db71995Sopenharmony_ci loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 59385db71995Sopenharmony_ci "terminator_CreateDevice: Failed in ICD %s vkCreateDevice call", icd_term->scanned_icd->lib_name); 59395db71995Sopenharmony_ci goto out; 59405db71995Sopenharmony_ci } 59415db71995Sopenharmony_ci 59425db71995Sopenharmony_ci *pDevice = dev->icd_device; 59435db71995Sopenharmony_ci loader_add_logical_device(icd_term, dev); 59445db71995Sopenharmony_ci 59455db71995Sopenharmony_ci // Init dispatch pointer in new device object 59465db71995Sopenharmony_ci loader_init_dispatch(*pDevice, &dev->loader_dispatch); 59475db71995Sopenharmony_ci 59485db71995Sopenharmony_ciout: 59495db71995Sopenharmony_ci if (NULL != icd_exts.list) { 59505db71995Sopenharmony_ci loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts); 59515db71995Sopenharmony_ci } 59525db71995Sopenharmony_ci 59535db71995Sopenharmony_ci // Restore pNext pointer to old VkDeviceGroupDeviceCreateInfo 59545db71995Sopenharmony_ci // in the chain to maintain consistency for the caller. 59555db71995Sopenharmony_ci if (caller_dgci_container != NULL) { 59565db71995Sopenharmony_ci caller_dgci_container->pNext = (VkBaseOutStructure *)caller_dgci; 59575db71995Sopenharmony_ci } 59585db71995Sopenharmony_ci 59595db71995Sopenharmony_ci return res; 59605db71995Sopenharmony_ci} 59615db71995Sopenharmony_ci 59625db71995Sopenharmony_ci// Update the trampoline physical devices with the wrapped version. 59635db71995Sopenharmony_ci// We always want to re-use previous physical device pointers since they may be used by an application 59645db71995Sopenharmony_ci// after returning previously. 59655db71995Sopenharmony_ciVkResult setup_loader_tramp_phys_devs(struct loader_instance *inst, uint32_t phys_dev_count, VkPhysicalDevice *phys_devs) { 59665db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 59675db71995Sopenharmony_ci uint32_t found_count = 0; 59685db71995Sopenharmony_ci uint32_t old_count = inst->phys_dev_count_tramp; 59695db71995Sopenharmony_ci uint32_t new_count = inst->total_gpu_count; 59705db71995Sopenharmony_ci struct loader_physical_device_tramp **new_phys_devs = NULL; 59715db71995Sopenharmony_ci 59725db71995Sopenharmony_ci if (0 == phys_dev_count) { 59735db71995Sopenharmony_ci return VK_SUCCESS; 59745db71995Sopenharmony_ci } 59755db71995Sopenharmony_ci if (phys_dev_count > new_count) { 59765db71995Sopenharmony_ci new_count = phys_dev_count; 59775db71995Sopenharmony_ci } 59785db71995Sopenharmony_ci 59795db71995Sopenharmony_ci // We want an old to new index array and a new to old index array 59805db71995Sopenharmony_ci int32_t *old_to_new_index = (int32_t *)loader_stack_alloc(sizeof(int32_t) * old_count); 59815db71995Sopenharmony_ci int32_t *new_to_old_index = (int32_t *)loader_stack_alloc(sizeof(int32_t) * new_count); 59825db71995Sopenharmony_ci if (NULL == old_to_new_index || NULL == new_to_old_index) { 59835db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 59845db71995Sopenharmony_ci } 59855db71995Sopenharmony_ci 59865db71995Sopenharmony_ci // Initialize both 59875db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) { 59885db71995Sopenharmony_ci old_to_new_index[cur_idx] = -1; 59895db71995Sopenharmony_ci } 59905db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < new_count; ++cur_idx) { 59915db71995Sopenharmony_ci new_to_old_index[cur_idx] = -1; 59925db71995Sopenharmony_ci } 59935db71995Sopenharmony_ci 59945db71995Sopenharmony_ci // Figure out the old->new and new->old indices 59955db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) { 59965db71995Sopenharmony_ci for (uint32_t new_idx = 0; new_idx < phys_dev_count; ++new_idx) { 59975db71995Sopenharmony_ci if (inst->phys_devs_tramp[cur_idx]->phys_dev == phys_devs[new_idx]) { 59985db71995Sopenharmony_ci old_to_new_index[cur_idx] = (int32_t)new_idx; 59995db71995Sopenharmony_ci new_to_old_index[new_idx] = (int32_t)cur_idx; 60005db71995Sopenharmony_ci found_count++; 60015db71995Sopenharmony_ci break; 60025db71995Sopenharmony_ci } 60035db71995Sopenharmony_ci } 60045db71995Sopenharmony_ci } 60055db71995Sopenharmony_ci 60065db71995Sopenharmony_ci // If we found exactly the number of items we were looking for as we had before. Then everything 60075db71995Sopenharmony_ci // we already have is good enough and we just need to update the array that was passed in with 60085db71995Sopenharmony_ci // the loader values. 60095db71995Sopenharmony_ci if (found_count == phys_dev_count && 0 != old_count && old_count == new_count) { 60105db71995Sopenharmony_ci for (uint32_t new_idx = 0; new_idx < phys_dev_count; ++new_idx) { 60115db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) { 60125db71995Sopenharmony_ci if (old_to_new_index[cur_idx] == (int32_t)new_idx) { 60135db71995Sopenharmony_ci phys_devs[new_idx] = (VkPhysicalDevice)inst->phys_devs_tramp[cur_idx]; 60145db71995Sopenharmony_ci break; 60155db71995Sopenharmony_ci } 60165db71995Sopenharmony_ci } 60175db71995Sopenharmony_ci } 60185db71995Sopenharmony_ci // Nothing else to do for this path 60195db71995Sopenharmony_ci res = VK_SUCCESS; 60205db71995Sopenharmony_ci } else { 60215db71995Sopenharmony_ci // Something is different, so do the full path of checking every device and creating a new array to use. 60225db71995Sopenharmony_ci // This can happen if a device was added, or removed, or we hadn't previously queried all the data and we 60235db71995Sopenharmony_ci // have more to store. 60245db71995Sopenharmony_ci new_phys_devs = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_tramp *) * new_count, 60255db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 60265db71995Sopenharmony_ci if (NULL == new_phys_devs) { 60275db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 60285db71995Sopenharmony_ci "setup_loader_tramp_phys_devs: Failed to allocate new physical device array of size %d", new_count); 60295db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 60305db71995Sopenharmony_ci goto out; 60315db71995Sopenharmony_ci } 60325db71995Sopenharmony_ci 60335db71995Sopenharmony_ci if (new_count > phys_dev_count) { 60345db71995Sopenharmony_ci found_count = phys_dev_count; 60355db71995Sopenharmony_ci } else { 60365db71995Sopenharmony_ci found_count = new_count; 60375db71995Sopenharmony_ci } 60385db71995Sopenharmony_ci 60395db71995Sopenharmony_ci // First try to see if an old item exists that matches the new item. If so, just copy it over. 60405db71995Sopenharmony_ci for (uint32_t new_idx = 0; new_idx < found_count; ++new_idx) { 60415db71995Sopenharmony_ci bool old_item_found = false; 60425db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) { 60435db71995Sopenharmony_ci if (old_to_new_index[cur_idx] == (int32_t)new_idx) { 60445db71995Sopenharmony_ci // Copy over old item to correct spot in the new array 60455db71995Sopenharmony_ci new_phys_devs[new_idx] = inst->phys_devs_tramp[cur_idx]; 60465db71995Sopenharmony_ci old_item_found = true; 60475db71995Sopenharmony_ci break; 60485db71995Sopenharmony_ci } 60495db71995Sopenharmony_ci } 60505db71995Sopenharmony_ci // Something wasn't found, so it's new so add it to the new list 60515db71995Sopenharmony_ci if (!old_item_found) { 60525db71995Sopenharmony_ci new_phys_devs[new_idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_tramp), 60535db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 60545db71995Sopenharmony_ci if (NULL == new_phys_devs[new_idx]) { 60555db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 60565db71995Sopenharmony_ci "setup_loader_tramp_phys_devs: Failed to allocate new trampoline physical device"); 60575db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 60585db71995Sopenharmony_ci goto out; 60595db71995Sopenharmony_ci } 60605db71995Sopenharmony_ci 60615db71995Sopenharmony_ci // Initialize the new physicalDevice object 60625db71995Sopenharmony_ci loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp); 60635db71995Sopenharmony_ci new_phys_devs[new_idx]->this_instance = inst; 60645db71995Sopenharmony_ci new_phys_devs[new_idx]->phys_dev = phys_devs[new_idx]; 60655db71995Sopenharmony_ci new_phys_devs[new_idx]->magic = PHYS_TRAMP_MAGIC_NUMBER; 60665db71995Sopenharmony_ci } 60675db71995Sopenharmony_ci 60685db71995Sopenharmony_ci phys_devs[new_idx] = (VkPhysicalDevice)new_phys_devs[new_idx]; 60695db71995Sopenharmony_ci } 60705db71995Sopenharmony_ci 60715db71995Sopenharmony_ci // We usually get here if the user array is smaller than the total number of devices, so copy the 60725db71995Sopenharmony_ci // remaining devices we have over to the new array. 60735db71995Sopenharmony_ci uint32_t start = found_count; 60745db71995Sopenharmony_ci for (uint32_t new_idx = start; new_idx < new_count; ++new_idx) { 60755db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) { 60765db71995Sopenharmony_ci if (old_to_new_index[cur_idx] == -1) { 60775db71995Sopenharmony_ci new_phys_devs[new_idx] = inst->phys_devs_tramp[cur_idx]; 60785db71995Sopenharmony_ci old_to_new_index[cur_idx] = new_idx; 60795db71995Sopenharmony_ci found_count++; 60805db71995Sopenharmony_ci break; 60815db71995Sopenharmony_ci } 60825db71995Sopenharmony_ci } 60835db71995Sopenharmony_ci } 60845db71995Sopenharmony_ci } 60855db71995Sopenharmony_ci 60865db71995Sopenharmony_ciout: 60875db71995Sopenharmony_ci 60885db71995Sopenharmony_ci if (NULL != new_phys_devs) { 60895db71995Sopenharmony_ci if (VK_SUCCESS != res) { 60905db71995Sopenharmony_ci for (uint32_t new_idx = 0; new_idx < found_count; ++new_idx) { 60915db71995Sopenharmony_ci // If an OOM occurred inside the copying of the new physical devices into the existing array 60925db71995Sopenharmony_ci // will leave some of the old physical devices in the array which may have been copied into 60935db71995Sopenharmony_ci // the new array, leading to them being freed twice. To avoid this we just make sure to not 60945db71995Sopenharmony_ci // delete physical devices which were copied. 60955db71995Sopenharmony_ci bool found = false; 60965db71995Sopenharmony_ci for (uint32_t cur_idx = 0; cur_idx < inst->phys_dev_count_tramp; cur_idx++) { 60975db71995Sopenharmony_ci if (new_phys_devs[new_idx] == inst->phys_devs_tramp[cur_idx]) { 60985db71995Sopenharmony_ci found = true; 60995db71995Sopenharmony_ci break; 61005db71995Sopenharmony_ci } 61015db71995Sopenharmony_ci } 61025db71995Sopenharmony_ci if (!found) { 61035db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_devs[new_idx]); 61045db71995Sopenharmony_ci } 61055db71995Sopenharmony_ci } 61065db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_devs); 61075db71995Sopenharmony_ci } else { 61085db71995Sopenharmony_ci if (new_count > inst->total_gpu_count) { 61095db71995Sopenharmony_ci inst->total_gpu_count = new_count; 61105db71995Sopenharmony_ci } 61115db71995Sopenharmony_ci // Free everything in the old array that was not copied into the new array 61125db71995Sopenharmony_ci // here. We can't attempt to do that before here since the previous loop 61135db71995Sopenharmony_ci // looking before the "out:" label may hit an out of memory condition resulting 61145db71995Sopenharmony_ci // in memory leaking. 61155db71995Sopenharmony_ci if (NULL != inst->phys_devs_tramp) { 61165db71995Sopenharmony_ci for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) { 61175db71995Sopenharmony_ci bool found = false; 61185db71995Sopenharmony_ci for (uint32_t j = 0; j < inst->total_gpu_count; j++) { 61195db71995Sopenharmony_ci if (inst->phys_devs_tramp[i] == new_phys_devs[j]) { 61205db71995Sopenharmony_ci found = true; 61215db71995Sopenharmony_ci break; 61225db71995Sopenharmony_ci } 61235db71995Sopenharmony_ci } 61245db71995Sopenharmony_ci if (!found) { 61255db71995Sopenharmony_ci loader_instance_heap_free(inst, inst->phys_devs_tramp[i]); 61265db71995Sopenharmony_ci } 61275db71995Sopenharmony_ci } 61285db71995Sopenharmony_ci loader_instance_heap_free(inst, inst->phys_devs_tramp); 61295db71995Sopenharmony_ci } 61305db71995Sopenharmony_ci inst->phys_devs_tramp = new_phys_devs; 61315db71995Sopenharmony_ci inst->phys_dev_count_tramp = found_count; 61325db71995Sopenharmony_ci } 61335db71995Sopenharmony_ci } 61345db71995Sopenharmony_ci if (VK_SUCCESS != res) { 61355db71995Sopenharmony_ci inst->total_gpu_count = 0; 61365db71995Sopenharmony_ci } 61375db71995Sopenharmony_ci 61385db71995Sopenharmony_ci return res; 61395db71995Sopenharmony_ci} 61405db71995Sopenharmony_ci 61415db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 61425db71995Sopenharmony_cibool is_linux_sort_enabled(struct loader_instance *inst) { 61435db71995Sopenharmony_ci bool sort_items = inst->supports_get_dev_prop_2; 61445db71995Sopenharmony_ci char *env_value = loader_getenv("VK_LOADER_DISABLE_SELECT", inst); 61455db71995Sopenharmony_ci if (NULL != env_value) { 61465db71995Sopenharmony_ci int32_t int_env_val = atoi(env_value); 61475db71995Sopenharmony_ci loader_free_getenv(env_value, inst); 61485db71995Sopenharmony_ci if (int_env_val != 0) { 61495db71995Sopenharmony_ci sort_items = false; 61505db71995Sopenharmony_ci } 61515db71995Sopenharmony_ci } 61525db71995Sopenharmony_ci return sort_items; 61535db71995Sopenharmony_ci} 61545db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 61555db71995Sopenharmony_ci 61565db71995Sopenharmony_ci// Look for physical_device in the provided phys_devs list, return true if found and put the index into out_idx, otherwise 61575db71995Sopenharmony_ci// return false 61585db71995Sopenharmony_cibool find_phys_dev(VkPhysicalDevice physical_device, uint32_t phys_devs_count, struct loader_physical_device_term **phys_devs, 61595db71995Sopenharmony_ci uint32_t *out_idx) { 61605db71995Sopenharmony_ci if (NULL == phys_devs) return false; 61615db71995Sopenharmony_ci for (uint32_t idx = 0; idx < phys_devs_count; idx++) { 61625db71995Sopenharmony_ci if (NULL != phys_devs[idx] && physical_device == phys_devs[idx]->phys_dev) { 61635db71995Sopenharmony_ci *out_idx = idx; 61645db71995Sopenharmony_ci return true; 61655db71995Sopenharmony_ci } 61665db71995Sopenharmony_ci } 61675db71995Sopenharmony_ci return false; 61685db71995Sopenharmony_ci} 61695db71995Sopenharmony_ci 61705db71995Sopenharmony_ci// Add physical_device to new_phys_devs 61715db71995Sopenharmony_ciVkResult check_and_add_to_new_phys_devs(struct loader_instance *inst, VkPhysicalDevice physical_device, 61725db71995Sopenharmony_ci struct loader_icd_physical_devices *dev_array, uint32_t *cur_new_phys_dev_count, 61735db71995Sopenharmony_ci struct loader_physical_device_term **new_phys_devs) { 61745db71995Sopenharmony_ci uint32_t out_idx = 0; 61755db71995Sopenharmony_ci uint32_t idx = *cur_new_phys_dev_count; 61765db71995Sopenharmony_ci // Check if the physical_device already exists in the new_phys_devs buffer, that means it was found from both 61775db71995Sopenharmony_ci // EnumerateAdapterPhysicalDevices and EnumeratePhysicalDevices and we need to skip it. 61785db71995Sopenharmony_ci if (find_phys_dev(physical_device, idx, new_phys_devs, &out_idx)) { 61795db71995Sopenharmony_ci return VK_SUCCESS; 61805db71995Sopenharmony_ci } 61815db71995Sopenharmony_ci // Check if it was found in a previous call to vkEnumeratePhysicalDevices, we can just copy over the old data. 61825db71995Sopenharmony_ci if (find_phys_dev(physical_device, inst->phys_dev_count_term, inst->phys_devs_term, &out_idx)) { 61835db71995Sopenharmony_ci new_phys_devs[idx] = inst->phys_devs_term[out_idx]; 61845db71995Sopenharmony_ci (*cur_new_phys_dev_count)++; 61855db71995Sopenharmony_ci return VK_SUCCESS; 61865db71995Sopenharmony_ci } 61875db71995Sopenharmony_ci 61885db71995Sopenharmony_ci // Exit in case something is already present - this shouldn't happen but better to be safe than overwrite existing data 61895db71995Sopenharmony_ci // since this code has been refactored a half dozen times. 61905db71995Sopenharmony_ci if (NULL != new_phys_devs[idx]) { 61915db71995Sopenharmony_ci return VK_SUCCESS; 61925db71995Sopenharmony_ci } 61935db71995Sopenharmony_ci // If this physical device is new, we need to allocate space for it. 61945db71995Sopenharmony_ci new_phys_devs[idx] = 61955db71995Sopenharmony_ci loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 61965db71995Sopenharmony_ci if (NULL == new_phys_devs[idx]) { 61975db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 61985db71995Sopenharmony_ci "check_and_add_to_new_phys_devs: Failed to allocate physical device terminator object %d", idx); 61995db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 62005db71995Sopenharmony_ci } 62015db71995Sopenharmony_ci 62025db71995Sopenharmony_ci loader_set_dispatch((void *)new_phys_devs[idx], inst->disp); 62035db71995Sopenharmony_ci new_phys_devs[idx]->this_icd_term = dev_array->icd_term; 62045db71995Sopenharmony_ci new_phys_devs[idx]->icd_index = (uint8_t)(dev_array->icd_index); 62055db71995Sopenharmony_ci new_phys_devs[idx]->phys_dev = physical_device; 62065db71995Sopenharmony_ci 62075db71995Sopenharmony_ci // Increment the count of new physical devices 62085db71995Sopenharmony_ci (*cur_new_phys_dev_count)++; 62095db71995Sopenharmony_ci return VK_SUCCESS; 62105db71995Sopenharmony_ci} 62115db71995Sopenharmony_ci 62125db71995Sopenharmony_ci/* Enumerate all physical devices from ICDs and add them to inst->phys_devs_term 62135db71995Sopenharmony_ci * 62145db71995Sopenharmony_ci * There are two methods to find VkPhysicalDevices - vkEnumeratePhysicalDevices and vkEnumerateAdapterPhysicalDevices 62155db71995Sopenharmony_ci * The latter is supported on windows only and on devices supporting ICD Interface Version 6 and greater. 62165db71995Sopenharmony_ci * 62175db71995Sopenharmony_ci * Once all physical devices are acquired, they need to be pulled into a single list of `loader_physical_device_term`'s. 62185db71995Sopenharmony_ci * They also need to be setup - the icd_term, icd_index, phys_dev, and disp (dispatch table) all need the correct data. 62195db71995Sopenharmony_ci * Additionally, we need to keep using already setup physical devices as they may be in use, thus anything enumerated 62205db71995Sopenharmony_ci * that is already in inst->phys_devs_term will be carried over. 62215db71995Sopenharmony_ci */ 62225db71995Sopenharmony_ci 62235db71995Sopenharmony_ciVkResult setup_loader_term_phys_devs(struct loader_instance *inst) { 62245db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 62255db71995Sopenharmony_ci struct loader_icd_term *icd_term; 62265db71995Sopenharmony_ci uint32_t icd_idx = 0; 62275db71995Sopenharmony_ci uint32_t windows_sorted_devices_count = 0; 62285db71995Sopenharmony_ci struct loader_icd_physical_devices *windows_sorted_devices_array = NULL; 62295db71995Sopenharmony_ci uint32_t icd_count = 0; 62305db71995Sopenharmony_ci struct loader_icd_physical_devices *icd_phys_dev_array = NULL; 62315db71995Sopenharmony_ci uint32_t new_phys_devs_capacity = 0; 62325db71995Sopenharmony_ci uint32_t new_phys_devs_count = 0; 62335db71995Sopenharmony_ci struct loader_physical_device_term **new_phys_devs = NULL; 62345db71995Sopenharmony_ci 62355db71995Sopenharmony_ci#if defined(_WIN32) 62365db71995Sopenharmony_ci // Get the physical devices supported by platform sorting mechanism into a separate list 62375db71995Sopenharmony_ci res = windows_read_sorted_physical_devices(inst, &windows_sorted_devices_count, &windows_sorted_devices_array); 62385db71995Sopenharmony_ci if (VK_SUCCESS != res) { 62395db71995Sopenharmony_ci goto out; 62405db71995Sopenharmony_ci } 62415db71995Sopenharmony_ci#endif 62425db71995Sopenharmony_ci 62435db71995Sopenharmony_ci icd_count = inst->total_icd_count; 62445db71995Sopenharmony_ci 62455db71995Sopenharmony_ci // Allocate something to store the physical device characteristics that we read from each ICD. 62465db71995Sopenharmony_ci icd_phys_dev_array = 62475db71995Sopenharmony_ci (struct loader_icd_physical_devices *)loader_stack_alloc(sizeof(struct loader_icd_physical_devices) * icd_count); 62485db71995Sopenharmony_ci if (NULL == icd_phys_dev_array) { 62495db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 62505db71995Sopenharmony_ci "setup_loader_term_phys_devs: Failed to allocate temporary ICD Physical device info array of size %d", 62515db71995Sopenharmony_ci icd_count); 62525db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 62535db71995Sopenharmony_ci goto out; 62545db71995Sopenharmony_ci } 62555db71995Sopenharmony_ci memset(icd_phys_dev_array, 0, sizeof(struct loader_icd_physical_devices) * icd_count); 62565db71995Sopenharmony_ci 62575db71995Sopenharmony_ci // For each ICD, query the number of physical devices, and then get an 62585db71995Sopenharmony_ci // internal value for those physical devices. 62595db71995Sopenharmony_ci icd_term = inst->icd_terms; 62605db71995Sopenharmony_ci while (NULL != icd_term) { 62615db71995Sopenharmony_ci res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].device_count, NULL); 62625db71995Sopenharmony_ci if (VK_SUCCESS != res) { 62635db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 62645db71995Sopenharmony_ci "setup_loader_term_phys_devs: Call to ICD %d's \'vkEnumeratePhysicalDevices\' failed with error 0x%08x", 62655db71995Sopenharmony_ci icd_idx, res); 62665db71995Sopenharmony_ci goto out; 62675db71995Sopenharmony_ci } 62685db71995Sopenharmony_ci 62695db71995Sopenharmony_ci icd_phys_dev_array[icd_idx].physical_devices = 62705db71995Sopenharmony_ci (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].device_count * sizeof(VkPhysicalDevice)); 62715db71995Sopenharmony_ci if (NULL == icd_phys_dev_array[icd_idx].physical_devices) { 62725db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 62735db71995Sopenharmony_ci "setup_loader_term_phys_devs: Failed to allocate temporary ICD Physical device array for ICD %d of size %d", 62745db71995Sopenharmony_ci icd_idx, icd_phys_dev_array[icd_idx].device_count); 62755db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 62765db71995Sopenharmony_ci goto out; 62775db71995Sopenharmony_ci } 62785db71995Sopenharmony_ci 62795db71995Sopenharmony_ci res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].device_count), 62805db71995Sopenharmony_ci icd_phys_dev_array[icd_idx].physical_devices); 62815db71995Sopenharmony_ci if (VK_SUCCESS != res) { 62825db71995Sopenharmony_ci goto out; 62835db71995Sopenharmony_ci } 62845db71995Sopenharmony_ci icd_phys_dev_array[icd_idx].icd_term = icd_term; 62855db71995Sopenharmony_ci icd_phys_dev_array[icd_idx].icd_index = icd_idx; 62865db71995Sopenharmony_ci icd_term = icd_term->next; 62875db71995Sopenharmony_ci ++icd_idx; 62885db71995Sopenharmony_ci } 62895db71995Sopenharmony_ci 62905db71995Sopenharmony_ci // Add up both the windows sorted and non windows found physical device counts 62915db71995Sopenharmony_ci for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) { 62925db71995Sopenharmony_ci new_phys_devs_capacity += windows_sorted_devices_array[i].device_count; 62935db71995Sopenharmony_ci } 62945db71995Sopenharmony_ci for (uint32_t i = 0; i < icd_count; ++i) { 62955db71995Sopenharmony_ci new_phys_devs_capacity += icd_phys_dev_array[i].device_count; 62965db71995Sopenharmony_ci } 62975db71995Sopenharmony_ci 62985db71995Sopenharmony_ci // Bail out if there are no physical devices reported 62995db71995Sopenharmony_ci if (0 == new_phys_devs_capacity) { 63005db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 63015db71995Sopenharmony_ci "setup_loader_term_phys_devs: Failed to detect any valid GPUs in the current config"); 63025db71995Sopenharmony_ci res = VK_ERROR_INITIALIZATION_FAILED; 63035db71995Sopenharmony_ci goto out; 63045db71995Sopenharmony_ci } 63055db71995Sopenharmony_ci 63065db71995Sopenharmony_ci // Create an allocation large enough to hold both the windows sorting enumeration and non-windows physical device 63075db71995Sopenharmony_ci // enumeration 63085db71995Sopenharmony_ci new_phys_devs = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_term *) * new_phys_devs_capacity, 63095db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 63105db71995Sopenharmony_ci if (NULL == new_phys_devs) { 63115db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 63125db71995Sopenharmony_ci "setup_loader_term_phys_devs: Failed to allocate new physical device array of size %d", new_phys_devs_capacity); 63135db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 63145db71995Sopenharmony_ci goto out; 63155db71995Sopenharmony_ci } 63165db71995Sopenharmony_ci 63175db71995Sopenharmony_ci // Copy over everything found through sorted enumeration 63185db71995Sopenharmony_ci for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) { 63195db71995Sopenharmony_ci for (uint32_t j = 0; j < windows_sorted_devices_array[i].device_count; ++j) { 63205db71995Sopenharmony_ci res = check_and_add_to_new_phys_devs(inst, windows_sorted_devices_array[i].physical_devices[j], 63215db71995Sopenharmony_ci &windows_sorted_devices_array[i], &new_phys_devs_count, new_phys_devs); 63225db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 63235db71995Sopenharmony_ci goto out; 63245db71995Sopenharmony_ci } 63255db71995Sopenharmony_ci } 63265db71995Sopenharmony_ci } 63275db71995Sopenharmony_ci 63285db71995Sopenharmony_ci// Now go through the rest of the physical devices and add them to new_phys_devs 63295db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 63305db71995Sopenharmony_ci 63315db71995Sopenharmony_ci if (is_linux_sort_enabled(inst)) { 63325db71995Sopenharmony_ci for (uint32_t dev = new_phys_devs_count; dev < new_phys_devs_capacity; ++dev) { 63335db71995Sopenharmony_ci new_phys_devs[dev] = 63345db71995Sopenharmony_ci loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 63355db71995Sopenharmony_ci if (NULL == new_phys_devs[dev]) { 63365db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 63375db71995Sopenharmony_ci "setup_loader_term_phys_devs: Failed to allocate physical device terminator object %d", dev); 63385db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 63395db71995Sopenharmony_ci goto out; 63405db71995Sopenharmony_ci } 63415db71995Sopenharmony_ci } 63425db71995Sopenharmony_ci 63435db71995Sopenharmony_ci // Get the physical devices supported by platform sorting mechanism into a separate list 63445db71995Sopenharmony_ci // Pass in a sublist to the function so it only operates on the correct elements. This means passing in a pointer to the 63455db71995Sopenharmony_ci // current next element in new_phys_devs and passing in a `count` of currently unwritten elements 63465db71995Sopenharmony_ci res = linux_read_sorted_physical_devices(inst, icd_count, icd_phys_dev_array, new_phys_devs_capacity - new_phys_devs_count, 63475db71995Sopenharmony_ci &new_phys_devs[new_phys_devs_count]); 63485db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 63495db71995Sopenharmony_ci goto out; 63505db71995Sopenharmony_ci } 63515db71995Sopenharmony_ci // Keep previously allocated physical device info since apps may already be using that! 63525db71995Sopenharmony_ci for (uint32_t new_idx = new_phys_devs_count; new_idx < new_phys_devs_capacity; new_idx++) { 63535db71995Sopenharmony_ci for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) { 63545db71995Sopenharmony_ci if (new_phys_devs[new_idx]->phys_dev == inst->phys_devs_term[old_idx]->phys_dev) { 63555db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 63565db71995Sopenharmony_ci "Copying old device %u into new device %u", old_idx, new_idx); 63575db71995Sopenharmony_ci // Free the old new_phys_devs info since we're not using it before we assign the new info 63585db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_devs[new_idx]); 63595db71995Sopenharmony_ci new_phys_devs[new_idx] = inst->phys_devs_term[old_idx]; 63605db71995Sopenharmony_ci break; 63615db71995Sopenharmony_ci } 63625db71995Sopenharmony_ci } 63635db71995Sopenharmony_ci } 63645db71995Sopenharmony_ci // now set the count to the capacity, as now the list is filled in 63655db71995Sopenharmony_ci new_phys_devs_count = new_phys_devs_capacity; 63665db71995Sopenharmony_ci // We want the following code to run if either linux sorting is disabled at compile time or runtime 63675db71995Sopenharmony_ci } else { 63685db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 63695db71995Sopenharmony_ci 63705db71995Sopenharmony_ci // Copy over everything found through the non-sorted means. 63715db71995Sopenharmony_ci for (uint32_t i = 0; i < icd_count; ++i) { 63725db71995Sopenharmony_ci for (uint32_t j = 0; j < icd_phys_dev_array[i].device_count; ++j) { 63735db71995Sopenharmony_ci res = check_and_add_to_new_phys_devs(inst, icd_phys_dev_array[i].physical_devices[j], &icd_phys_dev_array[i], 63745db71995Sopenharmony_ci &new_phys_devs_count, new_phys_devs); 63755db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 63765db71995Sopenharmony_ci goto out; 63775db71995Sopenharmony_ci } 63785db71995Sopenharmony_ci } 63795db71995Sopenharmony_ci } 63805db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 63815db71995Sopenharmony_ci } 63825db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 63835db71995Sopenharmony_ciout: 63845db71995Sopenharmony_ci 63855db71995Sopenharmony_ci if (VK_SUCCESS != res) { 63865db71995Sopenharmony_ci if (NULL != new_phys_devs) { 63875db71995Sopenharmony_ci // We've encountered an error, so we should free the new buffers. 63885db71995Sopenharmony_ci for (uint32_t i = 0; i < new_phys_devs_capacity; i++) { 63895db71995Sopenharmony_ci // May not have allocated this far, skip it if we hadn't. 63905db71995Sopenharmony_ci if (new_phys_devs[i] == NULL) continue; 63915db71995Sopenharmony_ci 63925db71995Sopenharmony_ci // If an OOM occurred inside the copying of the new physical devices into the existing array 63935db71995Sopenharmony_ci // will leave some of the old physical devices in the array which may have been copied into 63945db71995Sopenharmony_ci // the new array, leading to them being freed twice. To avoid this we just make sure to not 63955db71995Sopenharmony_ci // delete physical devices which were copied. 63965db71995Sopenharmony_ci bool found = false; 63975db71995Sopenharmony_ci if (NULL != inst->phys_devs_term) { 63985db71995Sopenharmony_ci for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) { 63995db71995Sopenharmony_ci if (new_phys_devs[i] == inst->phys_devs_term[old_idx]) { 64005db71995Sopenharmony_ci found = true; 64015db71995Sopenharmony_ci break; 64025db71995Sopenharmony_ci } 64035db71995Sopenharmony_ci } 64045db71995Sopenharmony_ci } 64055db71995Sopenharmony_ci if (!found) { 64065db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_devs[i]); 64075db71995Sopenharmony_ci } 64085db71995Sopenharmony_ci } 64095db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_devs); 64105db71995Sopenharmony_ci } 64115db71995Sopenharmony_ci inst->total_gpu_count = 0; 64125db71995Sopenharmony_ci } else { 64135db71995Sopenharmony_ci if (NULL != inst->phys_devs_term) { 64145db71995Sopenharmony_ci // Free everything in the old array that was not copied into the new array 64155db71995Sopenharmony_ci // here. We can't attempt to do that before here since the previous loop 64165db71995Sopenharmony_ci // looking before the "out:" label may hit an out of memory condition resulting 64175db71995Sopenharmony_ci // in memory leaking. 64185db71995Sopenharmony_ci for (uint32_t i = 0; i < inst->phys_dev_count_term; i++) { 64195db71995Sopenharmony_ci bool found = false; 64205db71995Sopenharmony_ci for (uint32_t j = 0; j < new_phys_devs_count; j++) { 64215db71995Sopenharmony_ci if (new_phys_devs != NULL && inst->phys_devs_term[i] == new_phys_devs[j]) { 64225db71995Sopenharmony_ci found = true; 64235db71995Sopenharmony_ci break; 64245db71995Sopenharmony_ci } 64255db71995Sopenharmony_ci } 64265db71995Sopenharmony_ci if (!found) { 64275db71995Sopenharmony_ci loader_instance_heap_free(inst, inst->phys_devs_term[i]); 64285db71995Sopenharmony_ci } 64295db71995Sopenharmony_ci } 64305db71995Sopenharmony_ci loader_instance_heap_free(inst, inst->phys_devs_term); 64315db71995Sopenharmony_ci } 64325db71995Sopenharmony_ci 64335db71995Sopenharmony_ci // Swap out old and new devices list 64345db71995Sopenharmony_ci inst->phys_dev_count_term = new_phys_devs_count; 64355db71995Sopenharmony_ci inst->phys_devs_term = new_phys_devs; 64365db71995Sopenharmony_ci inst->total_gpu_count = new_phys_devs_count; 64375db71995Sopenharmony_ci } 64385db71995Sopenharmony_ci 64395db71995Sopenharmony_ci if (windows_sorted_devices_array != NULL) { 64405db71995Sopenharmony_ci for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) { 64415db71995Sopenharmony_ci if (windows_sorted_devices_array[i].device_count > 0 && windows_sorted_devices_array[i].physical_devices != NULL) { 64425db71995Sopenharmony_ci loader_instance_heap_free(inst, windows_sorted_devices_array[i].physical_devices); 64435db71995Sopenharmony_ci } 64445db71995Sopenharmony_ci } 64455db71995Sopenharmony_ci loader_instance_heap_free(inst, windows_sorted_devices_array); 64465db71995Sopenharmony_ci } 64475db71995Sopenharmony_ci 64485db71995Sopenharmony_ci return res; 64495db71995Sopenharmony_ci} 64505db71995Sopenharmony_ci 64515db71995Sopenharmony_ciVkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32_t group_count, 64525db71995Sopenharmony_ci VkPhysicalDeviceGroupProperties *groups) { 64535db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 64545db71995Sopenharmony_ci uint32_t cur_idx; 64555db71995Sopenharmony_ci uint32_t dev_idx; 64565db71995Sopenharmony_ci 64575db71995Sopenharmony_ci if (0 == group_count) { 64585db71995Sopenharmony_ci return VK_SUCCESS; 64595db71995Sopenharmony_ci } 64605db71995Sopenharmony_ci 64615db71995Sopenharmony_ci // Generate a list of all the devices and convert them to the loader ID 64625db71995Sopenharmony_ci uint32_t phys_dev_count = 0; 64635db71995Sopenharmony_ci for (cur_idx = 0; cur_idx < group_count; ++cur_idx) { 64645db71995Sopenharmony_ci phys_dev_count += groups[cur_idx].physicalDeviceCount; 64655db71995Sopenharmony_ci } 64665db71995Sopenharmony_ci VkPhysicalDevice *devices = (VkPhysicalDevice *)loader_stack_alloc(sizeof(VkPhysicalDevice) * phys_dev_count); 64675db71995Sopenharmony_ci if (NULL == devices) { 64685db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 64695db71995Sopenharmony_ci } 64705db71995Sopenharmony_ci 64715db71995Sopenharmony_ci uint32_t cur_device = 0; 64725db71995Sopenharmony_ci for (cur_idx = 0; cur_idx < group_count; ++cur_idx) { 64735db71995Sopenharmony_ci for (dev_idx = 0; dev_idx < groups[cur_idx].physicalDeviceCount; ++dev_idx) { 64745db71995Sopenharmony_ci devices[cur_device++] = groups[cur_idx].physicalDevices[dev_idx]; 64755db71995Sopenharmony_ci } 64765db71995Sopenharmony_ci } 64775db71995Sopenharmony_ci 64785db71995Sopenharmony_ci // Update the devices based on the loader physical device values. 64795db71995Sopenharmony_ci res = setup_loader_tramp_phys_devs(inst, phys_dev_count, devices); 64805db71995Sopenharmony_ci if (VK_SUCCESS != res) { 64815db71995Sopenharmony_ci return res; 64825db71995Sopenharmony_ci } 64835db71995Sopenharmony_ci 64845db71995Sopenharmony_ci // Update the devices in the group structures now 64855db71995Sopenharmony_ci cur_device = 0; 64865db71995Sopenharmony_ci for (cur_idx = 0; cur_idx < group_count; ++cur_idx) { 64875db71995Sopenharmony_ci for (dev_idx = 0; dev_idx < groups[cur_idx].physicalDeviceCount; ++dev_idx) { 64885db71995Sopenharmony_ci groups[cur_idx].physicalDevices[dev_idx] = devices[cur_device++]; 64895db71995Sopenharmony_ci } 64905db71995Sopenharmony_ci } 64915db71995Sopenharmony_ci 64925db71995Sopenharmony_ci return res; 64935db71995Sopenharmony_ci} 64945db71995Sopenharmony_ci 64955db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, 64965db71995Sopenharmony_ci VkPhysicalDevice *pPhysicalDevices) { 64975db71995Sopenharmony_ci struct loader_instance *inst = (struct loader_instance *)instance; 64985db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 64995db71995Sopenharmony_ci 65005db71995Sopenharmony_ci // Always call the setup loader terminator physical devices because they may 65015db71995Sopenharmony_ci // have changed at any point. 65025db71995Sopenharmony_ci res = setup_loader_term_phys_devs(inst); 65035db71995Sopenharmony_ci if (VK_SUCCESS != res) { 65045db71995Sopenharmony_ci goto out; 65055db71995Sopenharmony_ci } 65065db71995Sopenharmony_ci 65075db71995Sopenharmony_ci uint32_t copy_count = inst->phys_dev_count_term; 65085db71995Sopenharmony_ci if (NULL != pPhysicalDevices) { 65095db71995Sopenharmony_ci if (copy_count > *pPhysicalDeviceCount) { 65105db71995Sopenharmony_ci copy_count = *pPhysicalDeviceCount; 65115db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 65125db71995Sopenharmony_ci "terminator_EnumeratePhysicalDevices : Trimming device count from %d to %d.", inst->phys_dev_count_term, 65135db71995Sopenharmony_ci copy_count); 65145db71995Sopenharmony_ci res = VK_INCOMPLETE; 65155db71995Sopenharmony_ci } 65165db71995Sopenharmony_ci 65175db71995Sopenharmony_ci for (uint32_t i = 0; i < copy_count; i++) { 65185db71995Sopenharmony_ci pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i]; 65195db71995Sopenharmony_ci } 65205db71995Sopenharmony_ci } 65215db71995Sopenharmony_ci 65225db71995Sopenharmony_ci *pPhysicalDeviceCount = copy_count; 65235db71995Sopenharmony_ci 65245db71995Sopenharmony_ciout: 65255db71995Sopenharmony_ci 65265db71995Sopenharmony_ci return res; 65275db71995Sopenharmony_ci} 65285db71995Sopenharmony_ci 65295db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, 65305db71995Sopenharmony_ci const char *pLayerName, uint32_t *pPropertyCount, 65315db71995Sopenharmony_ci VkExtensionProperties *pProperties) { 65325db71995Sopenharmony_ci if (NULL == pPropertyCount) { 65335db71995Sopenharmony_ci return VK_INCOMPLETE; 65345db71995Sopenharmony_ci } 65355db71995Sopenharmony_ci 65365db71995Sopenharmony_ci struct loader_physical_device_term *phys_dev_term; 65375db71995Sopenharmony_ci 65385db71995Sopenharmony_ci // Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected 65395db71995Sopenharmony_ci // type for VkPhysicalDevice. 65405db71995Sopenharmony_ci phys_dev_term = (struct loader_physical_device_term *)physicalDevice; 65415db71995Sopenharmony_ci 65425db71995Sopenharmony_ci // if we got here with a non-empty pLayerName, look up the extensions 65435db71995Sopenharmony_ci // from the json 65445db71995Sopenharmony_ci if (pLayerName != NULL && strlen(pLayerName) > 0) { 65455db71995Sopenharmony_ci uint32_t count; 65465db71995Sopenharmony_ci uint32_t copy_size; 65475db71995Sopenharmony_ci const struct loader_instance *inst = phys_dev_term->this_icd_term->this_instance; 65485db71995Sopenharmony_ci struct loader_device_extension_list *dev_ext_list = NULL; 65495db71995Sopenharmony_ci struct loader_device_extension_list local_ext_list; 65505db71995Sopenharmony_ci memset(&local_ext_list, 0, sizeof(local_ext_list)); 65515db71995Sopenharmony_ci if (vk_string_validate(MaxLoaderStringLength, pLayerName) == VK_STRING_ERROR_NONE) { 65525db71995Sopenharmony_ci for (uint32_t i = 0; i < inst->instance_layer_list.count; i++) { 65535db71995Sopenharmony_ci struct loader_layer_properties *props = &inst->instance_layer_list.list[i]; 65545db71995Sopenharmony_ci if (strcmp(props->info.layerName, pLayerName) == 0) { 65555db71995Sopenharmony_ci dev_ext_list = &props->device_extension_list; 65565db71995Sopenharmony_ci } 65575db71995Sopenharmony_ci } 65585db71995Sopenharmony_ci 65595db71995Sopenharmony_ci count = (dev_ext_list == NULL) ? 0 : dev_ext_list->count; 65605db71995Sopenharmony_ci if (pProperties == NULL) { 65615db71995Sopenharmony_ci *pPropertyCount = count; 65625db71995Sopenharmony_ci loader_destroy_generic_list(inst, (struct loader_generic_list *)&local_ext_list); 65635db71995Sopenharmony_ci return VK_SUCCESS; 65645db71995Sopenharmony_ci } 65655db71995Sopenharmony_ci 65665db71995Sopenharmony_ci copy_size = *pPropertyCount < count ? *pPropertyCount : count; 65675db71995Sopenharmony_ci for (uint32_t i = 0; i < copy_size; i++) { 65685db71995Sopenharmony_ci memcpy(&pProperties[i], &dev_ext_list->list[i].props, sizeof(VkExtensionProperties)); 65695db71995Sopenharmony_ci } 65705db71995Sopenharmony_ci *pPropertyCount = copy_size; 65715db71995Sopenharmony_ci 65725db71995Sopenharmony_ci loader_destroy_generic_list(inst, (struct loader_generic_list *)&local_ext_list); 65735db71995Sopenharmony_ci if (copy_size < count) { 65745db71995Sopenharmony_ci return VK_INCOMPLETE; 65755db71995Sopenharmony_ci } 65765db71995Sopenharmony_ci } else { 65775db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 65785db71995Sopenharmony_ci "vkEnumerateDeviceExtensionProperties: pLayerName is too long or is badly formed"); 65795db71995Sopenharmony_ci return VK_ERROR_EXTENSION_NOT_PRESENT; 65805db71995Sopenharmony_ci } 65815db71995Sopenharmony_ci 65825db71995Sopenharmony_ci return VK_SUCCESS; 65835db71995Sopenharmony_ci } 65845db71995Sopenharmony_ci 65855db71995Sopenharmony_ci // user is querying driver extensions and has supplied their own storage - just fill it out 65865db71995Sopenharmony_ci else if (pProperties) { 65875db71995Sopenharmony_ci struct loader_icd_term *icd_term = phys_dev_term->this_icd_term; 65885db71995Sopenharmony_ci uint32_t written_count = *pPropertyCount; 65895db71995Sopenharmony_ci VkResult res = 65905db71995Sopenharmony_ci icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &written_count, pProperties); 65915db71995Sopenharmony_ci if (res != VK_SUCCESS) { 65925db71995Sopenharmony_ci return res; 65935db71995Sopenharmony_ci } 65945db71995Sopenharmony_ci 65955db71995Sopenharmony_ci // Iterate over active layers, if they are an implicit layer, add their device extensions 65965db71995Sopenharmony_ci // After calling into the driver, written_count contains the amount of device extensions written. We can therefore write 65975db71995Sopenharmony_ci // layer extensions starting at that point in pProperties 65985db71995Sopenharmony_ci for (uint32_t i = 0; i < icd_term->this_instance->expanded_activated_layer_list.count; i++) { 65995db71995Sopenharmony_ci struct loader_layer_properties *layer_props = icd_term->this_instance->expanded_activated_layer_list.list[i]; 66005db71995Sopenharmony_ci if (0 == (layer_props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) { 66015db71995Sopenharmony_ci struct loader_device_extension_list *layer_ext_list = &layer_props->device_extension_list; 66025db71995Sopenharmony_ci for (uint32_t j = 0; j < layer_ext_list->count; j++) { 66035db71995Sopenharmony_ci struct loader_dev_ext_props *cur_ext_props = &layer_ext_list->list[j]; 66045db71995Sopenharmony_ci // look for duplicates 66055db71995Sopenharmony_ci if (has_vk_extension_property_array(&cur_ext_props->props, written_count, pProperties)) { 66065db71995Sopenharmony_ci continue; 66075db71995Sopenharmony_ci } 66085db71995Sopenharmony_ci 66095db71995Sopenharmony_ci if (*pPropertyCount <= written_count) { 66105db71995Sopenharmony_ci return VK_INCOMPLETE; 66115db71995Sopenharmony_ci } 66125db71995Sopenharmony_ci 66135db71995Sopenharmony_ci memcpy(&pProperties[written_count], &cur_ext_props->props, sizeof(VkExtensionProperties)); 66145db71995Sopenharmony_ci written_count++; 66155db71995Sopenharmony_ci } 66165db71995Sopenharmony_ci } 66175db71995Sopenharmony_ci } 66185db71995Sopenharmony_ci // Make sure we update the pPropertyCount with the how many were written 66195db71995Sopenharmony_ci *pPropertyCount = written_count; 66205db71995Sopenharmony_ci return res; 66215db71995Sopenharmony_ci } 66225db71995Sopenharmony_ci // Use `goto out;` for rest of this function 66235db71995Sopenharmony_ci 66245db71995Sopenharmony_ci // This case is during the call down the instance chain with pLayerName == NULL and pProperties == NULL 66255db71995Sopenharmony_ci struct loader_icd_term *icd_term = phys_dev_term->this_icd_term; 66265db71995Sopenharmony_ci struct loader_extension_list all_exts = {0}; 66275db71995Sopenharmony_ci VkResult res; 66285db71995Sopenharmony_ci 66295db71995Sopenharmony_ci // We need to find the count without duplicates. This requires querying the driver for the names of the extensions. 66305db71995Sopenharmony_ci res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &all_exts.count, NULL); 66315db71995Sopenharmony_ci if (res != VK_SUCCESS) { 66325db71995Sopenharmony_ci goto out; 66335db71995Sopenharmony_ci } 66345db71995Sopenharmony_ci // Then allocate memory to store the physical device extension list + the extensions layers provide 66355db71995Sopenharmony_ci // all_exts.count currently is the number of driver extensions 66365db71995Sopenharmony_ci all_exts.capacity = sizeof(VkExtensionProperties) * (all_exts.count + 20); 66375db71995Sopenharmony_ci all_exts.list = loader_instance_heap_alloc(icd_term->this_instance, all_exts.capacity, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 66385db71995Sopenharmony_ci if (NULL == all_exts.list) { 66395db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 66405db71995Sopenharmony_ci goto out; 66415db71995Sopenharmony_ci } 66425db71995Sopenharmony_ci 66435db71995Sopenharmony_ci // Get the available device extensions and put them in all_exts.list 66445db71995Sopenharmony_ci res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &all_exts.count, all_exts.list); 66455db71995Sopenharmony_ci if (res != VK_SUCCESS) { 66465db71995Sopenharmony_ci goto out; 66475db71995Sopenharmony_ci } 66485db71995Sopenharmony_ci 66495db71995Sopenharmony_ci // Iterate over active layers, if they are an implicit layer, add their device extensions to all_exts.list 66505db71995Sopenharmony_ci for (uint32_t i = 0; i < icd_term->this_instance->expanded_activated_layer_list.count; i++) { 66515db71995Sopenharmony_ci struct loader_layer_properties *layer_props = icd_term->this_instance->expanded_activated_layer_list.list[i]; 66525db71995Sopenharmony_ci if (0 == (layer_props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) { 66535db71995Sopenharmony_ci struct loader_device_extension_list *layer_ext_list = &layer_props->device_extension_list; 66545db71995Sopenharmony_ci for (uint32_t j = 0; j < layer_ext_list->count; j++) { 66555db71995Sopenharmony_ci res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1, &layer_ext_list->list[j].props); 66565db71995Sopenharmony_ci if (res != VK_SUCCESS) { 66575db71995Sopenharmony_ci goto out; 66585db71995Sopenharmony_ci } 66595db71995Sopenharmony_ci } 66605db71995Sopenharmony_ci } 66615db71995Sopenharmony_ci } 66625db71995Sopenharmony_ci 66635db71995Sopenharmony_ci // Write out the final de-duplicated count to pPropertyCount 66645db71995Sopenharmony_ci *pPropertyCount = all_exts.count; 66655db71995Sopenharmony_ci res = VK_SUCCESS; 66665db71995Sopenharmony_ci 66675db71995Sopenharmony_ciout: 66685db71995Sopenharmony_ci 66695db71995Sopenharmony_ci loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts); 66705db71995Sopenharmony_ci return res; 66715db71995Sopenharmony_ci} 66725db71995Sopenharmony_ci 66735db71995Sopenharmony_ciVkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) { 66745db71995Sopenharmony_ci VkStringErrorFlags result = VK_STRING_ERROR_NONE; 66755db71995Sopenharmony_ci int num_char_bytes = 0; 66765db71995Sopenharmony_ci int i, j; 66775db71995Sopenharmony_ci 66785db71995Sopenharmony_ci if (utf8 == NULL) { 66795db71995Sopenharmony_ci return VK_STRING_ERROR_NULL_PTR; 66805db71995Sopenharmony_ci } 66815db71995Sopenharmony_ci 66825db71995Sopenharmony_ci for (i = 0; i <= max_length; i++) { 66835db71995Sopenharmony_ci if (utf8[i] == 0) { 66845db71995Sopenharmony_ci break; 66855db71995Sopenharmony_ci } else if (i == max_length) { 66865db71995Sopenharmony_ci result |= VK_STRING_ERROR_LENGTH; 66875db71995Sopenharmony_ci break; 66885db71995Sopenharmony_ci } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) { 66895db71995Sopenharmony_ci num_char_bytes = 0; 66905db71995Sopenharmony_ci } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) { 66915db71995Sopenharmony_ci num_char_bytes = 1; 66925db71995Sopenharmony_ci } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) { 66935db71995Sopenharmony_ci num_char_bytes = 2; 66945db71995Sopenharmony_ci } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) { 66955db71995Sopenharmony_ci num_char_bytes = 3; 66965db71995Sopenharmony_ci } else { 66975db71995Sopenharmony_ci result = VK_STRING_ERROR_BAD_DATA; 66985db71995Sopenharmony_ci } 66995db71995Sopenharmony_ci 67005db71995Sopenharmony_ci // Validate the following num_char_bytes of data 67015db71995Sopenharmony_ci for (j = 0; (j < num_char_bytes) && (i < max_length); j++) { 67025db71995Sopenharmony_ci if (++i == max_length) { 67035db71995Sopenharmony_ci result |= VK_STRING_ERROR_LENGTH; 67045db71995Sopenharmony_ci break; 67055db71995Sopenharmony_ci } 67065db71995Sopenharmony_ci if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) { 67075db71995Sopenharmony_ci result |= VK_STRING_ERROR_BAD_DATA; 67085db71995Sopenharmony_ci } 67095db71995Sopenharmony_ci } 67105db71995Sopenharmony_ci } 67115db71995Sopenharmony_ci return result; 67125db71995Sopenharmony_ci} 67135db71995Sopenharmony_ci 67145db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceVersion(const VkEnumerateInstanceVersionChain *chain, 67155db71995Sopenharmony_ci uint32_t *pApiVersion) { 67165db71995Sopenharmony_ci (void)chain; 67175db71995Sopenharmony_ci // NOTE: The Vulkan WG doesn't want us checking pApiVersion for NULL, but instead 67185db71995Sopenharmony_ci // prefers us crashing. 67195db71995Sopenharmony_ci *pApiVersion = VK_HEADER_VERSION_COMPLETE; 67205db71995Sopenharmony_ci return VK_SUCCESS; 67215db71995Sopenharmony_ci} 67225db71995Sopenharmony_ci 67235db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL 67245db71995Sopenharmony_citerminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName, 67255db71995Sopenharmony_ci uint32_t *pPropertyCount, VkExtensionProperties *pProperties) { 67265db71995Sopenharmony_ci (void)chain; 67275db71995Sopenharmony_ci struct loader_extension_list *global_ext_list = NULL; 67285db71995Sopenharmony_ci struct loader_layer_list instance_layers; 67295db71995Sopenharmony_ci struct loader_extension_list local_ext_list; 67305db71995Sopenharmony_ci struct loader_icd_tramp_list icd_tramp_list; 67315db71995Sopenharmony_ci uint32_t copy_size; 67325db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 67335db71995Sopenharmony_ci struct loader_envvar_all_filters layer_filters = {0}; 67345db71995Sopenharmony_ci 67355db71995Sopenharmony_ci memset(&local_ext_list, 0, sizeof(local_ext_list)); 67365db71995Sopenharmony_ci memset(&instance_layers, 0, sizeof(instance_layers)); 67375db71995Sopenharmony_ci memset(&icd_tramp_list, 0, sizeof(icd_tramp_list)); 67385db71995Sopenharmony_ci 67395db71995Sopenharmony_ci res = parse_layer_environment_var_filters(NULL, &layer_filters); 67405db71995Sopenharmony_ci if (VK_SUCCESS != res) { 67415db71995Sopenharmony_ci goto out; 67425db71995Sopenharmony_ci } 67435db71995Sopenharmony_ci 67445db71995Sopenharmony_ci // Get layer libraries if needed 67455db71995Sopenharmony_ci if (pLayerName && strlen(pLayerName) != 0) { 67465db71995Sopenharmony_ci if (vk_string_validate(MaxLoaderStringLength, pLayerName) != VK_STRING_ERROR_NONE) { 67475db71995Sopenharmony_ci assert(VK_FALSE && "vkEnumerateInstanceExtensionProperties: pLayerName is too long or is badly formed"); 67485db71995Sopenharmony_ci res = VK_ERROR_EXTENSION_NOT_PRESENT; 67495db71995Sopenharmony_ci goto out; 67505db71995Sopenharmony_ci } 67515db71995Sopenharmony_ci 67525db71995Sopenharmony_ci res = loader_scan_for_layers(NULL, &instance_layers, &layer_filters); 67535db71995Sopenharmony_ci if (VK_SUCCESS != res) { 67545db71995Sopenharmony_ci goto out; 67555db71995Sopenharmony_ci } 67565db71995Sopenharmony_ci for (uint32_t i = 0; i < instance_layers.count; i++) { 67575db71995Sopenharmony_ci struct loader_layer_properties *props = &instance_layers.list[i]; 67585db71995Sopenharmony_ci if (strcmp(props->info.layerName, pLayerName) == 0) { 67595db71995Sopenharmony_ci global_ext_list = &props->instance_extension_list; 67605db71995Sopenharmony_ci break; 67615db71995Sopenharmony_ci } 67625db71995Sopenharmony_ci } 67635db71995Sopenharmony_ci } else { 67645db71995Sopenharmony_ci // Preload ICD libraries so subsequent calls to EnumerateInstanceExtensionProperties don't have to load them 67655db71995Sopenharmony_ci loader_preload_icds(); 67665db71995Sopenharmony_ci 67675db71995Sopenharmony_ci // Scan/discover all ICD libraries 67685db71995Sopenharmony_ci res = loader_icd_scan(NULL, &icd_tramp_list, NULL, NULL); 67695db71995Sopenharmony_ci // EnumerateInstanceExtensionProperties can't return anything other than OOM or VK_ERROR_LAYER_NOT_PRESENT 67705db71995Sopenharmony_ci if ((VK_SUCCESS != res && icd_tramp_list.count > 0) || res == VK_ERROR_OUT_OF_HOST_MEMORY) { 67715db71995Sopenharmony_ci goto out; 67725db71995Sopenharmony_ci } 67735db71995Sopenharmony_ci // Get extensions from all ICD's, merge so no duplicates 67745db71995Sopenharmony_ci res = loader_get_icd_loader_instance_extensions(NULL, &icd_tramp_list, &local_ext_list); 67755db71995Sopenharmony_ci if (VK_SUCCESS != res) { 67765db71995Sopenharmony_ci goto out; 67775db71995Sopenharmony_ci } 67785db71995Sopenharmony_ci loader_scanned_icd_clear(NULL, &icd_tramp_list); 67795db71995Sopenharmony_ci 67805db71995Sopenharmony_ci // Append enabled implicit layers. 67815db71995Sopenharmony_ci res = loader_scan_for_implicit_layers(NULL, &instance_layers, &layer_filters); 67825db71995Sopenharmony_ci if (VK_SUCCESS != res) { 67835db71995Sopenharmony_ci goto out; 67845db71995Sopenharmony_ci } 67855db71995Sopenharmony_ci for (uint32_t i = 0; i < instance_layers.count; i++) { 67865db71995Sopenharmony_ci struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list; 67875db71995Sopenharmony_ci loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list); 67885db71995Sopenharmony_ci } 67895db71995Sopenharmony_ci 67905db71995Sopenharmony_ci global_ext_list = &local_ext_list; 67915db71995Sopenharmony_ci } 67925db71995Sopenharmony_ci 67935db71995Sopenharmony_ci if (global_ext_list == NULL) { 67945db71995Sopenharmony_ci res = VK_ERROR_LAYER_NOT_PRESENT; 67955db71995Sopenharmony_ci goto out; 67965db71995Sopenharmony_ci } 67975db71995Sopenharmony_ci 67985db71995Sopenharmony_ci if (pProperties == NULL) { 67995db71995Sopenharmony_ci *pPropertyCount = global_ext_list->count; 68005db71995Sopenharmony_ci goto out; 68015db71995Sopenharmony_ci } 68025db71995Sopenharmony_ci 68035db71995Sopenharmony_ci copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count; 68045db71995Sopenharmony_ci for (uint32_t i = 0; i < copy_size; i++) { 68055db71995Sopenharmony_ci memcpy(&pProperties[i], &global_ext_list->list[i], sizeof(VkExtensionProperties)); 68065db71995Sopenharmony_ci } 68075db71995Sopenharmony_ci *pPropertyCount = copy_size; 68085db71995Sopenharmony_ci 68095db71995Sopenharmony_ci if (copy_size < global_ext_list->count) { 68105db71995Sopenharmony_ci res = VK_INCOMPLETE; 68115db71995Sopenharmony_ci goto out; 68125db71995Sopenharmony_ci } 68135db71995Sopenharmony_ci 68145db71995Sopenharmony_ciout: 68155db71995Sopenharmony_ci loader_destroy_generic_list(NULL, (struct loader_generic_list *)&icd_tramp_list); 68165db71995Sopenharmony_ci loader_destroy_generic_list(NULL, (struct loader_generic_list *)&local_ext_list); 68175db71995Sopenharmony_ci loader_delete_layer_list_and_properties(NULL, &instance_layers); 68185db71995Sopenharmony_ci return res; 68195db71995Sopenharmony_ci} 68205db71995Sopenharmony_ci 68215db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain, 68225db71995Sopenharmony_ci uint32_t *pPropertyCount, 68235db71995Sopenharmony_ci VkLayerProperties *pProperties) { 68245db71995Sopenharmony_ci (void)chain; 68255db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 68265db71995Sopenharmony_ci struct loader_layer_list instance_layer_list; 68275db71995Sopenharmony_ci struct loader_envvar_all_filters layer_filters = {0}; 68285db71995Sopenharmony_ci 68295db71995Sopenharmony_ci LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize); 68305db71995Sopenharmony_ci 68315db71995Sopenharmony_ci uint32_t copy_size; 68325db71995Sopenharmony_ci 68335db71995Sopenharmony_ci result = parse_layer_environment_var_filters(NULL, &layer_filters); 68345db71995Sopenharmony_ci if (VK_SUCCESS != result) { 68355db71995Sopenharmony_ci goto out; 68365db71995Sopenharmony_ci } 68375db71995Sopenharmony_ci 68385db71995Sopenharmony_ci // Get layer libraries 68395db71995Sopenharmony_ci memset(&instance_layer_list, 0, sizeof(instance_layer_list)); 68405db71995Sopenharmony_ci result = loader_scan_for_layers(NULL, &instance_layer_list, &layer_filters); 68415db71995Sopenharmony_ci if (VK_SUCCESS != result) { 68425db71995Sopenharmony_ci goto out; 68435db71995Sopenharmony_ci } 68445db71995Sopenharmony_ci 68455db71995Sopenharmony_ci uint32_t active_layer_count = 0; 68465db71995Sopenharmony_ci for (uint32_t i = 0; i < instance_layer_list.count; i++) { 68475db71995Sopenharmony_ci if (instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON || 68485db71995Sopenharmony_ci instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_DEFAULT) { 68495db71995Sopenharmony_ci active_layer_count++; 68505db71995Sopenharmony_ci } 68515db71995Sopenharmony_ci } 68525db71995Sopenharmony_ci 68535db71995Sopenharmony_ci if (pProperties == NULL) { 68545db71995Sopenharmony_ci *pPropertyCount = active_layer_count; 68555db71995Sopenharmony_ci goto out; 68565db71995Sopenharmony_ci } 68575db71995Sopenharmony_ci 68585db71995Sopenharmony_ci copy_size = (*pPropertyCount < active_layer_count) ? *pPropertyCount : active_layer_count; 68595db71995Sopenharmony_ci uint32_t output_properties_index = 0; 68605db71995Sopenharmony_ci for (uint32_t i = 0; i < copy_size; i++) { 68615db71995Sopenharmony_ci if (instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON || 68625db71995Sopenharmony_ci instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_DEFAULT) { 68635db71995Sopenharmony_ci memcpy(&pProperties[output_properties_index], &instance_layer_list.list[i].info, sizeof(VkLayerProperties)); 68645db71995Sopenharmony_ci output_properties_index++; 68655db71995Sopenharmony_ci } 68665db71995Sopenharmony_ci } 68675db71995Sopenharmony_ci 68685db71995Sopenharmony_ci *pPropertyCount = copy_size; 68695db71995Sopenharmony_ci 68705db71995Sopenharmony_ci if (copy_size < instance_layer_list.count) { 68715db71995Sopenharmony_ci result = VK_INCOMPLETE; 68725db71995Sopenharmony_ci goto out; 68735db71995Sopenharmony_ci } 68745db71995Sopenharmony_ci 68755db71995Sopenharmony_ciout: 68765db71995Sopenharmony_ci 68775db71995Sopenharmony_ci loader_delete_layer_list_and_properties(NULL, &instance_layer_list); 68785db71995Sopenharmony_ci return result; 68795db71995Sopenharmony_ci} 68805db71995Sopenharmony_ci 68815db71995Sopenharmony_ci// ---- Vulkan Core 1.1 terminators 68825db71995Sopenharmony_ci 68835db71995Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups( 68845db71995Sopenharmony_ci VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) { 68855db71995Sopenharmony_ci struct loader_instance *inst = (struct loader_instance *)instance; 68865db71995Sopenharmony_ci 68875db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 68885db71995Sopenharmony_ci struct loader_icd_term *icd_term; 68895db71995Sopenharmony_ci uint32_t total_count = 0; 68905db71995Sopenharmony_ci uint32_t cur_icd_group_count = 0; 68915db71995Sopenharmony_ci VkPhysicalDeviceGroupProperties **new_phys_dev_groups = NULL; 68925db71995Sopenharmony_ci struct loader_physical_device_group_term *local_phys_dev_groups = NULL; 68935db71995Sopenharmony_ci PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL; 68945db71995Sopenharmony_ci struct loader_icd_physical_devices *sorted_phys_dev_array = NULL; 68955db71995Sopenharmony_ci uint32_t sorted_count = 0; 68965db71995Sopenharmony_ci 68975db71995Sopenharmony_ci // For each ICD, query the number of physical device groups, and then get an 68985db71995Sopenharmony_ci // internal value for those physical devices. 68995db71995Sopenharmony_ci icd_term = inst->icd_terms; 69005db71995Sopenharmony_ci for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) { 69015db71995Sopenharmony_ci cur_icd_group_count = 0; 69025db71995Sopenharmony_ci 69035db71995Sopenharmony_ci // Get the function pointer to use to call into the ICD. This could be the core or KHR version 69045db71995Sopenharmony_ci if (inst->enabled_known_extensions.khr_device_group_creation) { 69055db71995Sopenharmony_ci fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR; 69065db71995Sopenharmony_ci } else { 69075db71995Sopenharmony_ci fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups; 69085db71995Sopenharmony_ci } 69095db71995Sopenharmony_ci 69105db71995Sopenharmony_ci if (NULL == fpEnumeratePhysicalDeviceGroups) { 69115db71995Sopenharmony_ci // Treat each ICD's GPU as it's own group if the extension isn't supported 69125db71995Sopenharmony_ci res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &cur_icd_group_count, NULL); 69135db71995Sopenharmony_ci if (res != VK_SUCCESS) { 69145db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 69155db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of \'EnumeratePhysicalDevices\' " 69165db71995Sopenharmony_ci "to ICD %d to get plain phys dev count.", 69175db71995Sopenharmony_ci icd_idx); 69185db71995Sopenharmony_ci continue; 69195db71995Sopenharmony_ci } 69205db71995Sopenharmony_ci } else { 69215db71995Sopenharmony_ci // Query the actual group info 69225db71995Sopenharmony_ci res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &cur_icd_group_count, NULL); 69235db71995Sopenharmony_ci if (res != VK_SUCCESS) { 69245db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 69255db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " 69265db71995Sopenharmony_ci "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get count.", 69275db71995Sopenharmony_ci icd_idx); 69285db71995Sopenharmony_ci continue; 69295db71995Sopenharmony_ci } 69305db71995Sopenharmony_ci } 69315db71995Sopenharmony_ci total_count += cur_icd_group_count; 69325db71995Sopenharmony_ci } 69335db71995Sopenharmony_ci 69345db71995Sopenharmony_ci // If GPUs not sorted yet, look through them and generate list of all available GPUs 69355db71995Sopenharmony_ci if (0 == total_count || 0 == inst->total_gpu_count) { 69365db71995Sopenharmony_ci res = setup_loader_term_phys_devs(inst); 69375db71995Sopenharmony_ci if (VK_SUCCESS != res) { 69385db71995Sopenharmony_ci goto out; 69395db71995Sopenharmony_ci } 69405db71995Sopenharmony_ci } 69415db71995Sopenharmony_ci 69425db71995Sopenharmony_ci if (NULL != pPhysicalDeviceGroupProperties) { 69435db71995Sopenharmony_ci // Create an array for the new physical device groups, which will be stored 69445db71995Sopenharmony_ci // in the instance for the Terminator code. 69455db71995Sopenharmony_ci new_phys_dev_groups = (VkPhysicalDeviceGroupProperties **)loader_instance_heap_calloc( 69465db71995Sopenharmony_ci inst, total_count * sizeof(VkPhysicalDeviceGroupProperties *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 69475db71995Sopenharmony_ci if (NULL == new_phys_dev_groups) { 69485db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 69495db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate new physical device group array of size %d", 69505db71995Sopenharmony_ci total_count); 69515db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 69525db71995Sopenharmony_ci goto out; 69535db71995Sopenharmony_ci } 69545db71995Sopenharmony_ci 69555db71995Sopenharmony_ci // Create a temporary array (on the stack) to keep track of the 69565db71995Sopenharmony_ci // returned VkPhysicalDevice values. 69575db71995Sopenharmony_ci local_phys_dev_groups = loader_stack_alloc(sizeof(struct loader_physical_device_group_term) * total_count); 69585db71995Sopenharmony_ci // Initialize the memory to something valid 69595db71995Sopenharmony_ci memset(local_phys_dev_groups, 0, sizeof(struct loader_physical_device_group_term) * total_count); 69605db71995Sopenharmony_ci 69615db71995Sopenharmony_ci#if defined(_WIN32) 69625db71995Sopenharmony_ci // Get the physical devices supported by platform sorting mechanism into a separate list 69635db71995Sopenharmony_ci res = windows_read_sorted_physical_devices(inst, &sorted_count, &sorted_phys_dev_array); 69645db71995Sopenharmony_ci if (VK_SUCCESS != res) { 69655db71995Sopenharmony_ci goto out; 69665db71995Sopenharmony_ci } 69675db71995Sopenharmony_ci#endif 69685db71995Sopenharmony_ci 69695db71995Sopenharmony_ci cur_icd_group_count = 0; 69705db71995Sopenharmony_ci icd_term = inst->icd_terms; 69715db71995Sopenharmony_ci for (uint8_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) { 69725db71995Sopenharmony_ci uint32_t count_this_time = total_count - cur_icd_group_count; 69735db71995Sopenharmony_ci 69745db71995Sopenharmony_ci // Get the function pointer to use to call into the ICD. This could be the core or KHR version 69755db71995Sopenharmony_ci if (inst->enabled_known_extensions.khr_device_group_creation) { 69765db71995Sopenharmony_ci fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR; 69775db71995Sopenharmony_ci } else { 69785db71995Sopenharmony_ci fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups; 69795db71995Sopenharmony_ci } 69805db71995Sopenharmony_ci 69815db71995Sopenharmony_ci if (NULL == fpEnumeratePhysicalDeviceGroups) { 69825db71995Sopenharmony_ci icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, NULL); 69835db71995Sopenharmony_ci 69845db71995Sopenharmony_ci VkPhysicalDevice *phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time); 69855db71995Sopenharmony_ci if (NULL == phys_dev_array) { 69865db71995Sopenharmony_ci loader_log( 69875db71995Sopenharmony_ci inst, VULKAN_LOADER_ERROR_BIT, 0, 69885db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate local physical device array of size %d", 69895db71995Sopenharmony_ci count_this_time); 69905db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 69915db71995Sopenharmony_ci goto out; 69925db71995Sopenharmony_ci } 69935db71995Sopenharmony_ci 69945db71995Sopenharmony_ci res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array); 69955db71995Sopenharmony_ci if (res != VK_SUCCESS) { 69965db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 69975db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " 69985db71995Sopenharmony_ci "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.", 69995db71995Sopenharmony_ci icd_idx); 70005db71995Sopenharmony_ci goto out; 70015db71995Sopenharmony_ci } 70025db71995Sopenharmony_ci 70035db71995Sopenharmony_ci // Add each GPU as it's own group 70045db71995Sopenharmony_ci for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) { 70055db71995Sopenharmony_ci uint32_t cur_index = indiv_gpu + cur_icd_group_count; 70065db71995Sopenharmony_ci local_phys_dev_groups[cur_index].this_icd_term = icd_term; 70075db71995Sopenharmony_ci local_phys_dev_groups[cur_index].icd_index = icd_idx; 70085db71995Sopenharmony_ci local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = 1; 70095db71995Sopenharmony_ci local_phys_dev_groups[cur_index].group_props.physicalDevices[0] = phys_dev_array[indiv_gpu]; 70105db71995Sopenharmony_ci } 70115db71995Sopenharmony_ci 70125db71995Sopenharmony_ci } else { 70135db71995Sopenharmony_ci res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, NULL); 70145db71995Sopenharmony_ci if (res != VK_SUCCESS) { 70155db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 70165db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " 70175db71995Sopenharmony_ci "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get group count.", 70185db71995Sopenharmony_ci icd_idx); 70195db71995Sopenharmony_ci goto out; 70205db71995Sopenharmony_ci } 70215db71995Sopenharmony_ci if (cur_icd_group_count + count_this_time < *pPhysicalDeviceGroupCount) { 70225db71995Sopenharmony_ci // The total amount is still less than the amount of physical device group data passed in 70235db71995Sopenharmony_ci // by the callee. Therefore, we don't have to allocate any temporary structures and we 70245db71995Sopenharmony_ci // can just use the data that was passed in. 70255db71995Sopenharmony_ci res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, 70265db71995Sopenharmony_ci &pPhysicalDeviceGroupProperties[cur_icd_group_count]); 70275db71995Sopenharmony_ci if (res != VK_SUCCESS) { 70285db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 70295db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " 70305db71995Sopenharmony_ci "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get group information.", 70315db71995Sopenharmony_ci icd_idx); 70325db71995Sopenharmony_ci goto out; 70335db71995Sopenharmony_ci } 70345db71995Sopenharmony_ci for (uint32_t group = 0; group < count_this_time; ++group) { 70355db71995Sopenharmony_ci uint32_t cur_index = group + cur_icd_group_count; 70365db71995Sopenharmony_ci local_phys_dev_groups[cur_index].group_props = pPhysicalDeviceGroupProperties[cur_index]; 70375db71995Sopenharmony_ci local_phys_dev_groups[cur_index].this_icd_term = icd_term; 70385db71995Sopenharmony_ci local_phys_dev_groups[cur_index].icd_index = icd_idx; 70395db71995Sopenharmony_ci } 70405db71995Sopenharmony_ci } else { 70415db71995Sopenharmony_ci // There's not enough space in the callee's allocated pPhysicalDeviceGroupProperties structs, 70425db71995Sopenharmony_ci // so we have to allocate temporary versions to collect all the data. However, we need to make 70435db71995Sopenharmony_ci // sure that at least the ones we do query utilize any pNext data in the callee's version. 70445db71995Sopenharmony_ci VkPhysicalDeviceGroupProperties *tmp_group_props = 70455db71995Sopenharmony_ci loader_stack_alloc(count_this_time * sizeof(VkPhysicalDeviceGroupProperties)); 70465db71995Sopenharmony_ci for (uint32_t group = 0; group < count_this_time; group++) { 70475db71995Sopenharmony_ci tmp_group_props[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; 70485db71995Sopenharmony_ci uint32_t cur_index = group + cur_icd_group_count; 70495db71995Sopenharmony_ci if (*pPhysicalDeviceGroupCount > cur_index) { 70505db71995Sopenharmony_ci tmp_group_props[group].pNext = pPhysicalDeviceGroupProperties[cur_index].pNext; 70515db71995Sopenharmony_ci } else { 70525db71995Sopenharmony_ci tmp_group_props[group].pNext = NULL; 70535db71995Sopenharmony_ci } 70545db71995Sopenharmony_ci tmp_group_props[group].subsetAllocation = false; 70555db71995Sopenharmony_ci } 70565db71995Sopenharmony_ci 70575db71995Sopenharmony_ci res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, tmp_group_props); 70585db71995Sopenharmony_ci if (res != VK_SUCCESS) { 70595db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 70605db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " 70615db71995Sopenharmony_ci "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get group information for temp data.", 70625db71995Sopenharmony_ci icd_idx); 70635db71995Sopenharmony_ci goto out; 70645db71995Sopenharmony_ci } 70655db71995Sopenharmony_ci for (uint32_t group = 0; group < count_this_time; ++group) { 70665db71995Sopenharmony_ci uint32_t cur_index = group + cur_icd_group_count; 70675db71995Sopenharmony_ci local_phys_dev_groups[cur_index].group_props = tmp_group_props[group]; 70685db71995Sopenharmony_ci local_phys_dev_groups[cur_index].this_icd_term = icd_term; 70695db71995Sopenharmony_ci local_phys_dev_groups[cur_index].icd_index = icd_idx; 70705db71995Sopenharmony_ci } 70715db71995Sopenharmony_ci } 70725db71995Sopenharmony_ci if (VK_SUCCESS != res) { 70735db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 70745db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed during dispatch call of " 70755db71995Sopenharmony_ci "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get content.", 70765db71995Sopenharmony_ci icd_idx); 70775db71995Sopenharmony_ci goto out; 70785db71995Sopenharmony_ci } 70795db71995Sopenharmony_ci } 70805db71995Sopenharmony_ci 70815db71995Sopenharmony_ci cur_icd_group_count += count_this_time; 70825db71995Sopenharmony_ci } 70835db71995Sopenharmony_ci 70845db71995Sopenharmony_ci#if defined(LOADER_ENABLE_LINUX_SORT) 70855db71995Sopenharmony_ci if (is_linux_sort_enabled(inst)) { 70865db71995Sopenharmony_ci // Get the physical devices supported by platform sorting mechanism into a separate list 70875db71995Sopenharmony_ci res = linux_sort_physical_device_groups(inst, total_count, local_phys_dev_groups); 70885db71995Sopenharmony_ci } 70895db71995Sopenharmony_ci#elif defined(_WIN32) 70905db71995Sopenharmony_ci // The Windows sorting information is only on physical devices. We need to take that and convert it to the group 70915db71995Sopenharmony_ci // information if it's present. 70925db71995Sopenharmony_ci if (sorted_count > 0) { 70935db71995Sopenharmony_ci res = 70945db71995Sopenharmony_ci windows_sort_physical_device_groups(inst, total_count, local_phys_dev_groups, sorted_count, sorted_phys_dev_array); 70955db71995Sopenharmony_ci } 70965db71995Sopenharmony_ci#endif // LOADER_ENABLE_LINUX_SORT 70975db71995Sopenharmony_ci 70985db71995Sopenharmony_ci // Just to be safe, make sure we successfully completed setup_loader_term_phys_devs above 70995db71995Sopenharmony_ci // before attempting to do the following. By verifying that setup_loader_term_phys_devs ran 71005db71995Sopenharmony_ci // first, it guarantees that each physical device will have a loader-specific handle. 71015db71995Sopenharmony_ci if (NULL != inst->phys_devs_term) { 71025db71995Sopenharmony_ci for (uint32_t group = 0; group < total_count; group++) { 71035db71995Sopenharmony_ci for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].group_props.physicalDeviceCount; 71045db71995Sopenharmony_ci group_gpu++) { 71055db71995Sopenharmony_ci bool found = false; 71065db71995Sopenharmony_ci for (uint32_t term_gpu = 0; term_gpu < inst->phys_dev_count_term; term_gpu++) { 71075db71995Sopenharmony_ci if (local_phys_dev_groups[group].group_props.physicalDevices[group_gpu] == 71085db71995Sopenharmony_ci inst->phys_devs_term[term_gpu]->phys_dev) { 71095db71995Sopenharmony_ci local_phys_dev_groups[group].group_props.physicalDevices[group_gpu] = 71105db71995Sopenharmony_ci (VkPhysicalDevice)inst->phys_devs_term[term_gpu]; 71115db71995Sopenharmony_ci found = true; 71125db71995Sopenharmony_ci break; 71135db71995Sopenharmony_ci } 71145db71995Sopenharmony_ci } 71155db71995Sopenharmony_ci if (!found) { 71165db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 71175db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed to find GPU %d in group %d returned by " 71185db71995Sopenharmony_ci "\'EnumeratePhysicalDeviceGroups\' in list returned by \'EnumeratePhysicalDevices\'", 71195db71995Sopenharmony_ci group_gpu, group); 71205db71995Sopenharmony_ci res = VK_ERROR_INITIALIZATION_FAILED; 71215db71995Sopenharmony_ci goto out; 71225db71995Sopenharmony_ci } 71235db71995Sopenharmony_ci } 71245db71995Sopenharmony_ci } 71255db71995Sopenharmony_ci } 71265db71995Sopenharmony_ci 71275db71995Sopenharmony_ci uint32_t idx = 0; 71285db71995Sopenharmony_ci 71295db71995Sopenharmony_ci // Copy or create everything to fill the new array of physical device groups 71305db71995Sopenharmony_ci for (uint32_t group = 0; group < total_count; group++) { 71315db71995Sopenharmony_ci // Skip groups which have been included through sorting 71325db71995Sopenharmony_ci if (local_phys_dev_groups[group].group_props.physicalDeviceCount == 0) { 71335db71995Sopenharmony_ci continue; 71345db71995Sopenharmony_ci } 71355db71995Sopenharmony_ci 71365db71995Sopenharmony_ci // Find the VkPhysicalDeviceGroupProperties object in local_phys_dev_groups 71375db71995Sopenharmony_ci VkPhysicalDeviceGroupProperties *group_properties = &local_phys_dev_groups[group].group_props; 71385db71995Sopenharmony_ci 71395db71995Sopenharmony_ci // Check if this physical device group with the same contents is already in the old buffer 71405db71995Sopenharmony_ci for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) { 71415db71995Sopenharmony_ci if (NULL != group_properties && NULL != inst->phys_dev_groups_term[old_idx] && 71425db71995Sopenharmony_ci group_properties->physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) { 71435db71995Sopenharmony_ci bool found_all_gpus = true; 71445db71995Sopenharmony_ci for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) { 71455db71995Sopenharmony_ci bool found_gpu = false; 71465db71995Sopenharmony_ci for (uint32_t new_gpu = 0; new_gpu < group_properties->physicalDeviceCount; new_gpu++) { 71475db71995Sopenharmony_ci if (group_properties->physicalDevices[new_gpu] == 71485db71995Sopenharmony_ci inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) { 71495db71995Sopenharmony_ci found_gpu = true; 71505db71995Sopenharmony_ci break; 71515db71995Sopenharmony_ci } 71525db71995Sopenharmony_ci } 71535db71995Sopenharmony_ci 71545db71995Sopenharmony_ci if (!found_gpu) { 71555db71995Sopenharmony_ci found_all_gpus = false; 71565db71995Sopenharmony_ci break; 71575db71995Sopenharmony_ci } 71585db71995Sopenharmony_ci } 71595db71995Sopenharmony_ci if (!found_all_gpus) { 71605db71995Sopenharmony_ci continue; 71615db71995Sopenharmony_ci } else { 71625db71995Sopenharmony_ci new_phys_dev_groups[idx] = inst->phys_dev_groups_term[old_idx]; 71635db71995Sopenharmony_ci break; 71645db71995Sopenharmony_ci } 71655db71995Sopenharmony_ci } 71665db71995Sopenharmony_ci } 71675db71995Sopenharmony_ci // If this physical device group isn't in the old buffer, create it 71685db71995Sopenharmony_ci if (group_properties != NULL && NULL == new_phys_dev_groups[idx]) { 71695db71995Sopenharmony_ci new_phys_dev_groups[idx] = (VkPhysicalDeviceGroupProperties *)loader_instance_heap_alloc( 71705db71995Sopenharmony_ci inst, sizeof(VkPhysicalDeviceGroupProperties), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 71715db71995Sopenharmony_ci if (NULL == new_phys_dev_groups[idx]) { 71725db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 71735db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups: Failed to allocate physical device group Terminator " 71745db71995Sopenharmony_ci "object %d", 71755db71995Sopenharmony_ci idx); 71765db71995Sopenharmony_ci total_count = idx; 71775db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 71785db71995Sopenharmony_ci goto out; 71795db71995Sopenharmony_ci } 71805db71995Sopenharmony_ci memcpy(new_phys_dev_groups[idx], group_properties, sizeof(VkPhysicalDeviceGroupProperties)); 71815db71995Sopenharmony_ci } 71825db71995Sopenharmony_ci 71835db71995Sopenharmony_ci ++idx; 71845db71995Sopenharmony_ci } 71855db71995Sopenharmony_ci } 71865db71995Sopenharmony_ci 71875db71995Sopenharmony_ciout: 71885db71995Sopenharmony_ci 71895db71995Sopenharmony_ci if (NULL != pPhysicalDeviceGroupProperties) { 71905db71995Sopenharmony_ci if (VK_SUCCESS != res) { 71915db71995Sopenharmony_ci if (NULL != new_phys_dev_groups) { 71925db71995Sopenharmony_ci // We've encountered an error, so we should free the new buffers. 71935db71995Sopenharmony_ci for (uint32_t i = 0; i < total_count; i++) { 71945db71995Sopenharmony_ci // If an OOM occurred inside the copying of the new physical device groups into the existing array will 71955db71995Sopenharmony_ci // leave some of the old physical device groups in the array which may have been copied into the new array, 71965db71995Sopenharmony_ci // leading to them being freed twice. To avoid this we just make sure to not delete physical device groups 71975db71995Sopenharmony_ci // which were copied. 71985db71995Sopenharmony_ci bool found = false; 71995db71995Sopenharmony_ci if (NULL != inst->phys_devs_term) { 72005db71995Sopenharmony_ci for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) { 72015db71995Sopenharmony_ci if (new_phys_dev_groups[i] == inst->phys_dev_groups_term[old_idx]) { 72025db71995Sopenharmony_ci found = true; 72035db71995Sopenharmony_ci break; 72045db71995Sopenharmony_ci } 72055db71995Sopenharmony_ci } 72065db71995Sopenharmony_ci } 72075db71995Sopenharmony_ci if (!found) { 72085db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_dev_groups[i]); 72095db71995Sopenharmony_ci } 72105db71995Sopenharmony_ci } 72115db71995Sopenharmony_ci loader_instance_heap_free(inst, new_phys_dev_groups); 72125db71995Sopenharmony_ci } 72135db71995Sopenharmony_ci } else { 72145db71995Sopenharmony_ci if (NULL != inst->phys_dev_groups_term) { 72155db71995Sopenharmony_ci // Free everything in the old array that was not copied into the new array 72165db71995Sopenharmony_ci // here. We can't attempt to do that before here since the previous loop 72175db71995Sopenharmony_ci // looking before the "out:" label may hit an out of memory condition resulting 72185db71995Sopenharmony_ci // in memory leaking. 72195db71995Sopenharmony_ci for (uint32_t i = 0; i < inst->phys_dev_group_count_term; i++) { 72205db71995Sopenharmony_ci bool found = false; 72215db71995Sopenharmony_ci for (uint32_t j = 0; j < total_count; j++) { 72225db71995Sopenharmony_ci if (inst->phys_dev_groups_term[i] == new_phys_dev_groups[j]) { 72235db71995Sopenharmony_ci found = true; 72245db71995Sopenharmony_ci break; 72255db71995Sopenharmony_ci } 72265db71995Sopenharmony_ci } 72275db71995Sopenharmony_ci if (!found) { 72285db71995Sopenharmony_ci loader_instance_heap_free(inst, inst->phys_dev_groups_term[i]); 72295db71995Sopenharmony_ci } 72305db71995Sopenharmony_ci } 72315db71995Sopenharmony_ci loader_instance_heap_free(inst, inst->phys_dev_groups_term); 72325db71995Sopenharmony_ci } 72335db71995Sopenharmony_ci 72345db71995Sopenharmony_ci // Swap in the new physical device group list 72355db71995Sopenharmony_ci inst->phys_dev_group_count_term = total_count; 72365db71995Sopenharmony_ci inst->phys_dev_groups_term = new_phys_dev_groups; 72375db71995Sopenharmony_ci } 72385db71995Sopenharmony_ci 72395db71995Sopenharmony_ci if (sorted_phys_dev_array != NULL) { 72405db71995Sopenharmony_ci for (uint32_t i = 0; i < sorted_count; ++i) { 72415db71995Sopenharmony_ci if (sorted_phys_dev_array[i].device_count > 0 && sorted_phys_dev_array[i].physical_devices != NULL) { 72425db71995Sopenharmony_ci loader_instance_heap_free(inst, sorted_phys_dev_array[i].physical_devices); 72435db71995Sopenharmony_ci } 72445db71995Sopenharmony_ci } 72455db71995Sopenharmony_ci loader_instance_heap_free(inst, sorted_phys_dev_array); 72465db71995Sopenharmony_ci } 72475db71995Sopenharmony_ci 72485db71995Sopenharmony_ci uint32_t copy_count = inst->phys_dev_group_count_term; 72495db71995Sopenharmony_ci if (NULL != pPhysicalDeviceGroupProperties) { 72505db71995Sopenharmony_ci if (copy_count > *pPhysicalDeviceGroupCount) { 72515db71995Sopenharmony_ci copy_count = *pPhysicalDeviceGroupCount; 72525db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 72535db71995Sopenharmony_ci "terminator_EnumeratePhysicalDeviceGroups : Trimming device count from %d to %d.", 72545db71995Sopenharmony_ci inst->phys_dev_group_count_term, copy_count); 72555db71995Sopenharmony_ci res = VK_INCOMPLETE; 72565db71995Sopenharmony_ci } 72575db71995Sopenharmony_ci 72585db71995Sopenharmony_ci for (uint32_t i = 0; i < copy_count; i++) { 72595db71995Sopenharmony_ci memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_term[i], sizeof(VkPhysicalDeviceGroupProperties)); 72605db71995Sopenharmony_ci } 72615db71995Sopenharmony_ci } 72625db71995Sopenharmony_ci 72635db71995Sopenharmony_ci *pPhysicalDeviceGroupCount = copy_count; 72645db71995Sopenharmony_ci 72655db71995Sopenharmony_ci } else { 72665db71995Sopenharmony_ci *pPhysicalDeviceGroupCount = total_count; 72675db71995Sopenharmony_ci } 72685db71995Sopenharmony_ci return res; 72695db71995Sopenharmony_ci} 7270