Add VK_IMPLICIT_LAYER_APTH & VK_ADD_IMPLICIT_LAYER_PATH env-vars
authorCharles Giessen <charles@lunarg.com>
Mon, 9 Sep 2024 21:43:53 +0000 (16:43 -0500)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Fri, 13 Sep 2024 23:51:03 +0000 (17:51 -0600)
Add the environment variables VK_IMPLICIT_LAYER_PATH and
VK_ADD_IMPLICIT_LAYER_PATH to control implicit layer path searching,
mirroring the existing explicit layer only VK_LAYER_PATH and
VK_ADD_LAYER_PATH.

This fixes a gap in environment variable controls over the behavior
of the loader.

12 files changed:
docs/LoaderApplicationInterface.md
docs/LoaderInterfaceArchitecture.md
docs/LoaderLayerInterface.md
loader/loader.c
loader/vk_loader_platform.h
tests/framework/shim/shim_common.cpp
tests/framework/test_environment.cpp
tests/framework/test_environment.h
tests/loader_envvar_tests.cpp
tests/loader_layer_tests.cpp
tests/loader_settings_tests.cpp
tests/loader_testing_main.cpp

index d8454f1fb02c89d18df9ceab0813b2e0dab92a3f..c05f2f46bdc1495b0a63cd1631b7ae0f74cf04af 100644 (file)
@@ -472,18 +472,23 @@ This can be accomplished in one of two ways:
 [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)
@@ -493,9 +498,9 @@ for more details.
 
 #### 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
index 01da9da0f83448b36693485ff38e23ebb728529a..8df9fdc827da15364ef2f97fdf193ffc9c556c99 100644 (file)
@@ -430,6 +430,8 @@ These behaviors also result in ignoring certain environment variables, such as:
   * `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)
 
@@ -624,6 +626,31 @@ discovery.
         &nbsp;&nbsp;VK_ADD_LAYER_PATH=<br/>
         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path_a&gt;;&lt;path_b&gt;</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/>
+        &nbsp;&nbsp;VK_ADD_IMPLICIT_LAYER_PATH=<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path_a&gt;:&lt;path_b&gt;<br/><br/>
+        set<br/>
+        &nbsp;&nbsp;VK_ADD_IMPLICIT_LAYER_PATH=<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path_a&gt;;&lt;path_b&gt;</small>
+    </td>
   </tr>
   <tr>
     <td><small>
@@ -680,6 +707,27 @@ discovery.
         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path_a&gt;;&lt;path_b&gt;
     </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/>
+        &nbsp;&nbsp;VK_IMPLICIT_LAYER_PATH=<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path_a&gt;:&lt;path_b&gt;<br/><br/>
+        set<br/>
+        &nbsp;&nbsp;VK_IMPLICIT_LAYER_PATH=<br/>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;path_a&gt;;&lt;path_b&gt;
+    </small></td>
+  </tr>
   <tr>
     <td><small>
         <i>VK_LOADER_DEBUG</i>
index 08a417550879c9c65e41fb0612f0d109197abb4c..68d00d8479a59584ed0d8ed1100a3c9016085514 100644 (file)
@@ -256,8 +256,18 @@ of search folders and will therefore be searched first.
 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.
 
@@ -353,8 +363,21 @@ of search folders and will therefore be searched first.
 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.
 
@@ -367,10 +390,10 @@ See
 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
@@ -438,8 +461,8 @@ following:
 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.
@@ -548,8 +571,9 @@ override any disables supplied in `VK_LOADER_LAYERS_DISABLE`.
 
 ### 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
@@ -2696,9 +2720,9 @@ Android Vulkan documentation</a>.
   <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,
index 525334c7c73e63d87c0f95a98c43c603ea64d6f7..53304e7b2651b64651f2a6dc88afe49b3236cf95 100644 (file)
@@ -3148,6 +3148,8 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
 #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
@@ -3156,8 +3158,8 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
 #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
index a70ba71a8cb24577ea440646718b24cd9c5de244..367d0522d0ff3b8e9fa85111a8c827bc76c7ef41 100644 (file)
 // 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"
index df5c552736efd30adc93a4c972c870ca155e6d2a..c35f1c896bbe96c8fce95d7b4d5fc7c56ba75456 100644 (file)
@@ -219,6 +219,9 @@ void PlatformShim::redirect_category(std::filesystem::path const& new_path, Mani
     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);
 
index ddd989fc65e3ec68d5935523dbf1801103df0b75..1f8a02a2389550f775e99f5f0e1c7106120bfc2a 100644 (file)
@@ -400,6 +400,8 @@ FrameworkEnvironment::FrameworkEnvironment(FrameworkSettings const& settings) no
     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"));
@@ -579,20 +581,40 @@ void FrameworkEnvironment::add_layer_impl(TestLayerDetails layer_details, Manife
             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;
index 3167f03c8babc794b4358b1370676024abac7e7c..ff0f300594c1009753a9e8554016cf8735ace9bc 100644 (file)
@@ -621,11 +621,13 @@ enum class ManifestLocation {
     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 {
@@ -697,6 +699,8 @@ struct FrameworkEnvironment {
     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:
index 30824f5f9d28af599e353a4a14f4a5c461da3a07..ef0b1ec59eaac5e3734fc3264f284f071e8ea6f9 100644 (file)
@@ -382,6 +382,107 @@ TEST(EnvVarICDOverrideSetup, TestOnlyAddLayerEnvVar) {
     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
index e06d88ec75ff54b95866f486393d82ee5d4a3436..459edd9984b876ecd9c1ecf2b3c227e2696198a7 100644 (file)
@@ -1009,6 +1009,177 @@ TEST(ImplicitLayers, DuplicateLayers) {
     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;
index 4bb60cdde34392b12d9a225c7d715976b6b2acb5..3e0520d1a0cc245a46ec5c27cdb9f0726bba1311 100644 (file)
@@ -1086,6 +1086,185 @@ TEST(SettingsFile, EnvVarsWork_VK_ADD_LAYER_PATH) {
     }
 }
 
+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({});
index f6e3d71b385fcd9bcb3d22adfdd1ce4e524a8fb8..20af4f54c317321724ed366f67ccc242335019fa 100644 (file)
@@ -73,6 +73,8 @@ int main(int argc, char** argv) {
     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"};