From 1e2154f7580d49d7d2f79e012264f5e275687780 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Wed, 10 Dec 2025 23:51:12 -0600 Subject: [PATCH] Fix duplicate layer output with the settings file When there exists a layer in the settings file with the same name as a layer in the default search paths with a different library_path, the loader was mistaking it as a 'distinct' layer. Because the settings file allows specifying layers by their path & whether to enable/disable them, it is possible to exactly specify which layers will load, including duplicates. --- loader/settings.c | 22 ++++++++++++++------- tests/loader_settings_tests.cpp | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/loader/settings.c b/loader/settings.c index 3ca695217..bc1ca327e 100644 --- a/loader/settings.c +++ b/loader/settings.c @@ -1034,7 +1034,10 @@ TEST_FUNCTION_EXPORT VkResult get_settings_layers(const struct loader_instance* // Skip comparing to UNORDERED_LAYER_LOCATION // If layer_property is a regular layer, check if the lib_path is the same. // Make sure that the lib_name pointers are non-null before calling strcmp. -bool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct loader_layer_properties* layer_property) { +// consider_lib_path - true if comparison should include the library_path in distinguishing layers. Used to prevent duplicates +// between settings file provided layers and default found layers +bool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct loader_layer_properties* layer_property, + bool consider_lib_path) { // If the layer is a meta layer, just check against the name for (uint32_t i = 0; i < layer_list->count; i++) { if (0 == strncmp(layer_list->list[i].info.layerName, layer_property->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) { @@ -1044,6 +1047,9 @@ bool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct load if (VK_LAYER_TYPE_FLAG_META_LAYER == (layer_property->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { return true; } + if (!consider_lib_path) { + return true; + } if (layer_list->list[i].lib_name && layer_property->lib_name) { return strcmp(layer_list->list[i].lib_name, layer_property->lib_name) == 0; } @@ -1092,7 +1098,7 @@ VkResult combine_settings_layers_with_regular_layers(const struct loader_instanc // Insert the settings layers into output_layers up to unordered_layer_index for (uint32_t i = 0; i < unordered_layer_location_index; i++) { - if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i])) { + if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i], true)) { res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]); if (VK_SUCCESS != res) { goto out; @@ -1102,8 +1108,8 @@ VkResult combine_settings_layers_with_regular_layers(const struct loader_instanc for (uint32_t i = 0; i < regular_layers->count; i++) { // Check if its already been put in the output_layers list as well as the remaining settings_layers - bool regular_layer_is_ordered = check_if_layer_is_in_list(output_layers, ®ular_layers->list[i]) || - check_if_layer_is_in_list(settings_layers, ®ular_layers->list[i]); + bool regular_layer_is_ordered = check_if_layer_is_in_list(output_layers, ®ular_layers->list[i], false) || + check_if_layer_is_in_list(settings_layers, ®ular_layers->list[i], false); // If it isn't found, add it if (!regular_layer_is_ordered) { res = loader_append_layer_property(inst, output_layers, ®ular_layers->list[i]); @@ -1119,9 +1125,11 @@ VkResult combine_settings_layers_with_regular_layers(const struct loader_instanc // Insert the rest of the settings layers into combined_layers from unordered_layer_index to the end // start at one after the unordered_layer_index for (uint32_t i = unordered_layer_location_index + 1; i < settings_layers->count; i++) { - res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]); - if (VK_SUCCESS != res) { - goto out; + if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i], true)) { + res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]); + if (VK_SUCCESS != res) { + goto out; + } } } diff --git a/tests/loader_settings_tests.cpp b/tests/loader_settings_tests.cpp index a52a4a5d2..e4bf85d5a 100644 --- a/tests/loader_settings_tests.cpp +++ b/tests/loader_settings_tests.cpp @@ -3089,6 +3089,41 @@ TEST(SettingsFile, EnvVarsWorkTogether) { } } +TEST(SettingsFile, DontAllowDuplicatesBetweenSettingsLayersAndDefaultLayers) { + FrameworkEnvironment env; + env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({}); + + const char* explicit_layer_name1 = "VK_LAYER_Regular_TestLayer1"; + env.add_explicit_layer( + ManifestLayer{}.add_layer( + ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)), + "explicit_test_layer1.json"); + + env.add_explicit_layer(TestLayerDetails{ + ManifestLayer{}.add_layer( + ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)), + "explicit_test_layer2.json"} + .set_discovery_type(ManifestDiscoveryType::override_folder)); + + env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting( + AppSpecificSettings{} + .add_stderr_log_filter("all") + .add_layer_configuration(LoaderSettingsLayerConfiguration{}.set_control("unordered_layer_location")) + .add_layer_configuration(LoaderSettingsLayerConfiguration{} + .set_name(explicit_layer_name1) + .set_path(env.get_shimmed_layer_manifest_path(1)) + .set_control("on")))); + + auto layer_props = env.GetLayerProperties(1); + ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name1)); + + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); + + auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1); + ASSERT_TRUE(string_eq(active_layer_props.at(0).layerName, explicit_layer_name1)); +} + // additional drivers being provided by settings file TEST(SettingsFile, AdditionalDrivers) { FrameworkEnvironment env{FrameworkSettings{}.set_log_filter("")};