[VkConfig](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
tool shipped with the Vulkan SDK.
2. Directing the loader to look for layers in specific files and/or folders by using the
-`VK_LAYER_PATH` environment variable.
+`VK_LAYER_PATH` and/or `VK_IMPLICIT_LAYER_PATH` environment variables.
-The `VK_LAYER_PATH` environment variable can contain multiple paths separated by
-the operating-system specific path separator.
+The `VK_LAYER_PATH` and `VK_IMPLICIT_LAYER_PATH` environment variables can contain multiple
+paths separated by the operating-system specific path separator.
On Windows, this is a semicolon (`;`), while on Linux and macOS it is a colon
(`:`).
If `VK_LAYER_PATH` exists, the files and/or folders listed will be scanned for explicit
layer manifest files.
Implicit layer discovery is unaffected by this environment variable.
-Each directory listed should be the full pathname of a folder containing layer
-manifest files.
+
+If `VK_IMPLICIT_LAYER_PATH` exists, the files and/or folders listed will be scanned for
+implicit layer manifest files.
+Explicit layer discovery is unaffected by this environment variable.
+
+Each directory listed in `VK_LAYER_PATH` and `VK_IMPLICIT_LAYER_PATH` should be the full
+pathname of a folder containing layer manifest files.
See the
[Table of Debug Environment Variables](LoaderInterfaceArchitecture.md#table-of-debug-environment-variables)
#### Exception for Elevated Privileges
-For security reasons, `VK_LAYER_PATH` is ignored if running with elevated
-privileges.
-Because of this, `VK_LAYER_PATH` can only be used for applications that do not
+For security reasons, `VK_LAYER_PATH` and `VK_IMPLICIT_LAYER_PATH` are ignored if running
+with elevated privileges.
+Because of this, the environment variables can only be used for applications that do not
use elevated privileges.
For more information see
* `VK_ADD_DRIVER_FILES`
* `VK_LAYER_PATH`
* `VK_ADD_LAYER_PATH`
+ * `VK_IMPLICIT_LAYER_PATH`
+ * `VK_ADD_IMPLICIT_LAYER_PATH`
* `XDG_CONFIG_HOME` (Linux/Mac-specific)
* `XDG_DATA_HOME` (Linux/Mac-specific)
VK_ADD_LAYER_PATH=<br/>
<path_a>;<path_b></small>
</td>
+ </tr>
+ <tr>
+ <td><small>
+ <i>VK_ADD_IMPLICIT_LAYER_PATH</i>
+ </small></td>
+ <td><small>
+ Provide a list of additional paths that the loader will use to search
+ for implicit layers in addition to the loader's standard layer library
+ search paths when looking for layer manifest files.
+ The paths will be added first, prior to the list of folders that would
+ be searched normally.
+ </small></td>
+ <td><small>
+ <a href="#elevated-privilege-caveats">
+ Ignored when running Vulkan application with elevated privileges.
+ </a>
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_ADD_IMPLICIT_LAYER_PATH=<br/>
+ <path_a>:<path_b><br/><br/>
+ set<br/>
+ VK_ADD_IMPLICIT_LAYER_PATH=<br/>
+ <path_a>;<path_b></small>
+ </td>
</tr>
<tr>
<td><small>
<path_a>;<path_b>
</small></td>
</tr>
+ <tr>
+ <td><small>
+ <i>VK_IMPLICIT_LAYER_PATH</i></small></td>
+ <td><small>
+ Override the loader's standard implicit layer search paths and use the
+ provided delimited files and/or folders to locate layer manifest files.
+ </small></td>
+ <td><small>
+ <a href="#elevated-privilege-caveats">
+ Ignored when running Vulkan application with elevated privileges.
+ </a>
+ </small></td>
+ <td><small>
+ export<br/>
+ VK_IMPLICIT_LAYER_PATH=<br/>
+ <path_a>:<path_b><br/><br/>
+ set<br/>
+ VK_IMPLICIT_LAYER_PATH=<br/>
+ <path_a>;<path_b>
+ </small></td>
+ </tr>
<tr>
<td><small>
<i>VK_LOADER_DEBUG</i>
If `VK_LAYER_PATH` is present, then `VK_ADD_LAYER_PATH` will not be used by the
loader and any values will be ignored.
-For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
-if running with elevated privileges.
+If `VK_IMPLICIT_LAYER_PATH` is defined, then the loader will look at the paths
+defined by that variable for implicit layer manifest files instead of using the
+information provided by the implicit layer registry keys.
+
+If `VK_ADD_IMPLICIT_LAYER_PATH` is defined, then the loader will look at the provided
+paths for implicit layer manifest files in addition to using the information
+provided by the implicit layer registry keys.
+The paths provided by `VK_ADD_IMPLICIT_LAYER_PATH` are added before the standard list
+of search folders and will therefore be searched first.
+
+For security reasons, `VK_LAYER_PATH`, `VK_ADD_LAYER_PATH`, `VK_IMPLICIT_LAYER_PATH`,
+and `VK_ADD_IMPLICIT_LAYER_PATH` are ignored if running with elevated privileges.
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
for more info.
If `VK_LAYER_PATH` is present, then `VK_ADD_LAYER_PATH` will not be used by the
loader and any values will be ignored.
-For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
-if running with elevated privileges.
+If `VK_IMPLICIT_LAYER_PATH` is defined, then the loader will look at the paths
+defined by that variable for implicit layer manifest files instead of using the
+information provided by the standard implicit layer paths mentioned above.
+
+If `VK_ADD_IMPLICIT_LAYER_PATH` is defined, then the loader will look at the
+provided paths for implicit layer manifest files in addition to using the
+information provided by the standard implicit layer paths mentioned above.
+The paths provided by `VK_ADD_IMPLICIT_LAYER_PATH` are added before the standard
+list of search folders and will therefore be searched first.
+
+If `VK_IMPLICIT_LAYER_PATH` is present, then `VK_ADD_IMPLICIT_LAYER_PATH` will
+not be used by the loader and any values will be ignored.
+
+For security reasons, `VK_LAYER_PATH`, `VK_ADD_LAYER_PATH`, `VK_IMPLICIT_LAYER_PATH`,
+and `VK_ADD_IMPLICIT_LAYER_PATH` are ignored if running with elevated privileges.
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
for more info.
in the [LoaderApplicationInterface.md document](LoaderApplicationInterface.md)
for more information on this.
-It is also important to note that while both `VK_LAYER_PATH` and
-`VK_ADD_LAYER_PATH` will point the loader paths to search for finding the
-manifest files, it does not guarantee the library files mentioned by the
-manifest will immediately be found.
+It is also important to note that while `VK_LAYER_PATH`, `VK_ADD_LAYER_PATH`,
+`VK_IMPLICIT_LAYER_PATH`, and `VK_ADD_IMPLICIT_LAYER_PATH` will point the
+loader at paths to search for finding the manifest files, it does not guarantee
+the library files mentioned by the manifest will immediately be found.
Often, the layer manifest file will point to the library file using a relative
or absolute path.
When a relative or absolute path is used, the loader can typically find the
The loader supports filter environment variables which can forcibly enable and
disable known layers.
Known layers are those that are already found by the loader taking into account
-default search paths and other environment variables
-(like `VK_LAYER_PATH` or `VK_ADD_LAYER_PATH`).
+default search paths and environment variables `VK_LAYER_PATH`, `VK_ADD_LAYER_PATH`,
+`VK_IMPLICIT_LAYER_PATH`, and `VK_ADD_IMPLICIT_LAYER_PATH`.
The filter variables will be compared against the layer name provided in the
layer's manifest file.
### Exception for Elevated Privileges
-For security reasons, `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored if
-running the Vulkan application with elevated privileges.
+For security reasons, `VK_LAYER_PATH`, `VK_ADD_LAYER_PATH`, `VK_IMPLICIT_LAYER_PATH`
+and `VK_ADD_IMPLICIT_LAYER_PATH` are ignored if running the Vulkan application
+with elevated privileges.
This is because they may insert new libraries into the executable process that
are not normally found by the loader.
Because of this, these environment variables can only be used for applications
<tr>
<td><small><b>LLP_LOADER_13</b></small></td>
<td>A loader <b>must</b> not load from user-defined paths (including the
- use of either <i>VK_LAYER_PATH</i> or <i>VK_ADD_LAYER_PATH</i>
- environment variables) when running elevated (Administrator/Super-user)
- applications.<br/>
+ use of <i>VK_LAYER_PATH</i>, <i>VK_ADD_LAYER_PATH</i>, <i>VK_IMPLICIT_LAYER_PATH</i>,
+ or <i>VK_ADD_IMPLICIT_LAYER_PATH</i> environment variables) when running
+ elevated (Administrator/Super-user) applications.<br/>
<b>This is for security reasons.</b>
</td>
<td>The behavior is undefined and may result in computer security lapses,
#endif
break;
case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER:
+ override_env = loader_secure_getenv(VK_IMPLICIT_LAYER_PATH_ENV_VAR, inst);
+ additional_env = loader_secure_getenv(VK_ADDITIONAL_IMPLICIT_LAYER_PATH_ENV_VAR, inst);
#if COMMON_UNIX_PLATFORMS
relative_location = VK_ILAYERS_INFO_RELATIVE_DIR;
#endif
#endif
break;
case LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER:
- override_env = loader_secure_getenv(VK_LAYER_PATH_ENV_VAR, inst);
- additional_env = loader_secure_getenv(VK_ADDITIONAL_LAYER_PATH_ENV_VAR, inst);
+ override_env = loader_secure_getenv(VK_EXPLICIT_LAYER_PATH_ENV_VAR, inst);
+ additional_env = loader_secure_getenv(VK_ADDITIONAL_EXPLICIT_LAYER_PATH_ENV_VAR, inst);
#if COMMON_UNIX_PLATFORMS
relative_location = VK_ELAYERS_INFO_RELATIVE_DIR;
#endif
// Environment Variable information
#define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES" // Deprecated in v1.3.207 loader
#define VK_DRIVER_FILES_ENV_VAR "VK_DRIVER_FILES"
-#define VK_LAYER_PATH_ENV_VAR "VK_LAYER_PATH"
+#define VK_EXPLICIT_LAYER_PATH_ENV_VAR "VK_LAYER_PATH"
// Support added in v1.3.207 loader
#define VK_ADDITIONAL_DRIVER_FILES_ENV_VAR "VK_ADD_DRIVER_FILES"
-#define VK_ADDITIONAL_LAYER_PATH_ENV_VAR "VK_ADD_LAYER_PATH"
+#define VK_ADDITIONAL_EXPLICIT_LAYER_PATH_ENV_VAR "VK_ADD_LAYER_PATH"
// Support added in v1.3.234 loader
#define VK_LAYERS_ENABLE_ENV_VAR "VK_LOADER_LAYERS_ENABLE"
#define VK_LAYERS_DISABLE_ENV_VAR "VK_LOADER_LAYERS_DISABLE"
#define VK_LOADER_DISABLE_ALL_LAYERS_VAR_3 "**"
#define VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR "~implicit~"
#define VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR "~explicit~"
+// Support added in v1.3.295 loader
+#define VK_IMPLICIT_LAYER_PATH_ENV_VAR "VK_IMPLICIT_LAYER_PATH"
+#define VK_ADDITIONAL_IMPLICIT_LAYER_PATH_ENV_VAR "VK_ADD_IMPLICIT_LAYER_PATH"
// Override layer information
#define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
if (category == ManifestCategory::explicit_layer) {
parse_and_add_env_var_override(paths, get_env_var("VK_LAYER_PATH", false)); // don't report failure
}
+ if (category == ManifestCategory::implicit_layer) {
+ parse_and_add_env_var_override(paths, get_env_var("VK_IMPLICIT_LAYER_PATH", false)); // don't report failure
+ }
parse_and_add_env_var_override(paths, FALLBACK_DATA_DIRS);
parse_and_add_env_var_override(paths, FALLBACK_CONFIG_DIRS);
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_env_var_layer_folder"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_add_env_var_layer_folder"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("implicit_layer_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("implicit_env_var_layer_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("implicit_add_env_var_layer_manifests"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("override_layer_manifests"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("app_package_manifests"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("macos_bundle"));
if (category == ManifestCategory::implicit_layer) fs_ptr = &get_folder(ManifestLocation::implicit_layer);
break;
case (ManifestDiscoveryType::env_var):
- fs_ptr = &get_folder(ManifestLocation::explicit_layer_env_var);
- if (layer_details.is_dir) {
- env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location()));
- } else {
- env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location() / layer_details.json_name));
+ if (category == ManifestCategory::explicit_layer) {
+ fs_ptr = &get_folder(ManifestLocation::explicit_layer_env_var);
+ if (layer_details.is_dir) {
+ env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location()));
+ } else {
+ env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location() / layer_details.json_name));
+ }
+ }
+ if (category == ManifestCategory::implicit_layer) {
+ fs_ptr = &get_folder(ManifestLocation::implicit_layer_env_var);
+ if (layer_details.is_dir) {
+ env_var_vk_implicit_layer_paths.add_to_list(narrow(fs_ptr->location()));
+ } else {
+ env_var_vk_implicit_layer_paths.add_to_list(narrow(fs_ptr->location() / layer_details.json_name));
+ }
}
platform_shim->add_known_path(fs_ptr->location());
break;
case (ManifestDiscoveryType::add_env_var):
- fs_ptr = &get_folder(ManifestLocation::explicit_layer_add_env_var);
- if (layer_details.is_dir) {
- add_env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location()));
- } else {
- add_env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location() / layer_details.json_name));
+ if (category == ManifestCategory::explicit_layer) {
+ fs_ptr = &get_folder(ManifestLocation::explicit_layer_add_env_var);
+ if (layer_details.is_dir) {
+ add_env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location()));
+ } else {
+ add_env_var_vk_layer_paths.add_to_list(narrow(fs_ptr->location() / layer_details.json_name));
+ }
+ }
+ if (category == ManifestCategory::implicit_layer) {
+ fs_ptr = &get_folder(ManifestLocation::implicit_layer_add_env_var);
+ if (layer_details.is_dir) {
+ add_env_var_vk_implicit_layer_paths.add_to_list(narrow(fs_ptr->location()));
+ } else {
+ add_env_var_vk_implicit_layer_paths.add_to_list(narrow(fs_ptr->location() / layer_details.json_name));
+ }
}
platform_shim->add_known_path(fs_ptr->location());
break;
explicit_layer_env_var = 4,
explicit_layer_add_env_var = 5,
implicit_layer = 6,
- override_layer = 7,
- windows_app_package = 8,
- macos_bundle = 9,
- unsecured_location = 10,
- settings_location = 11,
+ implicit_layer_env_var = 7,
+ implicit_layer_add_env_var = 8,
+ override_layer = 9,
+ windows_app_package = 10,
+ macos_bundle = 11,
+ unsecured_location = 12,
+ settings_location = 13,
};
struct FrameworkSettings {
EnvVarWrapper add_env_var_vk_icd_filenames{"VK_ADD_DRIVER_FILES"};
EnvVarWrapper env_var_vk_layer_paths{"VK_LAYER_PATH"};
EnvVarWrapper add_env_var_vk_layer_paths{"VK_ADD_LAYER_PATH"};
+ EnvVarWrapper env_var_vk_implicit_layer_paths{"VK_IMPLICIT_LAYER_PATH"};
+ EnvVarWrapper add_env_var_vk_implicit_layer_paths{"VK_ADD_IMPLICIT_LAYER_PATH"};
LoaderSettings loader_settings; // the current settings written to disk
private:
env.platform_shim->set_elevated_privilege(false);
}
+// Test VK_IMPLICIT_LAYER_PATH environment variable
+TEST(EnvVarICDOverrideSetup, TestOnlyImplicitLayerEnvVar) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device("physical_device_0");
+ env.platform_shim->redirect_path("/tmp/carol", env.get_folder(ManifestLocation::implicit_layer_env_var).location());
+
+ const char* layer_name = "TestLayer";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(layer_name)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DISABLE_ENV")),
+ "test_layer.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var));
+
+ // Now set up a layer path that includes default and user-specified locations,
+ // so that the test app can find them. Include some badly specified elements as well.
+ // Need to redirect the 'home' directory
+ std::filesystem::path HOME = "/home/fake_home";
+ EnvVarWrapper home_env_var{"HOME", HOME};
+ std::string vk_implicit_layer_path = ":/tmp/carol::::/:";
+ vk_implicit_layer_path += (HOME / "/ with spaces/:::::/tandy:");
+ EnvVarWrapper implicit_layer_path_env_var{"VK_IMPLICIT_LAYER_PATH", vk_implicit_layer_path};
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ auto active_layers1 = inst1.GetActiveLayers(inst1.GetPhysDev(), 1);
+ ASSERT_TRUE(string_eq(active_layers1.at(0).layerName, layer_name));
+
+ // look for VK_IMPLICIT_LAYER_PATHS
+ EXPECT_TRUE(env.debug_log.find("/tmp/carol"));
+ EXPECT_TRUE(env.debug_log.find("/tandy"));
+ EXPECT_TRUE(env.debug_log.find((HOME / "/ with spaces/")));
+
+ env.debug_log.clear();
+
+ env.platform_shim->set_elevated_privilege(true);
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ auto active_layers2 = inst2.GetActiveLayers(inst2.GetPhysDev(), 0);
+ ASSERT_TRUE(active_layers2.empty());
+
+ EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
+
+ env.platform_shim->set_elevated_privilege(false);
+}
+
+// Test VK_ADD_IMPLICIT_LAYER_PATH environment variable
+TEST(EnvVarICDOverrideSetup, TestOnlyAddImplicitLayerEnvVar) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device("physical_device_0");
+ env.platform_shim->redirect_path("/tmp/carol", env.get_folder(ManifestLocation::implicit_layer_add_env_var).location());
+
+ const char* layer_name = "TestLayer";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(layer_name)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("DISABLE_ENV")),
+ "test_layer.json")
+ .set_discovery_type(ManifestDiscoveryType::add_env_var));
+
+ // Set up a layer path that includes default and user-specified locations,
+ // so that the test app can find them. Include some badly specified elements as well.
+ // Need to redirect the 'home' directory
+ std::filesystem::path HOME = "/home/fake_home";
+ EnvVarWrapper home_env_var{"HOME", HOME};
+ std::string vk_add_implicit_layer_path = ":/tmp/carol::::/:";
+ vk_add_implicit_layer_path += (HOME / "/ with spaces/:::::/tandy:");
+ EnvVarWrapper add_implicit_layer_path_env_var{"VK_ADD_LAYER_PATH", vk_add_implicit_layer_path};
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ auto active_layers1 = inst1.GetActiveLayers(inst1.GetPhysDev(), 1);
+ ASSERT_TRUE(string_eq(active_layers1.at(0).layerName, layer_name));
+
+ // look for VK_ADD_IMPLICIT_LAYER_PATHS
+ EXPECT_TRUE(env.debug_log.find("/tmp/carol"));
+ EXPECT_TRUE(env.debug_log.find("/tandy"));
+ EXPECT_TRUE(env.debug_log.find((HOME / "/ with spaces/")));
+
+ env.debug_log.clear();
+
+ env.platform_shim->set_elevated_privilege(true);
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ auto active_layers2 = inst2.GetActiveLayers(inst2.GetPhysDev(), 0);
+ ASSERT_TRUE(active_layers2.empty());
+
+ EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
+
+ env.platform_shim->set_elevated_privilege(false);
+}
+
#endif
// Test that the driver filter select will only enable driver manifest files that match the filter
ASSERT_FALSE(env.debug_log.find("actually_layer_2"));
}
+TEST(ImplicitLayers, VkImplicitLayerPathEnvVar) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
+
+ // verify layer loads successfully when setting VK_IMPLICIT_LAYER_PATH to a full filepath
+ const char* regular_layer_name_1 = "VK_LAYER_RegularLayer1";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(regular_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Yikes")),
+ "regular_layer_1.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var)
+ .set_is_dir(false));
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.CheckCreate();
+ auto layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
+ EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name_1));
+}
+
+TEST(ImplicitLayers, VkImplicitLayerPathEnvVarContainsMultipleFilePaths) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
+
+ // verify layers load successfully when setting VK_IMPLICIT_LAYER_PATH to multiple full filepaths
+ const char* regular_layer_name_1 = "VK_LAYER_RegularLayer1";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(regular_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Yikes")),
+ "regular_layer_1.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var)
+ .set_is_dir(false));
+
+ const char* regular_layer_name_2 = "VK_LAYER_RegularLayer2";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(regular_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Yikes")),
+ "regular_layer_2.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var)
+ .set_is_dir(false));
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.CheckCreate();
+ auto layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 2);
+ EXPECT_TRUE(check_permutation({regular_layer_name_1, regular_layer_name_2}, layer_props));
+}
+
+TEST(ImplicitLayers, VkImplicitLayerPathEnvVarIsDirectory) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
+
+ // verify layers load successfully when setting VK_IMPLICIT_LAYER_PATH to a directory
+ const char* regular_layer_name_1 = "VK_LAYER_RegularLayer1";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(regular_layer_name_1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Yikes")),
+ "regular_layer_1.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var));
+
+ const char* regular_layer_name_2 = "VK_LAYER_RegularLayer2";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(regular_layer_name_2)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Yikes")),
+ "regular_layer_2.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var));
+
+ InstWrapper inst(env.vulkan_functions);
+ inst.CheckCreate();
+ auto layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 2);
+ EXPECT_TRUE(check_permutation({regular_layer_name_1, regular_layer_name_2}, layer_props));
+}
+
+// Test to make sure order layers are found in VK_IMPLICIT_LAYER_PATH is what decides which layer is loaded
+TEST(ImplicitLayers, DuplicateLayersInVkImplicitLayerPath) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
+
+ const char* layer_name = "VK_LAYER_RegularLayer1";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(layer_name)
+ .set_description("actually_layer_1")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Boo!")),
+ "layer.json")
+ .set_discovery_type(ManifestDiscoveryType::env_var)
+ .set_is_dir(true));
+ auto& layer1 = env.get_test_layer(0);
+ layer1.set_description("actually_layer_1");
+
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(layer_name)
+ .set_description("actually_layer_2")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Ah!")),
+ "layer.json")
+ // putting it in a separate folder then manually adding the folder to VK_IMPLICIT_LAYER_PATH
+ .set_discovery_type(ManifestDiscoveryType::override_folder)
+ .set_is_dir(true));
+ auto& layer2 = env.get_test_layer(1);
+ layer2.set_description("actually_layer_2");
+ env.env_var_vk_implicit_layer_paths.add_to_list(env.get_folder(ManifestLocation::override_layer).location().string());
+
+ auto layer_props = env.GetLayerProperties(2);
+ ASSERT_TRUE(string_eq(layer_name, layer_props[0].layerName));
+ ASSERT_TRUE(string_eq(layer1.description.c_str(), layer_props[0].description));
+ ASSERT_TRUE(string_eq(layer_name, layer_props[1].layerName));
+ ASSERT_TRUE(string_eq(layer2.description.c_str(), layer_props[1].description));
+
+ EnvVarWrapper inst_layers_env_var{"VK_INSTANCE_LAYERS"};
+ inst_layers_env_var.add_to_list(layer_name);
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.CheckCreate();
+
+ // Expect the first layer added to be found
+ auto enabled_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
+ ASSERT_TRUE(string_eq(layer_name, enabled_layer_props[0].layerName));
+ ASSERT_TRUE(string_eq(layer1.description.c_str(), enabled_layer_props[0].description));
+}
+
+TEST(ImplicitLayers, DuplicateLayersInVK_ADD_IMPLICIT_LAYER_PATH) {
+ FrameworkEnvironment env;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
+
+ const char* same_layer_name_1 = "VK_LAYER_RegularLayer1";
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(same_layer_name_1)
+ .set_description("actually_layer_1")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Red")),
+ "regular_layer_1.json")
+ // use override folder as just a folder and manually set the VK_ADD_IMPLICIT_LAYER_PATH env-var to it
+ .set_discovery_type(ManifestDiscoveryType::override_folder)
+ .set_is_dir(true));
+ auto& layer1 = env.get_test_layer(0);
+ layer1.set_description("actually_layer_1");
+ layer1.set_make_spurious_log_in_create_instance("actually_layer_1");
+ env.add_env_var_vk_implicit_layer_paths.add_to_list(narrow(env.get_folder(ManifestLocation::override_layer).location()));
+
+ env.add_implicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(same_layer_name_1)
+ .set_description("actually_layer_2")
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Blue")),
+ "regular_layer_1.json")
+ .set_discovery_type(ManifestDiscoveryType::add_env_var)
+ .set_is_dir(true));
+ auto& layer2 = env.get_test_layer(1);
+ layer2.set_description("actually_layer_2");
+ layer2.set_make_spurious_log_in_create_instance("actually_layer_2");
+
+ auto layer_props = env.GetLayerProperties(2);
+ ASSERT_TRUE(string_eq(same_layer_name_1, layer_props[0].layerName));
+ ASSERT_TRUE(string_eq(same_layer_name_1, layer_props[1].layerName));
+ ASSERT_TRUE(string_eq(layer1.description.c_str(), layer_props[0].description));
+ ASSERT_TRUE(string_eq(layer2.description.c_str(), layer_props[1].description));
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ auto enabled_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
+ ASSERT_TRUE(string_eq(same_layer_name_1, enabled_layer_props.at(0).layerName));
+ ASSERT_TRUE(string_eq(layer1.description.c_str(), enabled_layer_props.at(0).description));
+ ASSERT_TRUE(env.debug_log.find("actually_layer_1"));
+ ASSERT_FALSE(env.debug_log.find("actually_layer_2"));
+}
+
// Meta layer which contains component layers that do not exist.
TEST(MetaLayers, InvalidComponentLayer) {
FrameworkEnvironment env;
}
}
+TEST(SettingsFile, EnvVarsWork_VK_IMPLICIT_LAYER_PATH) {
+ 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(TestLayerDetails{
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "explicit_test_layer1.json"}
+ .set_discovery_type(ManifestDiscoveryType::env_var));
+
+ const char* implicit_layer_name1 = "VK_LAYER_Implicit_TestLayer1";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Domierigato")),
+ "implicit_layer1.json");
+ const char* settings_layer_path = "VK_LAYER_Regular_TestLayer2";
+ env.add_implicit_layer(TestLayerDetails{ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(settings_layer_path)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Domierigato")),
+ "implicit_test_layer2.json"});
+
+ {
+ auto layer_props = env.GetLayerProperties(3);
+ ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layer_props.at(1).layerName, settings_layer_path));
+ ASSERT_TRUE(string_eq(layer_props.at(2).layerName, explicit_layer_name1));
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, settings_layer_path));
+ }
+ {
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.create_info.add_layer(explicit_layer_name1);
+ inst.CheckCreate();
+ ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, settings_layer_path));
+ ASSERT_TRUE(string_eq(layers.at(2).layerName, explicit_layer_name1));
+ }
+ env.update_loader_settings(env.loader_settings.add_app_specific_setting(
+ AppSpecificSettings{}
+ .add_stderr_log_filter("all")
+ .add_layer_configuration(LoaderSettingsLayerConfiguration{}
+ .set_name(settings_layer_path)
+ .set_control("on")
+ .set_path(env.get_shimmed_layer_manifest_path(2))
+ .set_treat_as_implicit_manifest(true))
+ .add_layer_configuration(LoaderSettingsLayerConfiguration{}.set_control("unordered_layer_location"))));
+ {
+ auto layer_props = env.GetLayerProperties(3);
+ ASSERT_TRUE(string_eq(layer_props.at(0).layerName, settings_layer_path));
+ ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layer_props.at(2).layerName, explicit_layer_name1));
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, settings_layer_path));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name1));
+ }
+ {
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.create_info.add_layer(explicit_layer_name1);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, settings_layer_path));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(2).layerName, explicit_layer_name1));
+ }
+}
+
+TEST(SettingsFile, EnvVarsWork_VK_ADD_IMPLICIT_LAYER_PATH) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
+
+ const char* implicit_layer_name1 = "VK_LAYER_Implicit_TestLayer1";
+ env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(implicit_layer_name1)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("Domierigato")),
+ "implicit_layer1.json");
+ const char* explicit_layer_name1 = "VK_LAYER_Regular_TestLayer1";
+ 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_layer1.json"}
+ .set_discovery_type(ManifestDiscoveryType::add_env_var));
+ const char* settings_layer_name = "VK_LAYER_Regular_TestLayer2";
+ env.add_implicit_layer(TestLayerDetails{ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
+ .set_name(settings_layer_name)
+ .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
+ .set_disable_environment("gozaimasu")),
+ "implicit_test_layer2.json"});
+
+ {
+ auto layer_props = env.GetLayerProperties(3);
+ ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layer_props.at(1).layerName, settings_layer_name));
+ ASSERT_TRUE(string_eq(layer_props.at(2).layerName, explicit_layer_name1));
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, settings_layer_name));
+ }
+ {
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.create_info.add_layer(explicit_layer_name1);
+ inst.CheckCreate();
+ ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, settings_layer_name));
+ ASSERT_TRUE(string_eq(layers.at(2).layerName, explicit_layer_name1));
+ }
+
+ env.update_loader_settings(env.loader_settings.add_app_specific_setting(
+ AppSpecificSettings{}
+ .add_stderr_log_filter("all")
+ .add_layer_configuration(LoaderSettingsLayerConfiguration{}
+ .set_name(explicit_layer_name1)
+ .set_control("on")
+ .set_path(env.get_shimmed_layer_manifest_path(1)))
+ .add_layer_configuration(LoaderSettingsLayerConfiguration{}
+ .set_name(settings_layer_name)
+ .set_control("on")
+ .set_path(env.get_shimmed_layer_manifest_path(2))
+ .set_treat_as_implicit_manifest(true))
+ .add_layer_configuration(LoaderSettingsLayerConfiguration{}
+ .set_name(implicit_layer_name1)
+ .set_control("on")
+ .set_path(env.get_shimmed_layer_manifest_path(0))
+ .set_treat_as_implicit_manifest(true))));
+ {
+ auto layer_props = env.GetLayerProperties(3);
+ ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name1));
+ ASSERT_TRUE(string_eq(layer_props.at(1).layerName, settings_layer_name));
+ ASSERT_TRUE(string_eq(layer_props.at(2).layerName, implicit_layer_name1));
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, settings_layer_name));
+ ASSERT_TRUE(string_eq(layers.at(2).layerName, implicit_layer_name1));
+ }
+ {
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.create_info.add_layer(explicit_layer_name1);
+ inst.CheckCreate();
+ ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
+ auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
+ ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name1));
+ ASSERT_TRUE(string_eq(layers.at(1).layerName, settings_layer_name));
+ ASSERT_TRUE(string_eq(layers.at(2).layerName, implicit_layer_name1));
+ }
+}
+
TEST(SettingsFile, EnvVarsWork_VK_INSTANCE_LAYERS) {
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
EnvVarWrapper vk_add_driver_files_env_var{"VK_ADD_DRIVER_FILES"};
EnvVarWrapper vk_layer_path_env_var{"VK_LAYER_PATH"};
EnvVarWrapper vk_add_layer_path_env_var{"VK_ADD_LAYER_PATH"};
+ EnvVarWrapper vk_implicit_layer_path_env_var{"VK_IMPLICIT_LAYER_PATH"};
+ EnvVarWrapper vk_add_implicit_layer_path_env_var{"VK_ADD_IMPLICIT_LAYER_PATH"};
EnvVarWrapper vk_instance_layers_env_var{"VK_INSTANCE_LAYERS"};
EnvVarWrapper vk_loader_drivers_select_env_var{"VK_LOADER_DRIVERS_SELECT"};
EnvVarWrapper vk_loader_drivers_disable_env_var{"VK_LOADER_DRIVERS_DISABLE"};