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)">
DriverDriverDriverLoaderTerminator
@@ -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" />
EnvironmentEnabledEnabledExplicitLayersApplicationEnabledExplicitLayers
-
-
-
- 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;