diff --git a/docs/LoaderInterfaceArchitecture.md b/docs/LoaderInterfaceArchitecture.md index a1bf4c8fa..99615a0c0 100644 --- a/docs/LoaderInterfaceArchitecture.md +++ b/docs/LoaderInterfaceArchitecture.md @@ -888,9 +888,7 @@ discovery. Known layers are those which are found by the loader taking into account default search paths and other environment variables (like VK_LAYER_PATH). -
- This has replaced the older deprecated environment variable - VK_INSTANCE_LAYERS + This functionality is only available with Loaders built with version @@ -1045,8 +1043,7 @@ may be removed in a future loader release. ppEnabledLayerNames. - This has been deprecated by VK_LOADER_LAYERS_ENABLE. - It also overrides any layers disabled with + It overrides any layers disabled with VK_LOADER_LAYERS_DISABLE. diff --git a/docs/LoaderLayerInterface.md b/docs/LoaderLayerInterface.md index ae640c95e..ea175e132 100644 --- a/docs/LoaderLayerInterface.md +++ b/docs/LoaderLayerInterface.md @@ -563,7 +563,7 @@ i.e. they do not require any external context to be enabled, will be enabled. ##### `VK_INSTANCE_LAYERS` -The original `VK_INSTANCE_LAYERS` can be viewed as a special case of the new +The original `VK_INSTANCE_LAYERS` can be viewed as a special case of `VK_LOADER_LAYERS_ENABLE`. Because of this, any layers enabled via `VK_INSTANCE_LAYERS` will be treated the same as layers enabled with `VK_LOADER_LAYERS_ENABLE` and will therefore diff --git a/docs/images/loader_layer_order.png b/docs/images/loader_layer_order.png index 46cdbd155..4f4efe8c1 100644 Binary files a/docs/images/loader_layer_order.png and b/docs/images/loader_layer_order.png differ diff --git a/docs/images/loader_layer_order_calls.png b/docs/images/loader_layer_order_calls.png index 01dc08ce2..18ca25c42 100644 Binary files a/docs/images/loader_layer_order_calls.png and b/docs/images/loader_layer_order_calls.png differ diff --git a/docs/images/svgs/loader_layer_order.svg b/docs/images/svgs/loader_layer_order.svg index e6cafac17..dd4eca2eb 100755 --- a/docs/images/svgs/loader_layer_order.svg +++ b/docs/images/svgs/loader_layer_order.svg @@ -5,9 +5,9 @@ viewBox="0 0 1121.6842 464.72108" id="svg11653" version="1.1" - inkscape:version="1.1 (c68e22c387, 2021-05-23)" + inkscape:version="1.4.2 (ebf0e940, 2025-05-08)" sodipodi:docname="loader_layer_order.svg" - inkscape:export-filename="/home/marky/dev/khronos/hub/loader/docs/images/loader_layer_order.png" + inkscape:export-filename="../loader_layer_order.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" @@ -503,7 +503,7 @@ x2="55.75" y2="1014.3622" /> + inkscape:pagecheckerboard="0" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" /> @@ -760,7 +762,8 @@ inkscape:groupmode="layer" id="layer2" inkscape:label="Background" - transform="translate(11.848806,7.6125679)"> + transform="translate(11.848806,7.6125679)" + style="display:inline"> + + + + + + + + + + + + + transform="translate(141.49609,-63.082703)"> + style="fill:url(#linearGradient4620-0-16-5-1-9);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.33939;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + ry="20.9611" /> EnabledEnabledExplicitLayers + + transform="translate(153.49609,-63.082664)"> ImplicitLayers - - - - - - - - - - - - diff --git a/docs/images/svgs/loader_layer_order_calls.svg b/docs/images/svgs/loader_layer_order_calls.svg index 51e2e8e03..098fe892a 100644 --- a/docs/images/svgs/loader_layer_order_calls.svg +++ b/docs/images/svgs/loader_layer_order_calls.svg @@ -1,11 +1,11 @@ - - - - - + gradientTransform="matrix(1.3793103,0,0,1.9195479,1067.8858,-1869.7148)" /> + inkscape:pagecheckerboard="0" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" /> @@ -576,25 +542,25 @@ inkscape:label="Background" transform="translate(0.62160975,46.138115)"> Driver Driver Driver LoaderTerminator @@ -1077,7 +1043,7 @@ + style="fill:url(#linearGradient4620-0-16-5-3-2);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.35222;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + height="139.37927" + x="640" + y="891.2583" + ry="22.649132" /> EnvironmentEnabledEnabledExplicitLayers ApplicationEnabledExplicitLayers - - - - OverrideLayer - - - - - - - - - - - - - - - - - - - - - - diff --git a/loader/loader.c b/loader/loader.c index 99daa47ea..d3d48f360 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -4641,15 +4641,20 @@ loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *i // Go through the search_list and find any layers which match type. If layer // type match is found in then add it to ext_list. -VkResult loader_add_implicit_layers(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters, - struct loader_pointer_layer_list *target_list, +// If the layer name is in enabled_layers_env, do not add it to the list, that way it can be ordered alongside the other env-var +// enabled layers +VkResult loader_add_implicit_layers(const struct loader_instance *inst, const char *enabled_layers_env, + const struct loader_envvar_all_filters *filters, struct loader_pointer_layer_list *target_list, struct loader_pointer_layer_list *expanded_target_list, const struct loader_layer_list *source_list) { for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) { struct loader_layer_properties *prop = &source_list->list[src_layer]; if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) { - VkResult result = loader_add_implicit_layer(inst, prop, filters, target_list, expanded_target_list, source_list); - if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; + // If this layer appears in the enabled_layers_env, don't add it. We will let loader_add_environment_layers handle it + if (NULL == enabled_layers_env || NULL == strstr(enabled_layers_env, prop->info.layerName)) { + VkResult result = loader_add_implicit_layer(inst, prop, filters, target_list, expanded_target_list, source_list); + if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result; + } } } return VK_SUCCESS; @@ -4675,6 +4680,7 @@ VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkIns const struct loader_layer_list *instance_layers, const struct loader_envvar_all_filters *layer_filters) { VkResult res = VK_SUCCESS; + char *enabled_layers_env = NULL; assert(inst && "Cannot have null instance"); @@ -4701,15 +4707,17 @@ VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkIns goto out; } + enabled_layers_env = loader_getenv(ENABLED_LAYERS_ENV, inst); + // Add any implicit layers first - res = loader_add_implicit_layers(inst, layer_filters, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, - instance_layers); + res = loader_add_implicit_layers(inst, enabled_layers_env, layer_filters, &inst->app_activated_layer_list, + &inst->expanded_activated_layer_list, instance_layers); if (res != VK_SUCCESS) { goto out; } // Add any layers specified via environment variable next - res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, layer_filters, &inst->app_activated_layer_list, + res = loader_add_environment_layers(inst, enabled_layers_env, layer_filters, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers); if (res != VK_SUCCESS) { goto out; @@ -4721,6 +4729,10 @@ VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkIns warn_if_layers_are_older_than_application(inst); out: + if (enabled_layers_env != NULL) { + loader_free_getenv(enabled_layers_env, inst); + } + return res; } @@ -5564,6 +5576,7 @@ VkResult loader_validate_instance_extensions(struct loader_instance *inst, const const VkInstanceCreateInfo *pCreateInfo) { VkExtensionProperties *extension_prop; char *env_value; + char *enabled_layers_env = NULL; bool check_if_known = true; VkResult res = VK_SUCCESS; @@ -5593,14 +5606,17 @@ VkResult loader_validate_instance_extensions(struct loader_instance *inst, const goto out; } } else { + enabled_layers_env = loader_getenv(ENABLED_LAYERS_ENV, inst); + // Build the lists of active layers (including meta layers) and expanded layers (with meta layers resolved to their // components) - res = loader_add_implicit_layers(inst, layer_filters, &active_layers, &expanded_layers, instance_layers); + res = + loader_add_implicit_layers(inst, enabled_layers_env, layer_filters, &active_layers, &expanded_layers, instance_layers); if (res != VK_SUCCESS) { goto out; } - res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, layer_filters, &active_layers, - &expanded_layers, instance_layers); + res = loader_add_environment_layers(inst, enabled_layers_env, layer_filters, &active_layers, &expanded_layers, + instance_layers); if (res != VK_SUCCESS) { goto out; } @@ -5686,6 +5702,10 @@ VkResult loader_validate_instance_extensions(struct loader_instance *inst, const out: loader_destroy_pointer_layer_list(inst, &active_layers); loader_destroy_pointer_layer_list(inst, &expanded_layers); + if (enabled_layers_env != NULL) { + loader_free_getenv(enabled_layers_env, inst); + } + return res; } diff --git a/loader/loader_environment.c b/loader/loader_environment.c index 6489efac8..f940bded0 100644 --- a/loader/loader_environment.c +++ b/loader/loader_environment.c @@ -448,20 +448,20 @@ bool check_name_matches_filter_environment_var(const char *name, const struct lo // Get the layer name(s) from the env_name environment variable. If layer is found in // search_list then add it to layer_list. But only add it to layer_list if type_flags matches. -VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags, +VkResult loader_add_environment_layers(struct loader_instance *inst, const char *enabled_layers_env, const struct loader_envvar_all_filters *filters, struct loader_pointer_layer_list *target_list, struct loader_pointer_layer_list *expanded_target_list, const struct loader_layer_list *source_list) { VkResult res = VK_SUCCESS; - char *layer_env = loader_getenv(ENABLED_LAYERS_ENV, inst); + const enum layer_type_flags type_flags = VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER; // If the layer environment variable is present (i.e. VK_INSTANCE_LAYERS), we will always add it to the layer list. - if (layer_env != NULL) { - size_t layer_env_len = strlen(layer_env) + 1; + if (enabled_layers_env != NULL) { + size_t layer_env_len = strlen(enabled_layers_env) + 1; char *name = loader_stack_alloc(layer_env_len); if (name != NULL) { - loader_strncpy(name, layer_env_len, layer_env, layer_env_len); + loader_strncpy(name, layer_env_len, enabled_layers_env, layer_env_len); loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"", ENABLED_LAYERS_ENV, name); @@ -560,9 +560,5 @@ VkResult loader_add_environment_layers(struct loader_instance *inst, const enum out: - if (layer_env != NULL) { - loader_free_getenv(layer_env, inst); - } - return res; } diff --git a/loader/loader_environment.h b/loader/loader_environment.h index d120ec95c..8f657ddc9 100644 --- a/loader/loader_environment.h +++ b/loader/loader_environment.h @@ -49,7 +49,7 @@ VkResult parse_layers_disable_filter_environment_var(const struct loader_instanc struct loader_envvar_disable_layers_filter *disable_struct); VkResult parse_layer_environment_var_filters(const struct loader_instance *inst, struct loader_envvar_all_filters *layer_filters); bool check_name_matches_filter_environment_var(const char *name, const struct loader_envvar_filter *filter_struct); -VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags, +VkResult loader_add_environment_layers(struct loader_instance *inst, const char *enabled_layers_env, const struct loader_envvar_all_filters *filters, struct loader_pointer_layer_list *target_list, struct loader_pointer_layer_list *expanded_target_list, diff --git a/tests/loader_layer_tests.cpp b/tests/loader_layer_tests.cpp index a98850996..c21d847e8 100644 --- a/tests/loader_layer_tests.cpp +++ b/tests/loader_layer_tests.cpp @@ -1176,6 +1176,55 @@ TEST(ImplicitLayers, DuplicateLayersInVK_ADD_IMPLICIT_LAYER_PATH) { ASSERT_FALSE(env.debug_log.find("actually_layer_2")); } +TEST(ImplicitLayers, OrderedByVK_INSTANCE_LAYERS) { + FrameworkEnvironment env; + env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({}); + const char* implicit_layer_name = "VK_LAYER_implicit"; + env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{} + .set_name(implicit_layer_name) + + .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2) + .set_disable_environment("foo")), + "implicit_layer.json"); + const char* explicit_layer_name = "VK_LAYER_explicit"; + env.add_explicit_layer( + ManifestLayer{}.add_layer( + ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)), + "explicit_layer.json"); + // Only enable the explicit layer through the env-var + { + EnvVarWrapper env_var("VK_INSTANCE_LAYERS"); + env_var.add_to_list(explicit_layer_name); + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); + auto active_layers = inst.GetActiveLayers(inst.GetPhysDev(), 2); + ASSERT_TRUE(string_eq(active_layers.at(0).layerName, implicit_layer_name)); + ASSERT_TRUE(string_eq(active_layers.at(1).layerName, explicit_layer_name)); + } + // Enable both layers, implicit then explicit + { + EnvVarWrapper env_var("VK_INSTANCE_LAYERS"); + env_var.add_to_list(implicit_layer_name); + env_var.add_to_list(explicit_layer_name); + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); + auto active_layers = inst.GetActiveLayers(inst.GetPhysDev(), 2); + ASSERT_TRUE(string_eq(active_layers.at(0).layerName, implicit_layer_name)); + ASSERT_TRUE(string_eq(active_layers.at(1).layerName, explicit_layer_name)); + } + // Enable both layers, explicit then implicit + { + EnvVarWrapper env_var("VK_INSTANCE_LAYERS"); + env_var.add_to_list(explicit_layer_name); + env_var.add_to_list(implicit_layer_name); + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); + auto active_layers = inst.GetActiveLayers(inst.GetPhysDev(), 2); + ASSERT_TRUE(string_eq(active_layers.at(0).layerName, explicit_layer_name)); + ASSERT_TRUE(string_eq(active_layers.at(1).layerName, implicit_layer_name)); + } +} + // Meta layer which contains component layers that do not exist. TEST(MetaLayers, InvalidComponentLayer) { FrameworkEnvironment env;