1/* 2 * 3 * Copyright (c) 2023 The Khronos Group Inc. 4 * Copyright (c) 2023 Valve Corporation 5 * Copyright (c) 2023 LunarG, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 * 20 * Author: Charles Giessen <charles@lunarg.com> 21 * 22 */ 23 24#include "settings.h" 25 26#include "allocation.h" 27#include "cJSON.h" 28#include "loader.h" 29#include "loader_environment.h" 30#include "loader_windows.h" 31#include "log.h" 32#include "stack_allocation.h" 33#include "vk_loader_platform.h" 34 35loader_platform_thread_mutex global_loader_settings_lock; 36loader_settings global_loader_settings; 37 38void free_layer_configuration(const struct loader_instance* inst, loader_settings_layer_configuration* layer_configuration) { 39 loader_instance_heap_free(inst, layer_configuration->name); 40 loader_instance_heap_free(inst, layer_configuration->path); 41 memset(layer_configuration, 0, sizeof(loader_settings_layer_configuration)); 42} 43 44void free_loader_settings(const struct loader_instance* inst, loader_settings* settings) { 45 if (NULL != settings->layer_configurations) { 46 for (uint32_t i = 0; i < settings->layer_configuration_count; i++) { 47 free_layer_configuration(inst, &settings->layer_configurations[i]); 48 } 49 } 50 loader_instance_heap_free(inst, settings->layer_configurations); 51 loader_instance_heap_free(inst, settings->settings_file_path); 52 memset(settings, 0, sizeof(loader_settings)); 53} 54 55loader_settings_layer_control parse_control_string(char* control_string) { 56 loader_settings_layer_control layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT; 57 if (strcmp(control_string, "auto") == 0) 58 layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT; 59 else if (strcmp(control_string, "on") == 0) 60 layer_control = LOADER_SETTINGS_LAYER_CONTROL_ON; 61 else if (strcmp(control_string, "off") == 0) 62 layer_control = LOADER_SETTINGS_LAYER_CONTROL_OFF; 63 else if (strcmp(control_string, "unordered_layer_location") == 0) 64 layer_control = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION; 65 return layer_control; 66} 67 68const char* loader_settings_layer_control_to_string(loader_settings_layer_control control) { 69 switch (control) { 70 case (LOADER_SETTINGS_LAYER_CONTROL_DEFAULT): 71 return "auto"; 72 case (LOADER_SETTINGS_LAYER_CONTROL_ON): 73 return "on"; 74 case (LOADER_SETTINGS_LAYER_CONTROL_OFF): 75 return "off"; 76 case (LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION): 77 return "unordered_layer_location"; 78 default: 79 return "UNKNOWN_LAYER_CONTROl"; 80 } 81} 82 83uint32_t parse_log_filters_from_strings(struct loader_string_list* log_filters) { 84 uint32_t filters = 0; 85 for (uint32_t i = 0; i < log_filters->count; i++) { 86 if (strcmp(log_filters->list[i], "all") == 0) 87 filters |= VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_PERF_BIT | VULKAN_LOADER_ERROR_BIT | 88 VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT | VULKAN_LOADER_VALIDATION_BIT; 89 else if (strcmp(log_filters->list[i], "info") == 0) 90 filters |= VULKAN_LOADER_INFO_BIT; 91 else if (strcmp(log_filters->list[i], "warn") == 0) 92 filters |= VULKAN_LOADER_WARN_BIT; 93 else if (strcmp(log_filters->list[i], "perf") == 0) 94 filters |= VULKAN_LOADER_PERF_BIT; 95 else if (strcmp(log_filters->list[i], "error") == 0) 96 filters |= VULKAN_LOADER_ERROR_BIT; 97 else if (strcmp(log_filters->list[i], "debug") == 0) 98 filters |= VULKAN_LOADER_DEBUG_BIT; 99 else if (strcmp(log_filters->list[i], "layer") == 0) 100 filters |= VULKAN_LOADER_LAYER_BIT; 101 else if (strcmp(log_filters->list[i], "driver") == 0) 102 filters |= VULKAN_LOADER_DRIVER_BIT; 103 else if (strcmp(log_filters->list[i], "validation") == 0) 104 filters |= VULKAN_LOADER_VALIDATION_BIT; 105 } 106 return filters; 107} 108 109bool parse_json_enable_disable_option(const struct loader_instance* inst, cJSON* object, const char* key) { 110 char* str = NULL; 111 VkResult res = loader_parse_json_string(object, key, &str); 112 if (res != VK_SUCCESS || NULL == str) { 113 return false; 114 } 115 bool enable = false; 116 if (strcmp(str, "enabled") == 0) { 117 enable = true; 118 } 119 loader_instance_heap_free(inst, str); 120 return enable; 121} 122 123VkResult parse_layer_configuration(const struct loader_instance* inst, cJSON* layer_configuration_json, 124 loader_settings_layer_configuration* layer_configuration) { 125 char* control_string = NULL; 126 VkResult res = loader_parse_json_string(layer_configuration_json, "control", &control_string); 127 if (res != VK_SUCCESS) { 128 goto out; 129 } 130 layer_configuration->control = parse_control_string(control_string); 131 loader_instance_heap_free(inst, control_string); 132 133 // If that is the only value - do no further parsing 134 if (layer_configuration->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) { 135 goto out; 136 } 137 138 res = loader_parse_json_string(layer_configuration_json, "name", &(layer_configuration->name)); 139 if (res != VK_SUCCESS) { 140 goto out; 141 } 142 143 res = loader_parse_json_string(layer_configuration_json, "path", &(layer_configuration->path)); 144 if (res != VK_SUCCESS) { 145 goto out; 146 } 147 148 cJSON* treat_as_implicit_manifest = loader_cJSON_GetObjectItem(layer_configuration_json, "treat_as_implicit_manifest"); 149 if (treat_as_implicit_manifest && treat_as_implicit_manifest->type == cJSON_True) { 150 layer_configuration->treat_as_implicit_manifest = true; 151 } 152out: 153 if (VK_SUCCESS != res) { 154 free_layer_configuration(inst, layer_configuration); 155 } 156 return res; 157} 158 159VkResult parse_layer_configurations(const struct loader_instance* inst, cJSON* settings_object, loader_settings* loader_settings) { 160 VkResult res = VK_SUCCESS; 161 162 cJSON* layer_configurations = loader_cJSON_GetObjectItem(settings_object, "layers"); 163 if (NULL == layer_configurations) { 164 return VK_ERROR_INITIALIZATION_FAILED; 165 } 166 167 uint32_t layer_configurations_count = loader_cJSON_GetArraySize(layer_configurations); 168 if (layer_configurations_count == 0) { 169 return VK_SUCCESS; 170 } 171 172 loader_settings->layer_configuration_count = layer_configurations_count; 173 174 loader_settings->layer_configurations = loader_instance_heap_calloc( 175 inst, sizeof(loader_settings_layer_configuration) * layer_configurations_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 176 if (NULL == loader_settings->layer_configurations) { 177 res = VK_ERROR_OUT_OF_HOST_MEMORY; 178 goto out; 179 } 180 181 for (uint32_t i = 0; i < layer_configurations_count; i++) { 182 cJSON* layer = loader_cJSON_GetArrayItem(layer_configurations, i); 183 if (NULL == layer) { 184 res = VK_ERROR_INITIALIZATION_FAILED; 185 goto out; 186 } 187 res = parse_layer_configuration(inst, layer, &(loader_settings->layer_configurations[i])); 188 if (VK_SUCCESS != res) { 189 goto out; 190 } 191 } 192out: 193 if (res != VK_SUCCESS) { 194 if (loader_settings->layer_configurations) { 195 for (uint32_t i = 0; i < loader_settings->layer_configuration_count; i++) { 196 free_layer_configuration(inst, &(loader_settings->layer_configurations[i])); 197 } 198 loader_settings->layer_configuration_count = 0; 199 loader_instance_heap_free(inst, loader_settings->layer_configurations); 200 loader_settings->layer_configurations = NULL; 201 } 202 } 203 204 return res; 205} 206 207VkResult check_if_settings_path_exists(const struct loader_instance* inst, char* base, char* suffix, char** settings_file_path) { 208 if (NULL == base || NULL == suffix) { 209 return VK_ERROR_INITIALIZATION_FAILED; 210 } 211 size_t base_len = strlen(base); 212 size_t suffix_len = strlen(suffix); 213 size_t path_len = base_len + suffix_len + 1; 214 *settings_file_path = loader_instance_heap_calloc(inst, path_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 215 if (NULL == *settings_file_path) { 216 return VK_ERROR_OUT_OF_HOST_MEMORY; 217 } 218 loader_strncpy(*settings_file_path, path_len, base, base_len); 219 loader_strncat(*settings_file_path, path_len, suffix, suffix_len); 220 221 if (!loader_platform_file_exists(*settings_file_path)) { 222 loader_instance_heap_free(inst, *settings_file_path); 223 *settings_file_path = NULL; 224 return VK_ERROR_INITIALIZATION_FAILED; 225 } 226 return VK_SUCCESS; 227} 228VkResult get_unix_settings_path(const struct loader_instance* inst, char** settings_file_path) { 229 VkResult res = 230 check_if_settings_path_exists(inst, loader_secure_getenv("HOME", inst), 231 "/.local/share/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, settings_file_path); 232 if (res == VK_SUCCESS) { 233 return res; 234 } 235 // If HOME isn't set, fallback to XDG_DATA_HOME 236 res = check_if_settings_path_exists(inst, loader_secure_getenv("XDG_DATA_HOME", inst), 237 "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, settings_file_path); 238 if (res == VK_SUCCESS) { 239 return res; 240 } 241 // if XDG_DATA_HOME isn't set, fallback to /etc. 242 // note that the settings_fil_path_suffix stays the same since its the same layout as for XDG_DATA_HOME 243 return check_if_settings_path_exists(inst, "/etc", "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, 244 settings_file_path); 245} 246 247bool check_if_settings_are_equal(loader_settings* a, loader_settings* b) { 248 // If either pointer is null, return true 249 if (NULL == a || NULL == b) return false; 250 bool are_equal = true; 251 are_equal &= a->settings_active == b->settings_active; 252 are_equal &= a->has_unordered_layer_location == b->has_unordered_layer_location; 253 are_equal &= a->debug_level == b->debug_level; 254 are_equal &= a->layer_configuration_count == b->layer_configuration_count; 255 if (!are_equal) return false; 256 for (uint32_t i = 0; i < a->layer_configuration_count && i < b->layer_configuration_count; i++) { 257 if (a->layer_configurations[i].name && b->layer_configurations[i].name) { 258 are_equal &= 0 == strcmp(a->layer_configurations[i].name, b->layer_configurations[i].name); 259 } else { 260 are_equal = false; 261 } 262 if (a->layer_configurations[i].path && b->layer_configurations[i].path) { 263 are_equal &= 0 == strcmp(a->layer_configurations[i].path, b->layer_configurations[i].path); 264 } else { 265 are_equal = false; 266 } 267 are_equal &= a->layer_configurations[i].control == b->layer_configurations[i].control; 268 } 269 return are_equal; 270} 271 272void log_settings(const struct loader_instance* inst, loader_settings* settings) { 273 if (settings == NULL) { 274 return; 275 } 276 loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Using layer configurations found in loader settings from %s", 277 settings->settings_file_path); 278 279 loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Layer Configurations count = %d", settings->layer_configuration_count); 280 for (uint32_t i = 0; i < settings->layer_configuration_count; i++) { 281 loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---- Layer Configuration [%d] ----", i); 282 if (settings->layer_configurations[i].control != LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) { 283 loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Name: %s", settings->layer_configurations[i].name); 284 loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Path: %s", settings->layer_configurations[i].path); 285 } 286 loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Control: %s", 287 loader_settings_layer_control_to_string(settings->layer_configurations[i].control)); 288 } 289 loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---------------------------------"); 290} 291 292// Loads the vk_loader_settings.json file 293// Returns VK_SUCCESS if it was found & was successfully parsed. Otherwise, it returns VK_ERROR_INITIALIZATION_FAILED if it 294// wasn't found or failed to parse, and returns VK_ERROR_OUT_OF_HOST_MEMORY if it was unable to allocate enough memory. 295VkResult get_loader_settings(const struct loader_instance* inst, loader_settings* loader_settings) { 296 VkResult res = VK_SUCCESS; 297 cJSON* json = NULL; 298 char* file_format_version_string = NULL; 299 char* settings_file_path = NULL; 300#if defined(WIN32) 301 res = windows_get_loader_settings_file_path(inst, &settings_file_path); 302 if (res != VK_SUCCESS) { 303 goto out; 304 } 305 306#elif COMMON_UNIX_PLATFORMS 307 res = get_unix_settings_path(inst, &settings_file_path); 308 if (res != VK_SUCCESS) { 309 goto out; 310 } 311#else 312#warning "Unsupported platform - must specify platform specific location for vk_loader_settings.json" 313#endif 314 315 res = loader_get_json(inst, settings_file_path, &json); 316 // Make sure sure the top level json value is an object 317 if (res != VK_SUCCESS || NULL == json || json->type != 6) { 318 goto out; 319 } 320 321 res = loader_parse_json_string(json, "file_format_version", &file_format_version_string); 322 if (res != VK_SUCCESS) { 323 goto out; 324 } 325 uint32_t settings_array_count = 0; 326 bool has_multi_setting_file = false; 327 cJSON* settings_array = loader_cJSON_GetObjectItem(json, "settings_array"); 328 cJSON* single_settings_object = loader_cJSON_GetObjectItem(json, "settings"); 329 if (NULL != settings_array) { 330 has_multi_setting_file = true; 331 settings_array_count = loader_cJSON_GetArraySize(settings_array); 332 } else if (NULL != single_settings_object) { 333 settings_array_count = 1; 334 } 335 336 // Corresponds to the settings object that has no app keys 337 int global_settings_index = -1; 338 // Corresponds to the settings object which has a matching app key 339 int index_to_use = -1; 340 341 char current_process_path[1024]; 342 bool valid_exe_path = NULL != loader_platform_executable_path(current_process_path, 1024); 343 344 for (int i = 0; i < (int)settings_array_count; i++) { 345 if (has_multi_setting_file) { 346 single_settings_object = loader_cJSON_GetArrayItem(settings_array, i); 347 } 348 cJSON* app_keys = loader_cJSON_GetObjectItem(single_settings_object, "app_keys"); 349 if (NULL == app_keys) { 350 if (global_settings_index == -1) { 351 global_settings_index = i; // use the first 'global' settings that has no app keys as the global one 352 } 353 continue; 354 } else if (valid_exe_path) { 355 int app_key_count = loader_cJSON_GetArraySize(app_keys); 356 if (app_key_count == 0) { 357 continue; // empty array 358 } 359 for (int j = 0; j < app_key_count; j++) { 360 cJSON* app_key_json = loader_cJSON_GetArrayItem(app_keys, j); 361 if (NULL == app_key_json) { 362 continue; 363 } 364 char* app_key = loader_cJSON_Print(app_key_json); 365 if (NULL == app_key) { 366 continue; 367 } 368 369 if (strcmp(current_process_path, app_key) == 0) { 370 index_to_use = i; 371 } 372 loader_instance_heap_free(inst, app_key); 373 if (index_to_use == i) { 374 break; // break only after freeing the app key 375 } 376 } 377 } 378 } 379 380 // No app specific settings match - either use global settings or exit 381 if (index_to_use == -1) { 382 if (global_settings_index == -1) { 383 goto out; // No global settings were found - exit 384 } else { 385 index_to_use = global_settings_index; // Global settings are present - use it 386 } 387 } 388 389 // Now get the actual settings object to use - already have it if there is only one settings object 390 // If there are multiple settings, just need to set single_settings_object to the desired settings object 391 if (has_multi_setting_file) { 392 single_settings_object = loader_cJSON_GetArrayItem(settings_array, index_to_use); 393 if (NULL == single_settings_object) { 394 res = VK_ERROR_INITIALIZATION_FAILED; 395 goto out; 396 } 397 } 398 399 // optional 400 cJSON* stderr_filter = loader_cJSON_GetObjectItem(single_settings_object, "stderr_log"); 401 if (NULL != stderr_filter) { 402 struct loader_string_list stderr_log = {0}; 403 res = loader_parse_json_array_of_strings(inst, single_settings_object, "stderr_log", &stderr_log); 404 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 405 goto out; 406 } 407 loader_settings->debug_level = parse_log_filters_from_strings(&stderr_log); 408 free_string_list(inst, &stderr_log); 409 } 410 411 // optional 412 cJSON* logs_to_use = loader_cJSON_GetObjectItem(single_settings_object, "log_locations"); 413 if (NULL != logs_to_use) { 414 int log_count = loader_cJSON_GetArraySize(logs_to_use); 415 for (int i = 0; i < log_count; i++) { 416 cJSON* log_element = loader_cJSON_GetArrayItem(logs_to_use, i); 417 // bool is_valid = true; 418 if (NULL != log_element) { 419 struct loader_string_list log_destinations = {0}; 420 res = loader_parse_json_array_of_strings(inst, log_element, "destinations", &log_destinations); 421 if (res != VK_SUCCESS) { 422 // is_valid = false; 423 } 424 free_string_list(inst, &log_destinations); 425 struct loader_string_list log_filters = {0}; 426 res = loader_parse_json_array_of_strings(inst, log_element, "filters", &log_filters); 427 if (res != VK_SUCCESS) { 428 // is_valid = false; 429 } 430 free_string_list(inst, &log_filters); 431 } 432 } 433 } 434 435 res = parse_layer_configurations(inst, single_settings_object, loader_settings); 436 if (res != VK_SUCCESS) { 437 goto out; 438 } 439 440 // Determine if there exists a layer configuration indicating where to put layers not contained in the settings file 441 // LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION 442 for (uint32_t i = 0; i < loader_settings->layer_configuration_count; i++) { 443 if (loader_settings->layer_configurations[i].control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) { 444 loader_settings->has_unordered_layer_location = true; 445 break; 446 } 447 } 448 449 loader_settings->settings_file_path = settings_file_path; 450 settings_file_path = NULL; 451 loader_settings->settings_active = true; 452out: 453 if (NULL != json) { 454 loader_cJSON_Delete(json); 455 } 456 457 loader_instance_heap_free(inst, settings_file_path); 458 459 loader_instance_heap_free(inst, file_format_version_string); 460 return res; 461} 462 463VkResult update_global_loader_settings(void) { 464 loader_settings settings = {0}; 465 VkResult res = get_loader_settings(NULL, &settings); 466 loader_platform_thread_lock_mutex(&global_loader_settings_lock); 467 468 free_loader_settings(NULL, &global_loader_settings); 469 if (res == VK_SUCCESS) { 470 if (!check_if_settings_are_equal(&settings, &global_loader_settings)) { 471 log_settings(NULL, &settings); 472 } 473 474 memcpy(&global_loader_settings, &settings, sizeof(loader_settings)); 475 if (global_loader_settings.settings_active) { 476 loader_set_global_debug_level(global_loader_settings.debug_level); 477 } 478 } 479 loader_platform_thread_unlock_mutex(&global_loader_settings_lock); 480 return res; 481} 482 483void init_global_loader_settings(void) { 484 loader_platform_thread_create_mutex(&global_loader_settings_lock); 485 // Free out the global settings in case the process was loaded & unloaded 486 free_loader_settings(NULL, &global_loader_settings); 487} 488void teardown_global_loader_settings(void) { 489 free_loader_settings(NULL, &global_loader_settings); 490 loader_platform_thread_delete_mutex(&global_loader_settings_lock); 491} 492 493bool should_skip_logging_global_messages(VkFlags msg_type) { 494 loader_platform_thread_lock_mutex(&global_loader_settings_lock); 495 bool should_skip = global_loader_settings.settings_active && 0 != (msg_type & global_loader_settings.debug_level); 496 loader_platform_thread_unlock_mutex(&global_loader_settings_lock); 497 return should_skip; 498} 499 500// Use this function to get the correct settings to use based on the context 501// If inst is NULL - use the global settings and lock the mutex 502// Else return the settings local to the instance - but do nto lock the mutex 503const loader_settings* get_current_settings_and_lock(const struct loader_instance* inst) { 504 if (inst) { 505 return &inst->settings; 506 } 507 loader_platform_thread_lock_mutex(&global_loader_settings_lock); 508 return &global_loader_settings; 509} 510// Release the global settings lock if we are using the global settings - aka if inst is NULL 511void release_current_settings_lock(const struct loader_instance* inst) { 512 if (inst == NULL) { 513 loader_platform_thread_unlock_mutex(&global_loader_settings_lock); 514 } 515} 516 517VkResult get_settings_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers, 518 bool* should_search_for_other_layers) { 519 VkResult res = VK_SUCCESS; 520 *should_search_for_other_layers = true; // default to true 521 522 const loader_settings* settings = get_current_settings_and_lock(inst); 523 524 if (NULL == settings || !settings->settings_active) { 525 goto out; 526 } 527 528 // Assume the list doesn't contain LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION at first 529 *should_search_for_other_layers = false; 530 531 for (uint32_t i = 0; i < settings->layer_configuration_count; i++) { 532 loader_settings_layer_configuration* layer_config = &settings->layer_configurations[i]; 533 534 // If we encountered a layer that should be forced off, we add it to the settings_layers list but only 535 // with the data required to compare it with layers not in the settings file (aka name and manifest path) 536 if (layer_config->control == LOADER_SETTINGS_LAYER_CONTROL_OFF) { 537 struct loader_layer_properties props = {0}; 538 props.settings_control_value = LOADER_SETTINGS_LAYER_CONTROL_OFF; 539 loader_strncpy(props.info.layerName, VK_MAX_EXTENSION_NAME_SIZE, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE); 540 props.info.layerName[VK_MAX_EXTENSION_NAME_SIZE - 1] = '\0'; 541 res = loader_copy_to_new_str(inst, layer_config->path, &props.manifest_file_name); 542 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 543 goto out; 544 } 545 res = loader_append_layer_property(inst, settings_layers, &props); 546 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 547 loader_free_layer_properties(inst, &props); 548 goto out; 549 } 550 continue; 551 } 552 553 // The special layer location that indicates where unordered layers should go only should have the 554 // settings_control_value set - everything else should be NULL 555 if (layer_config->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) { 556 struct loader_layer_properties props = {0}; 557 props.settings_control_value = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION; 558 res = loader_append_layer_property(inst, settings_layers, &props); 559 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) { 560 loader_free_layer_properties(inst, &props); 561 goto out; 562 } 563 *should_search_for_other_layers = true; 564 continue; 565 } 566 567 if (layer_config->path == NULL) { 568 continue; 569 } 570 571 cJSON* json = NULL; 572 VkResult local_res = loader_get_json(inst, layer_config->path, &json); 573 if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) { 574 res = VK_ERROR_OUT_OF_HOST_MEMORY; 575 goto out; 576 } else if (VK_SUCCESS != local_res || NULL == json) { 577 continue; 578 } 579 580 local_res = 581 loader_add_layer_properties(inst, settings_layers, json, layer_config->treat_as_implicit_manifest, layer_config->path); 582 loader_cJSON_Delete(json); 583 584 // If the error is anything other than out of memory we still want to try to load the other layers 585 if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) { 586 res = VK_ERROR_OUT_OF_HOST_MEMORY; 587 goto out; 588 } 589 struct loader_layer_properties* newly_added_layer = &settings_layers->list[settings_layers->count - 1]; 590 newly_added_layer->settings_control_value = layer_config->control; 591 // If the manifest file found has a name that differs from the one in the settings, remove this layer from consideration 592 bool should_remove = false; 593 if (strncmp(newly_added_layer->info.layerName, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE) != 0) { 594 should_remove = true; 595 loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1); 596 } 597 // Make sure the layer isn't already in the list 598 for (uint32_t j = 0; settings_layers->count > 0 && j < settings_layers->count - 1; j++) { 599 if (0 == 600 strncmp(settings_layers->list[j].info.layerName, newly_added_layer->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) { 601 if (0 == (newly_added_layer->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) && 602 strcmp(settings_layers->list[j].lib_name, newly_added_layer->lib_name) == 0) { 603 should_remove = true; 604 break; 605 } 606 } 607 } 608 if (should_remove) { 609 loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1); 610 } 611 } 612 613out: 614 release_current_settings_lock(inst); 615 return res; 616} 617 618// Check if layers has an element with the same name. 619// If layer_property is a regular layer, check if the lib_path is the same. 620// If layer_property is a meta layer, just use the layerName 621bool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct loader_layer_properties* layer_property) { 622 // If the layer is a meta layer, just check against the name 623 for (uint32_t i = 0; i < layer_list->count; i++) { 624 if (0 == strncmp(layer_list->list[i].info.layerName, layer_property->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) { 625 if (0 == (layer_property->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) && 626 strcmp(layer_list->list[i].lib_name, layer_property->lib_name) == 0) { 627 return true; 628 } 629 } 630 } 631 return false; 632} 633 634VkResult combine_settings_layers_with_regular_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers, 635 struct loader_layer_list* regular_layers, 636 struct loader_layer_list* output_layers) { 637 VkResult res = VK_SUCCESS; 638 bool has_unordered_layer_location = false; 639 uint32_t unordered_layer_location_index = 0; 640 // Location to put layers that aren't known to the settings file 641 // Find it here so we dont have to pass in a loader_settings struct 642 for (uint32_t i = 0; i < settings_layers->count; i++) { 643 if (settings_layers->list[i].settings_control_value == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) { 644 has_unordered_layer_location = true; 645 unordered_layer_location_index = i; 646 break; 647 } 648 } 649 650 if (settings_layers->count == 0 && regular_layers->count == 0) { 651 // No layers to combine 652 goto out; 653 } else if (settings_layers->count == 0) { 654 // No settings layers - just copy regular to output_layers - memset regular layers to prevent double frees 655 *output_layers = *regular_layers; 656 memset(regular_layers, 0, sizeof(struct loader_layer_list)); 657 goto out; 658 } else if (regular_layers->count == 0 || !has_unordered_layer_location) { 659 // No regular layers or has_unordered_layer_location is false - just copy settings to output_layers - 660 // memset settings layers to prevent double frees 661 *output_layers = *settings_layers; 662 memset(settings_layers, 0, sizeof(struct loader_layer_list)); 663 goto out; 664 } 665 666 res = loader_init_generic_list(inst, (struct loader_generic_list*)output_layers, 667 (settings_layers->count + regular_layers->count) * sizeof(struct loader_layer_properties)); 668 if (VK_SUCCESS != res) { 669 goto out; 670 } 671 672 // Insert the settings layers into output_layers up to unordered_layer_index 673 for (uint32_t i = 0; i < unordered_layer_location_index; i++) { 674 if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i])) { 675 res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]); 676 if (VK_SUCCESS != res) { 677 goto out; 678 } 679 } 680 } 681 682 for (uint32_t i = 0; i < regular_layers->count; i++) { 683 // Check if its already been put in the output_layers list as well as the remaining settings_layers 684 bool regular_layer_is_ordered = check_if_layer_is_in_list(output_layers, ®ular_layers->list[i]) || 685 check_if_layer_is_in_list(settings_layers, ®ular_layers->list[i]); 686 // If it isn't found, add it 687 if (!regular_layer_is_ordered) { 688 res = loader_append_layer_property(inst, output_layers, ®ular_layers->list[i]); 689 if (VK_SUCCESS != res) { 690 goto out; 691 } 692 } else { 693 // layer is already ordered and can be safely freed 694 loader_free_layer_properties(inst, ®ular_layers->list[i]); 695 } 696 } 697 698 // Insert the rest of the settings layers into combined_layers from unordered_layer_index to the end 699 // start at one after the unordered_layer_index 700 for (uint32_t i = unordered_layer_location_index + 1; i < settings_layers->count; i++) { 701 res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]); 702 if (VK_SUCCESS != res) { 703 goto out; 704 } 705 } 706 707out: 708 if (res != VK_SUCCESS) { 709 loader_delete_layer_list_and_properties(inst, output_layers); 710 } 711 712 return res; 713} 714 715VkResult enable_correct_layers_from_settings(const struct loader_instance* inst, const struct loader_envvar_all_filters* filters, 716 uint32_t app_enabled_name_count, const char* const* app_enabled_names, 717 const struct loader_layer_list* instance_layers, 718 struct loader_pointer_layer_list* target_layer_list, 719 struct loader_pointer_layer_list* activated_layer_list) { 720 VkResult res = VK_SUCCESS; 721 char* vk_instance_layers_env = loader_getenv(ENABLED_LAYERS_ENV, inst); 722 size_t vk_instance_layers_env_len = 0; 723 char* vk_instance_layers_env_copy = NULL; 724 if (vk_instance_layers_env != NULL) { 725 vk_instance_layers_env_len = strlen(vk_instance_layers_env) + 1; 726 vk_instance_layers_env_copy = loader_stack_alloc(vk_instance_layers_env_len); 727 728 loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers: %s", 729 ENABLED_LAYERS_ENV, vk_instance_layers_env); 730 } 731 for (uint32_t i = 0; i < instance_layers->count; i++) { 732 bool enable_layer = false; 733 struct loader_layer_properties* props = &instance_layers->list[i]; 734 735 // Do not enable the layer if the settings have it set as off 736 if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_OFF) { 737 continue; 738 } 739 // Force enable it based on settings 740 if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON) { 741 enable_layer = true; 742 } 743 744 // Check if disable filter needs to skip the layer 745 if ((filters->disable_filter.disable_all || filters->disable_filter.disable_all_implicit || 746 check_name_matches_filter_environment_var(props->info.layerName, &filters->disable_filter.additional_filters)) && 747 !check_name_matches_filter_environment_var(props->info.layerName, &filters->allow_filter)) { 748 continue; 749 } 750 // Check the enable filter 751 if (!enable_layer && check_name_matches_filter_environment_var(props->info.layerName, &filters->enable_filter)) { 752 enable_layer = true; 753 } 754 755 // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS 756 if (!enable_layer && vk_instance_layers_env && vk_instance_layers_env_copy && vk_instance_layers_env_len > 0) { 757 // Copy the env-var on each iteration, so that loader_get_next_path can correctly find the separators 758 // This solution only needs one stack allocation ahead of time rather than an allocation per layer in the env-var 759 loader_strncpy(vk_instance_layers_env_copy, vk_instance_layers_env_len, vk_instance_layers_env, 760 vk_instance_layers_env_len); 761 762 while (vk_instance_layers_env_copy && *vk_instance_layers_env_copy) { 763 char* next = loader_get_next_path(vk_instance_layers_env_copy); 764 if (0 == strcmp(vk_instance_layers_env_copy, props->info.layerName)) { 765 enable_layer = true; 766 break; 767 } 768 vk_instance_layers_env_copy = next; 769 } 770 } 771 772 // Check if it should be enabled by the application 773 if (!enable_layer) { 774 for (uint32_t j = 0; j < app_enabled_name_count; j++) { 775 if (strcmp(props->info.layerName, app_enabled_names[j]) == 0) { 776 enable_layer = true; 777 break; 778 } 779 } 780 } 781 782 // Check if its an implicit layers and thus enabled by default 783 if (!enable_layer && (0 == (props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) && 784 loader_implicit_layer_is_enabled(inst, filters, props)) { 785 enable_layer = true; 786 } 787 788 if (enable_layer) { 789 // Check if the layer is a meta layer reuse the existing function to add the meta layer 790 if (props->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) { 791 res = loader_add_meta_layer(inst, filters, props, target_layer_list, activated_layer_list, instance_layers, NULL); 792 if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out; 793 } else { 794 res = loader_add_layer_properties_to_list(inst, target_layer_list, props); 795 if (res != VK_SUCCESS) { 796 goto out; 797 } 798 res = loader_add_layer_properties_to_list(inst, activated_layer_list, props); 799 if (res != VK_SUCCESS) { 800 goto out; 801 } 802 } 803 } 804 } 805out: 806 return res; 807} 808