1/*
2 * Copyright (c) 2023 The Khronos Group Inc.
3 * Copyright (c) 2023 Valve Corporation
4 * Copyright (c) 2023 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and/or associated documentation files (the "Materials"), to
8 * deal in the Materials without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Materials, and to permit persons to whom the Materials are
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice(s) and this permission notice shall be included in
14 * all copies or substantial portions of the Materials.
15 *
16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 *
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23 * USE OR OTHER DEALINGS IN THE MATERIALS.
24 *
25 * Author: Charles Giessen <charles@lunarg.com>
26 */
27
28#include "test_environment.h"
29
30std::string get_settings_location_log_message([[maybe_unused]] FrameworkEnvironment const& env,
31                                              [[maybe_unused]] bool use_secure = false) {
32    std::string s = "Using layer configurations found in loader settings from ";
33#if defined(WIN32)
34    return s + env.get_folder(ManifestLocation::settings_location).location().str() + "\\vk_loader_settings.json";
35#elif COMMON_UNIX_PLATFORMS
36    if (use_secure)
37        return s + "/etc/vulkan/loader_settings.d/vk_loader_settings.json";
38    else
39        return s + "/home/fake_home/.local/share/vulkan/loader_settings.d/vk_loader_settings.json";
40#endif
41}
42
43// Make sure settings layer is found and that a layer defined in it is loaded
44TEST(SettingsFile, FileExist) {
45    FrameworkEnvironment env{};
46    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
47    const char* regular_layer_name = "VK_LAYER_TestLayer_0";
48    env.add_explicit_layer(TestLayerDetails{
49        ManifestLayer{}.add_layer(
50            ManifestLayer::LayerDescription{}.set_name(regular_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
51        "regular_test_layer.json"}
52                               .set_discovery_type(ManifestDiscoveryType::override_folder));
53    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
54        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
55            LoaderSettingsLayerConfiguration{}
56                .set_name(regular_layer_name)
57                .set_path(env.get_shimmed_layer_manifest_path().str())
58                .set_control("on"))));
59    {
60        auto layer_props = env.GetLayerProperties(1);
61        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name));
62
63        InstWrapper inst{env.vulkan_functions};
64        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
65        inst.CheckCreate();
66
67        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
68        auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
69        EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, regular_layer_name));
70    }
71}
72
73// Make sure that if the settings file is in a user local path, that it isn't used when running with elevated privileges
74TEST(SettingsFile, SettingsInUnsecuredLocation) {
75    FrameworkEnvironment env{};
76    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
77    const char* regular_layer_name = "VK_LAYER_TestLayer_0";
78    env.add_explicit_layer(TestLayerDetails{
79        ManifestLayer{}.add_layer(
80            ManifestLayer::LayerDescription{}.set_name(regular_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
81        "regular_test_layer.json"}
82                               .set_discovery_type(ManifestDiscoveryType::override_folder));
83    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
84        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
85            LoaderSettingsLayerConfiguration{}
86                .set_name(regular_layer_name)
87                .set_path(env.get_layer_manifest_path().str())
88                .set_control("on"))));
89    {
90        auto layer_props = env.GetLayerProperties(1);
91        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name));
92
93        InstWrapper inst{env.vulkan_functions};
94        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
95        inst.CheckCreate();
96
97        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
98        env.debug_log.clear();
99        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
100        ASSERT_TRUE(string_eq(layers.at(0).layerName, regular_layer_name));
101    }
102    env.platform_shim->set_elevated_privilege(true);
103    {
104        ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
105
106        InstWrapper inst{env.vulkan_functions};
107        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
108        inst.CheckCreate();
109
110        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
111        ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
112    }
113}
114
115TEST(SettingsFile, SettingsInSecuredLocation) {
116    FrameworkEnvironment env{FrameworkSettings{}.set_secure_loader_settings(true)};
117    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
118    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
119    const char* regular_layer_name = "VK_LAYER_TestLayer_0";
120    env.add_explicit_layer(TestLayerDetails{
121        ManifestLayer{}.add_layer(
122            ManifestLayer::LayerDescription{}.set_name(regular_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
123        "regular_test_layer.json"}
124                               .set_discovery_type(ManifestDiscoveryType::override_folder));
125    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
126        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
127            LoaderSettingsLayerConfiguration{}
128                .set_name(regular_layer_name)
129                .set_path(env.get_layer_manifest_path().str())
130                .set_control("on"))));
131    {
132        auto layer_props = env.GetLayerProperties(1);
133        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name));
134
135        InstWrapper inst{env.vulkan_functions};
136        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
137        inst.CheckCreate();
138
139        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env, true)));
140        env.debug_log.clear();
141        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
142        ASSERT_TRUE(string_eq(layers.at(0).layerName, regular_layer_name));
143    }
144    env.platform_shim->set_elevated_privilege(true);
145    {
146        auto layer_props = env.GetLayerProperties(1);
147        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name));
148
149        InstWrapper inst{env.vulkan_functions};
150        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
151        inst.CheckCreate();
152
153        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env, true)));
154        env.debug_log.clear();
155        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
156        ASSERT_TRUE(string_eq(layers.at(0).layerName, regular_layer_name));
157    }
158}
159
160// Make sure settings file can have multiple sets of settings
161TEST(SettingsFile, SupportsMultipleSetingsSimultaneously) {
162    FrameworkEnvironment env{};
163    const char* app_specific_layer_name = "VK_LAYER_TestLayer_0";
164    env.add_explicit_layer(TestLayerDetails{
165        ManifestLayer{}.add_layer(
166            ManifestLayer::LayerDescription{}.set_name(app_specific_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
167        "VK_LAYER_app_specific.json"}
168                               .set_discovery_type(ManifestDiscoveryType::override_folder));
169    const char* global_layer_name = "VK_LAYER_TestLayer_1";
170    env.add_explicit_layer(TestLayerDetails{
171        ManifestLayer{}.add_layer(
172            ManifestLayer::LayerDescription{}.set_name(global_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
173        "VK_LAYER_global.json"}
174                               .set_discovery_type(ManifestDiscoveryType::override_folder));
175    env.update_loader_settings(
176        env.loader_settings
177            // configuration that matches the current executable path - but dont set the app-key just yet
178            .add_app_specific_setting(AppSpecificSettings{}
179                                          .add_stderr_log_filter("all")
180                                          .add_layer_configuration(LoaderSettingsLayerConfiguration{}
181                                                                       .set_name(app_specific_layer_name)
182                                                                       .set_path(env.get_layer_manifest_path(0).str())
183                                                                       .set_control("on"))
184                                          .add_app_key("key0"))
185            // configuration that should never be used
186            .add_app_specific_setting(
187                AppSpecificSettings{}
188                    .add_stderr_log_filter("all")
189                    .add_layer_configuration(
190                        LoaderSettingsLayerConfiguration{}.set_name("VK_LAYER_haha").set_path("/made/up/path").set_control("auto"))
191                    .add_layer_configuration(LoaderSettingsLayerConfiguration{}
192                                                 .set_name("VK_LAYER_haha2")
193                                                 .set_path("/made/up/path2")
194                                                 .set_control("auto"))
195                    .add_app_key("key1")
196                    .add_app_key("key2"))
197            // Add a global configuration
198            .add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
199                LoaderSettingsLayerConfiguration{}
200                    .set_name(global_layer_name)
201                    .set_path(env.get_layer_manifest_path(1).str())
202                    .set_control("on"))));
203    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
204    {
205        auto layer_props = env.GetLayerProperties(1);
206        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, global_layer_name));
207
208        // Check that the global config is used
209        InstWrapper inst{env.vulkan_functions};
210        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
211        inst.CheckCreate();
212        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
213        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
214        ASSERT_TRUE(string_eq(layers.at(0).layerName, global_layer_name));
215    }
216    env.debug_log.clear();
217    // Set one set to contain the current executable path
218    env.loader_settings.app_specific_settings.at(0).add_app_key(fs::fixup_backslashes_in_path(test_platform_executable_path()));
219    env.update_loader_settings(env.loader_settings);
220    {
221        auto layer_props = env.GetLayerProperties(1);
222        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, app_specific_layer_name));
223
224        InstWrapper inst{env.vulkan_functions};
225        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
226        inst.CheckCreate();
227        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
228        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
229        ASSERT_TRUE(string_eq(layers.at(0).layerName, app_specific_layer_name));
230    }
231}
232
233// Make sure layers found through the settings file are enableable by environment variables
234TEST(SettingsFile, LayerAutoEnabledByEnvVars) {
235    FrameworkEnvironment env{};
236    env.loader_settings.set_file_format_version({1, 0, 0});
237    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
238
239    const char* layer_name = "VK_LAYER_automatic";
240    env.add_explicit_layer(
241        TestLayerDetails{ManifestLayer{}.add_layer(
242                             ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
243                         "layer_name.json"}
244            .set_discovery_type(ManifestDiscoveryType::override_folder));
245
246    env.update_loader_settings(
247        env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
248            LoaderSettingsLayerConfiguration{}
249                .set_name(layer_name)
250                .set_path(env.get_layer_manifest_path(0).str())
251                .set_control("auto"))));
252    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
253    {
254        EnvVarWrapper instance_layers{"VK_INSTANCE_LAYERS", layer_name};
255        auto layer_props = env.GetLayerProperties(1);
256        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, layer_name));
257
258        InstWrapper inst{env.vulkan_functions};
259        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
260        inst.CheckCreate();
261        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
262        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
263        ASSERT_TRUE(string_eq(layers.at(0).layerName, layer_name));
264    }
265    env.debug_log.clear();
266
267    {
268        EnvVarWrapper loader_layers_enable{"VK_LOADER_LAYERS_ENABLE", layer_name};
269        auto layer_props = env.GetLayerProperties(1);
270        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, layer_name));
271        InstWrapper inst{env.vulkan_functions};
272        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
273        inst.CheckCreate();
274        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
275        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
276        ASSERT_TRUE(string_eq(layers.at(0).layerName, layer_name));
277    }
278}
279
280// Make sure layers are disallowed from loading if the settings file says so
281TEST(SettingsFile, LayerDisablesImplicitLayer) {
282    FrameworkEnvironment env{};
283    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
284    const char* implicit_layer_name = "VK_LAYER_Implicit_TestLayer";
285    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
286                                                         .set_name(implicit_layer_name)
287                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
288                                                         .set_disable_environment("oof")),
289                           "implicit_test_layer.json");
290
291    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
292        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
293            LoaderSettingsLayerConfiguration{}
294                .set_name(implicit_layer_name)
295                .set_path(env.get_shimmed_layer_manifest_path(0).str())
296                .set_control("off")
297                .set_treat_as_implicit_manifest(true))));
298    {
299        ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
300        InstWrapper inst{env.vulkan_functions};
301        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
302        inst.CheckCreate();
303
304        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
305        ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
306    }
307}
308
309// Implicit layers should be reordered by the settings file
310TEST(SettingsFile, ImplicitLayersDontInterfere) {
311    FrameworkEnvironment env{};
312    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
313    const char* implicit_layer_name1 = "VK_LAYER_Implicit_TestLayer1";
314    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
315                                                         .set_name(implicit_layer_name1)
316                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
317                                                         .set_disable_environment("oof")),
318                           "implicit_test_layer1.json");
319    const char* implicit_layer_name2 = "VK_LAYER_Implicit_TestLayer2";
320    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
321                                                         .set_name(implicit_layer_name2)
322                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
323                                                         .set_disable_environment("oof")),
324                           "implicit_test_layer2.json");
325    // validate order when settings file is not present
326    {
327        auto layer_props = env.GetLayerProperties(2);
328        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name1));
329        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name2));
330
331        InstWrapper inst{env.vulkan_functions};
332        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
333        inst.CheckCreate();
334        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
335        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
336        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
337        ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name2));
338    }
339    // Now setup the settings file to contain a specific order
340    env.update_loader_settings(LoaderSettings{}.add_app_specific_setting(
341        AppSpecificSettings{}
342            .add_stderr_log_filter("all")
343            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
344                                         .set_name(implicit_layer_name1)
345                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
346                                         .set_control("auto")
347                                         .set_treat_as_implicit_manifest(true))
348            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
349                                         .set_name(implicit_layer_name2)
350                                         .set_path(env.get_shimmed_layer_manifest_path(1).str())
351                                         .set_control("auto")
352                                         .set_treat_as_implicit_manifest(true))));
353    {
354        auto layer_props = env.GetLayerProperties(2);
355        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name1));
356        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name2));
357
358        InstWrapper inst{env.vulkan_functions};
359        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
360        inst.CheckCreate();
361        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
362        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
363        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
364        ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name2));
365    }
366
367    // Flip the order and store the settings in the env for later use in the test
368    env.loader_settings = LoaderSettings{}.add_app_specific_setting(
369        AppSpecificSettings{}
370            .add_stderr_log_filter("all")
371            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
372                                         .set_name(implicit_layer_name2)
373                                         .set_path(env.get_shimmed_layer_manifest_path(1).str())
374                                         .set_control("auto")
375                                         .set_treat_as_implicit_manifest(true))
376            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
377                                         .set_name(implicit_layer_name1)
378                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
379                                         .set_control("auto")
380                                         .set_treat_as_implicit_manifest(true)));
381    env.update_loader_settings(env.loader_settings);
382
383    {
384        auto layer_props = env.GetLayerProperties(2);
385        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name2));
386        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name1));
387
388        InstWrapper inst{env.vulkan_functions};
389        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
390        inst.CheckCreate();
391        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
392        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
393        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name2));
394        ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name1));
395    }
396
397    // Now add an explicit layer into the middle and verify that is in the correct location
398    const char* explicit_layer_name3 = "VK_LAYER_Explicit_TestLayer3";
399    env.add_explicit_layer(
400        ManifestLayer{}.add_layer(
401            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name3).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
402        "explicit_test_layer3.json");
403    env.loader_settings.app_specific_settings.at(0).layer_configurations.insert(
404        env.loader_settings.app_specific_settings.at(0).layer_configurations.begin() + 1,
405        LoaderSettingsLayerConfiguration{}
406            .set_name(explicit_layer_name3)
407            .set_path(env.get_shimmed_layer_manifest_path(2).str())
408            .set_control("on"));
409    env.update_loader_settings(env.loader_settings);
410    {
411        auto layer_props = env.GetLayerProperties(3);
412        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name2));
413        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, explicit_layer_name3));
414        ASSERT_TRUE(string_eq(layer_props.at(2).layerName, implicit_layer_name1));
415
416        InstWrapper inst{env.vulkan_functions};
417        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
418        inst.CheckCreate();
419        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
420        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
421        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name2));
422        ASSERT_TRUE(string_eq(layers.at(1).layerName, explicit_layer_name3));
423        ASSERT_TRUE(string_eq(layers.at(2).layerName, implicit_layer_name1));
424    }
425}
426
427// Make sure layers that are disabled can't be enabled by the application
428TEST(SettingsFile, ApplicationEnablesIgnored) {
429    FrameworkEnvironment env{};
430    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
431    const char* explicit_layer_name = "VK_LAYER_TestLayer";
432    env.add_explicit_layer(
433        ManifestLayer{}.add_layer(
434            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
435        "regular_test_layer.json");
436
437    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
438        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
439            LoaderSettingsLayerConfiguration{}
440                .set_name(explicit_layer_name)
441                .set_path(env.get_shimmed_layer_manifest_path(0).str())
442                .set_control("off"))));
443    {
444        ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
445        InstWrapper inst{env.vulkan_functions};
446        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
447        inst.create_info.add_layer(explicit_layer_name);
448        ASSERT_NO_FATAL_FAILURE(inst.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT));
449    }
450}
451
452TEST(SettingsFile, LayerListIsEmpty) {
453    FrameworkEnvironment env{};
454    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
455    const char* implicit_layer_name = "VK_LAYER_TestLayer";
456    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
457                                                         .set_name(implicit_layer_name)
458                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
459                                                         .set_disable_environment("HeeHee")),
460                           "regular_test_layer.json");
461
462    JsonWriter writer{};
463    writer.StartObject();
464    writer.AddKeyedString("file_format_version", "1.0.0");
465    writer.StartKeyedObject("settings");
466    writer.StartKeyedObject("layers");
467    writer.EndObject();
468    writer.EndObject();
469    writer.EndObject();
470    env.write_settings_file(writer.output);
471
472    ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
473
474    InstWrapper inst{env.vulkan_functions};
475    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
476    inst.CheckCreate();
477    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
478    ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
479}
480
481// If a settings file exists but contains no valid settings - don't consider it
482TEST(SettingsFile, InvalidSettingsFile) {
483    FrameworkEnvironment env{};
484    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
485    const char* explicit_layer_name = "VK_LAYER_TestLayer";
486    env.add_explicit_layer(
487        ManifestLayer{}.add_layer(
488            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
489        "regular_test_layer.json");
490    const char* implicit_layer_name = "VK_LAYER_ImplicitTestLayer";
491    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
492                                                         .set_name(implicit_layer_name)
493                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
494                                                         .set_disable_environment("foobarbaz")),
495                           "implicit_test_layer.json");
496    auto check_integrity = [&env, explicit_layer_name, implicit_layer_name]() {
497        auto layer_props = env.GetLayerProperties(2);
498        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name));
499        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, explicit_layer_name));
500        InstWrapper inst{env.vulkan_functions};
501        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
502        inst.create_info.add_layer(explicit_layer_name);
503        inst.CheckCreate();
504        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
505        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
506        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name));
507        ASSERT_TRUE(string_eq(layers.at(1).layerName, explicit_layer_name));
508    };
509
510    {
511        std::fstream fuzzer_output_json_file{FUZZER_OUTPUT_JSON_FILE, std::ios_base::in};
512        ASSERT_TRUE(fuzzer_output_json_file.is_open());
513        std::stringstream fuzzer_output_json;
514        fuzzer_output_json << fuzzer_output_json_file.rdbuf();
515        env.write_settings_file(fuzzer_output_json.str());
516
517        check_integrity();
518    }
519
520    // No actual settings
521    {
522        JsonWriter writer{};
523        writer.StartObject();
524        writer.AddKeyedString("file_format_version", "0.0.0");
525        writer.EndObject();
526        env.write_settings_file(writer.output);
527
528        check_integrity();
529    }
530
531    {
532        JsonWriter writer{};
533        writer.StartObject();
534        writer.AddKeyedString("file_format_version", "0.0.0");
535        writer.StartKeyedArray("settings_array");
536        writer.EndArray();
537        writer.StartKeyedObject("settings");
538        writer.EndObject();
539        writer.EndObject();
540        env.write_settings_file(writer.output);
541
542        check_integrity();
543    }
544
545    {
546        JsonWriter writer{};
547        writer.StartObject();
548        for (uint32_t i = 0; i < 3; i++) {
549            writer.StartKeyedArray("settings_array");
550            writer.EndArray();
551            writer.StartKeyedObject("boogabooga");
552            writer.EndObject();
553            writer.StartKeyedObject("settings");
554            writer.EndObject();
555        }
556        writer.EndObject();
557        env.write_settings_file(writer.output);
558
559        check_integrity();
560    }
561}
562
563// Unknown layers are put in the correct location
564TEST(SettingsFile, UnknownLayersInRightPlace) {
565    FrameworkEnvironment env{};
566    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
567    const char* explicit_layer_name1 = "VK_LAYER_TestLayer1";
568    env.add_explicit_layer(
569        ManifestLayer{}.add_layer(
570            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
571        "regular_test_layer1.json");
572    const char* implicit_layer_name1 = "VK_LAYER_ImplicitTestLayer1";
573    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
574                                                         .set_name(implicit_layer_name1)
575                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
576                                                         .set_disable_environment("foobarbaz")),
577                           "implicit_test_layer1.json");
578    const char* explicit_layer_name2 = "VK_LAYER_TestLayer2";
579    env.add_explicit_layer(
580        ManifestLayer{}.add_layer(
581            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
582        "regular_test_layer2.json");
583    const char* implicit_layer_name2 = "VK_LAYER_ImplicitTestLayer2";
584    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
585                                                         .set_name(implicit_layer_name2)
586                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
587                                                         .set_disable_environment("foobarbaz")),
588                           "implicit_test_layer2.json");
589
590    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
591        AppSpecificSettings{}
592            .add_stderr_log_filter("all")
593            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
594                                         .set_name(explicit_layer_name2)
595                                         .set_path(env.get_shimmed_layer_manifest_path(2).str())
596                                         .set_control("on"))
597            .add_layer_configuration(LoaderSettingsLayerConfiguration{}.set_control("unordered_layer_location"))
598            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
599                                         .set_name(implicit_layer_name2)
600                                         .set_path(env.get_shimmed_layer_manifest_path(3).str())
601                                         .set_control("on")
602                                         .set_treat_as_implicit_manifest(true))));
603
604    auto layer_props = env.GetLayerProperties(4);
605    ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name2));
606    ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name1));
607    ASSERT_TRUE(string_eq(layer_props.at(2).layerName, explicit_layer_name1));
608    ASSERT_TRUE(string_eq(layer_props.at(3).layerName, implicit_layer_name2));
609    InstWrapper inst{env.vulkan_functions};
610    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
611    inst.create_info.add_layer(explicit_layer_name1);
612    inst.CheckCreate();
613    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
614    auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 4);
615    ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name2));
616    ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name1));
617    ASSERT_TRUE(string_eq(layer_props.at(2).layerName, explicit_layer_name1));
618    ASSERT_TRUE(string_eq(layer_props.at(3).layerName, implicit_layer_name2));
619}
620
621// Settings file allows loading multiple layers with the same name - as long as the path is different
622TEST(SettingsFile, MultipleLayersWithSameName) {
623    FrameworkEnvironment env{};
624    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
625
626    const char* explicit_layer_name = "VK_LAYER_TestLayer";
627    env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
628                                                         .set_name(explicit_layer_name)
629                                                         .set_description("0000")
630                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
631                           "regular_test_layer1.json");
632
633    env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
634                                                         .set_name(explicit_layer_name)
635                                                         .set_description("1111")
636                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
637                           "regular_test_layer2.json");
638
639    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
640        AppSpecificSettings{}
641            .add_stderr_log_filter("all")
642            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
643                                         .set_name(explicit_layer_name)
644                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
645                                         .set_control("on"))
646            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
647                                         .set_name(explicit_layer_name)
648                                         .set_path(env.get_shimmed_layer_manifest_path(1).str())
649                                         .set_control("on"))));
650    auto layer_props = env.GetLayerProperties(2);
651    ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name));
652    ASSERT_TRUE(string_eq(layer_props.at(0).description, "0000"));
653    ASSERT_TRUE(string_eq(layer_props.at(1).layerName, explicit_layer_name));
654    ASSERT_TRUE(string_eq(layer_props.at(1).description, "1111"));
655    InstWrapper inst{env.vulkan_functions};
656    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
657    inst.CheckCreate();
658    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
659    auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
660    ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name));
661    ASSERT_TRUE(string_eq(layers.at(0).description, "0000"));
662    ASSERT_TRUE(string_eq(layers.at(1).layerName, explicit_layer_name));
663    ASSERT_TRUE(string_eq(layers.at(1).description, "1111"));
664}
665
666// Settings file shouldn't be able to cause the same layer from the same path twice
667TEST(SettingsFile, MultipleLayersWithSamePath) {
668    FrameworkEnvironment env{};
669    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
670
671    const char* explicit_layer_name = "VK_LAYER_TestLayer";
672    env.add_explicit_layer(
673        ManifestLayer{}.add_layer(
674            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
675        "regular_test_layer1.json");
676
677    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
678        AppSpecificSettings{}
679            .add_stderr_log_filter("all")
680            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
681                                         .set_name(explicit_layer_name)
682                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
683                                         .set_control("on"))
684            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
685                                         .set_name(explicit_layer_name)
686                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
687                                         .set_control("on"))));
688
689    auto layer_props = env.GetLayerProperties(1);
690    ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name));
691
692    InstWrapper inst{env.vulkan_functions};
693    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
694    inst.CheckCreate();
695    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
696    auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
697    ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name));
698}
699
700// Settings contains a layer whose name doesn't match the one found in the layer manifest - make sure the layer from the settings
701// file is removed
702TEST(SettingsFile, MismatchedLayerNameAndManifestPath) {
703    FrameworkEnvironment env{};
704    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
705
706    const char* manifest_explicit_layer_name = "VK_LAYER_MANIFEST_TestLayer";
707    const char* settings_explicit_layer_name = "VK_LAYER_Settings_TestLayer";
708    env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
709                                                         .set_name(manifest_explicit_layer_name)
710                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
711                           "regular_test_layer1.json");
712
713    const char* implicit_layer_name = "VK_LAYER_Implicit_TestLayer";
714    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
715                                                         .set_name(implicit_layer_name)
716                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
717                                                         .set_disable_environment("oof")),
718                           "implicit_test_layer.json");
719
720    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
721        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
722            LoaderSettingsLayerConfiguration{}
723                .set_name(settings_explicit_layer_name)
724                .set_path(env.get_shimmed_layer_manifest_path(0).str())
725                .set_control("on"))));
726
727    ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
728
729    InstWrapper inst{env.vulkan_functions};
730    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
731    inst.CheckCreate();
732    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
733    ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
734}
735
736// Settings file should take precedence over the meta layer, if present
737TEST(SettingsFile, MetaLayerAlsoActivates) {
738    FrameworkEnvironment env{};
739    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
740
741    const char* settings_explicit_layer_name = "VK_LAYER_Regular_TestLayer";
742    env.add_explicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
743                                                         .set_name(settings_explicit_layer_name)
744                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
745                           "explicit_test_layer.json");
746
747    const char* settings_implicit_layer_name = "VK_LAYER_RegularImplicit_TestLayer";
748    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
749                                                         .set_name(settings_implicit_layer_name)
750                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
751                                                         .set_disable_environment("AndISaidHey")
752                                                         .set_enable_environment("WhatsGoingOn")),
753                           "implicit_layer.json");
754
755    const char* component_explicit_layer_name1 = "VK_LAYER_Component_TestLayer1";
756    env.add_explicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
757                                                                          .set_name(component_explicit_layer_name1)
758                                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
759                                            "component_test_layer1.json"));
760
761    const char* component_explicit_layer_name2 = "VK_LAYER_Component_TestLayer2";
762    env.add_explicit_layer(TestLayerDetails(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
763                                                                          .set_name(component_explicit_layer_name2)
764                                                                          .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
765                                            "component_test_layer2.json"));
766
767    const char* meta_layer_name1 = "VK_LAYER_meta_layer1";
768    env.add_implicit_layer(
769        ManifestLayer{}.set_file_format_version({1, 1, 2}).add_layer(ManifestLayer::LayerDescription{}
770                                                                         .set_name(meta_layer_name1)
771                                                                         .add_component_layer(component_explicit_layer_name2)
772                                                                         .add_component_layer(component_explicit_layer_name1)
773                                                                         .set_disable_environment("NotGonnaWork")),
774        "meta_test_layer.json");
775
776    const char* meta_layer_name2 = "VK_LAYER_meta_layer2";
777    env.add_implicit_layer(
778        ManifestLayer{}.set_file_format_version({1, 1, 2}).add_layer(ManifestLayer::LayerDescription{}
779                                                                         .set_name(meta_layer_name2)
780                                                                         .add_component_layer(component_explicit_layer_name1)
781                                                                         .set_disable_environment("ILikeTrains")
782                                                                         .set_enable_environment("BakedBeans")),
783        "not_automatic_meta_test_layer.json");
784
785    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
786        AppSpecificSettings{}
787            .add_stderr_log_filter("all")
788            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
789                                         .set_name(settings_explicit_layer_name)
790                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
791                                         .set_control("on")
792                                         .set_treat_as_implicit_manifest(false))
793            .add_layer_configuration(LoaderSettingsLayerConfiguration{}.set_control("unordered_layer_location"))
794            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
795                                         .set_name(settings_implicit_layer_name)
796                                         .set_path(env.get_shimmed_layer_manifest_path(1).str())
797                                         .set_control("auto")
798                                         .set_treat_as_implicit_manifest(true))));
799    {
800        EnvVarWrapper enable_meta_layer{"WhatsGoingOn", "1"};
801        auto layer_props = env.GetLayerProperties(6);
802        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, settings_explicit_layer_name));
803        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, meta_layer_name1));
804        ASSERT_TRUE(string_eq(layer_props.at(2).layerName, meta_layer_name2));
805        ASSERT_TRUE(string_eq(layer_props.at(3).layerName, component_explicit_layer_name1));
806        ASSERT_TRUE(string_eq(layer_props.at(4).layerName, component_explicit_layer_name2));
807        ASSERT_TRUE(string_eq(layer_props.at(5).layerName, settings_implicit_layer_name));
808
809        InstWrapper inst{env.vulkan_functions};
810        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
811        inst.CheckCreate();
812        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
813        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 5);
814        ASSERT_TRUE(string_eq(layers.at(0).layerName, settings_explicit_layer_name));
815        ASSERT_TRUE(string_eq(layers.at(1).layerName, component_explicit_layer_name2));
816        ASSERT_TRUE(string_eq(layers.at(2).layerName, component_explicit_layer_name1));
817        ASSERT_TRUE(string_eq(layers.at(3).layerName, meta_layer_name1));
818        ASSERT_TRUE(string_eq(layers.at(4).layerName, settings_implicit_layer_name));
819    }
820    {
821        EnvVarWrapper enable_meta_layer{"BakedBeans", "1"};
822        auto layer_props = env.GetLayerProperties(6);
823        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, settings_explicit_layer_name));
824        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, meta_layer_name1));
825        ASSERT_TRUE(string_eq(layer_props.at(2).layerName, meta_layer_name2));
826        ASSERT_TRUE(string_eq(layer_props.at(3).layerName, component_explicit_layer_name1));
827        ASSERT_TRUE(string_eq(layer_props.at(4).layerName, component_explicit_layer_name2));
828        ASSERT_TRUE(string_eq(layer_props.at(5).layerName, settings_implicit_layer_name));
829
830        InstWrapper inst{env.vulkan_functions};
831        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
832        inst.CheckCreate();
833        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
834        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 5);
835        ASSERT_TRUE(string_eq(layers.at(0).layerName, settings_explicit_layer_name));
836        ASSERT_TRUE(string_eq(layers.at(1).layerName, component_explicit_layer_name2));
837        ASSERT_TRUE(string_eq(layers.at(2).layerName, component_explicit_layer_name1));
838        ASSERT_TRUE(string_eq(layers.at(3).layerName, meta_layer_name1));
839        ASSERT_TRUE(string_eq(layers.at(4).layerName, meta_layer_name2));
840    }
841}
842
843// Layers are correctly ordered by settings file.
844TEST(SettingsFile, LayerOrdering) {
845    FrameworkEnvironment env{};
846    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
847
848    const char* explicit_layer_name1 = "VK_LAYER_Regular_TestLayer1";
849    env.add_explicit_layer(
850        ManifestLayer{}.add_layer(
851            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
852        "explicit_test_layer1.json");
853
854    const char* explicit_layer_name2 = "VK_LAYER_Regular_TestLayer2";
855    env.add_explicit_layer(
856        ManifestLayer{}.add_layer(
857            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
858        "explicit_test_layer2.json");
859
860    const char* implicit_layer_name1 = "VK_LAYER_Implicit_TestLayer1";
861    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
862                                                         .set_name(implicit_layer_name1)
863                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
864                                                         .set_disable_environment("Domierigato")),
865                           "implicit_layer1.json");
866
867    const char* implicit_layer_name2 = "VK_LAYER_Implicit_TestLayer2";
868    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
869                                                         .set_name(implicit_layer_name2)
870                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
871                                                         .set_disable_environment("Mistehrobato")),
872                           "implicit_layer2.json");
873
874    env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all"));
875
876    std::vector<LoaderSettingsLayerConfiguration> layer_configs{4};
877    layer_configs.at(0)
878        .set_name(explicit_layer_name1)
879        .set_path(env.get_shimmed_layer_manifest_path(0).str())
880        .set_control("on")
881        .set_treat_as_implicit_manifest(false);
882    layer_configs.at(1)
883        .set_name(explicit_layer_name2)
884        .set_path(env.get_shimmed_layer_manifest_path(1).str())
885        .set_control("on")
886        .set_treat_as_implicit_manifest(false);
887    layer_configs.at(2)
888        .set_name(implicit_layer_name1)
889        .set_path(env.get_shimmed_layer_manifest_path(2).str())
890        .set_control("on")
891        .set_treat_as_implicit_manifest(true);
892    layer_configs.at(3)
893        .set_name(implicit_layer_name2)
894        .set_path(env.get_shimmed_layer_manifest_path(3).str())
895        .set_control("on")
896        .set_treat_as_implicit_manifest(true);
897
898    std::sort(layer_configs.begin(), layer_configs.end());
899    uint32_t permutation_count = 0;
900    do {
901        env.loader_settings.app_specific_settings.at(0).layer_configurations.clear();
902        env.loader_settings.app_specific_settings.at(0).add_layer_configurations(layer_configs);
903        env.update_loader_settings(env.loader_settings);
904
905        auto layer_props = env.GetLayerProperties(4);
906        for (uint32_t i = 0; i < 4; i++) {
907            ASSERT_TRUE(layer_configs.at(i).name == layer_props.at(i).layerName);
908        }
909
910        InstWrapper inst{env.vulkan_functions};
911        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
912        inst.CheckCreate();
913        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
914        auto active_layers = inst.GetActiveLayers(inst.GetPhysDev(), 4);
915        for (uint32_t i = 0; i < 4; i++) {
916            ASSERT_TRUE(layer_configs.at(i).name == active_layers.at(i).layerName);
917        }
918        env.debug_log.clear();
919        permutation_count++;
920    } while (std::next_permutation(layer_configs.begin(), layer_configs.end()));
921    ASSERT_EQ(permutation_count, 24U);  // should be this many orderings
922}
923
924TEST(SettingsFile, EnvVarsWork_VK_LAYER_PATH) {
925    FrameworkEnvironment env{};
926    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
927
928    const char* explicit_layer_name1 = "VK_LAYER_Regular_TestLayer1";
929    env.add_explicit_layer(TestLayerDetails{
930        ManifestLayer{}.add_layer(
931            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
932        "explicit_test_layer1.json"}
933                               .set_discovery_type(ManifestDiscoveryType::env_var));
934
935    const char* implicit_layer_name1 = "VK_LAYER_Implicit_TestLayer1";
936    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
937                                                         .set_name(implicit_layer_name1)
938                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
939                                                         .set_disable_environment("Domierigato")),
940                           "implicit_layer1.json");
941    const char* non_env_var_layer_name2 = "VK_LAYER_Regular_TestLayer2";
942    env.add_explicit_layer(TestLayerDetails{
943        ManifestLayer{}.add_layer(
944            ManifestLayer::LayerDescription{}.set_name(non_env_var_layer_name2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
945        "explicit_test_layer2.json"});
946
947    {
948        auto layer_props = env.GetLayerProperties(2);
949        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name1));
950        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, explicit_layer_name1));
951
952        InstWrapper inst{env.vulkan_functions};
953        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
954        inst.CheckCreate();
955        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
956        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
957        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
958    }
959    {
960        InstWrapper inst{env.vulkan_functions};
961        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
962        inst.create_info.add_layer(explicit_layer_name1);
963        inst.CheckCreate();
964        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
965        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
966        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
967        ASSERT_TRUE(string_eq(layers.at(1).layerName, explicit_layer_name1));
968    }
969    env.update_loader_settings(env.loader_settings.add_app_specific_setting(
970        AppSpecificSettings{}
971            .add_stderr_log_filter("all")
972            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
973                                         .set_name(non_env_var_layer_name2)
974                                         .set_control("on")
975                                         .set_path(env.get_shimmed_layer_manifest_path(2).str()))
976            .add_layer_configuration(LoaderSettingsLayerConfiguration{}.set_control("unordered_layer_location"))));
977    {
978        auto layer_props = env.GetLayerProperties(3);
979        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, non_env_var_layer_name2));
980        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, implicit_layer_name1));
981        ASSERT_TRUE(string_eq(layer_props.at(2).layerName, explicit_layer_name1));
982
983        InstWrapper inst{env.vulkan_functions};
984        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
985        inst.CheckCreate();
986        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
987        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
988        ASSERT_TRUE(string_eq(layers.at(0).layerName, non_env_var_layer_name2));
989        ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name1));
990    }
991    {
992        InstWrapper inst{env.vulkan_functions};
993        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
994        inst.create_info.add_layer(explicit_layer_name1);
995        inst.CheckCreate();
996        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
997        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
998        ASSERT_TRUE(string_eq(layers.at(0).layerName, non_env_var_layer_name2));
999        ASSERT_TRUE(string_eq(layers.at(1).layerName, implicit_layer_name1));
1000        ASSERT_TRUE(string_eq(layers.at(2).layerName, explicit_layer_name1));
1001    }
1002}
1003
1004TEST(SettingsFile, EnvVarsWork_VK_ADD_LAYER_PATH) {
1005    FrameworkEnvironment env{};
1006    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1007
1008    const char* implicit_layer_name1 = "VK_LAYER_Implicit_TestLayer1";
1009    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1010                                                         .set_name(implicit_layer_name1)
1011                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1012                                                         .set_disable_environment("Domierigato")),
1013                           "implicit_layer1.json");
1014    const char* explicit_layer_name1 = "VK_LAYER_Regular_TestLayer1";
1015    env.add_explicit_layer(TestLayerDetails{
1016        ManifestLayer{}.add_layer(
1017            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name1).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1018        "explicit_test_layer1.json"}
1019                               .set_discovery_type(ManifestDiscoveryType::add_env_var));
1020    const char* non_env_var_layer_name2 = "VK_LAYER_Regular_TestLayer2";
1021    env.add_explicit_layer(TestLayerDetails{
1022        ManifestLayer{}.add_layer(
1023            ManifestLayer::LayerDescription{}.set_name(non_env_var_layer_name2).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1024        "explicit_test_layer2.json"});
1025
1026    {
1027        auto layer_props = env.GetLayerProperties(3);
1028        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, implicit_layer_name1));
1029        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, explicit_layer_name1));
1030        ASSERT_TRUE(string_eq(layer_props.at(2).layerName, non_env_var_layer_name2));
1031
1032        InstWrapper inst{env.vulkan_functions};
1033        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1034        inst.CheckCreate();
1035        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
1036        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1037        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
1038    }
1039    {
1040        InstWrapper inst{env.vulkan_functions};
1041        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1042        inst.create_info.add_layer(explicit_layer_name1);
1043        inst.CheckCreate();
1044        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
1045        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 2);
1046        ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name1));
1047        ASSERT_TRUE(string_eq(layers.at(1).layerName, explicit_layer_name1));
1048    }
1049
1050    env.update_loader_settings(env.loader_settings.add_app_specific_setting(
1051        AppSpecificSettings{}
1052            .add_stderr_log_filter("all")
1053            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
1054                                         .set_name(explicit_layer_name1)
1055                                         .set_control("on")
1056                                         .set_path(env.get_shimmed_layer_manifest_path(1).str()))
1057            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
1058                                         .set_name(non_env_var_layer_name2)
1059                                         .set_control("on")
1060                                         .set_path(env.get_shimmed_layer_manifest_path(2).str()))
1061            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
1062                                         .set_name(implicit_layer_name1)
1063                                         .set_control("on")
1064                                         .set_path(env.get_shimmed_layer_manifest_path(0).str())
1065                                         .set_treat_as_implicit_manifest(true))));
1066    {
1067        auto layer_props = env.GetLayerProperties(3);
1068        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name1));
1069        ASSERT_TRUE(string_eq(layer_props.at(1).layerName, non_env_var_layer_name2));
1070        ASSERT_TRUE(string_eq(layer_props.at(2).layerName, implicit_layer_name1));
1071
1072        InstWrapper inst{env.vulkan_functions};
1073        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1074        inst.CheckCreate();
1075        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1076        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
1077        ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name1));
1078        ASSERT_TRUE(string_eq(layers.at(1).layerName, non_env_var_layer_name2));
1079        ASSERT_TRUE(string_eq(layers.at(2).layerName, implicit_layer_name1));
1080    }
1081    {
1082        InstWrapper inst{env.vulkan_functions};
1083        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1084        inst.create_info.add_layer(explicit_layer_name1);
1085        inst.CheckCreate();
1086        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1087        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 3);
1088        ASSERT_TRUE(string_eq(layers.at(0).layerName, explicit_layer_name1));
1089        ASSERT_TRUE(string_eq(layers.at(1).layerName, non_env_var_layer_name2));
1090        ASSERT_TRUE(string_eq(layers.at(2).layerName, implicit_layer_name1));
1091    }
1092}
1093
1094TEST(SettingsFile, EnvVarsWork_VK_INSTANCE_LAYERS) {
1095    FrameworkEnvironment env{};
1096    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1097
1098    const char* explicit_layer_name = "VK_LAYER_Regular_TestLayer1";
1099    env.add_explicit_layer(TestLayerDetails{
1100        ManifestLayer{}.add_layer(
1101            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1102        "explicit_test_layer1.json"});
1103
1104    {
1105        EnvVarWrapper vk_instance_layers{"VK_INSTANCE_LAYERS", explicit_layer_name};
1106        auto layer_props = env.GetLayerProperties(1);
1107        ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name));
1108
1109        InstWrapper inst{env.vulkan_functions};
1110        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1111        inst.CheckCreate();
1112        ASSERT_FALSE(env.debug_log.find(get_settings_location_log_message(env)));
1113        auto layer = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1114        ASSERT_TRUE(string_eq(layer.at(0).layerName, explicit_layer_name));
1115    }
1116    env.update_loader_settings(
1117        env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1118            LoaderSettingsLayerConfiguration{}
1119                .set_name(explicit_layer_name)
1120                .set_control("off")
1121                .set_path(env.get_shimmed_layer_manifest_path(0).str()))));
1122    {
1123        ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
1124
1125        InstWrapper inst{env.vulkan_functions};
1126        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1127        inst.CheckCreate();
1128        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1129        ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
1130    }
1131    {
1132        EnvVarWrapper vk_instance_layers{"VK_INSTANCE_LAYERS", explicit_layer_name};
1133        ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
1134
1135        InstWrapper inst{env.vulkan_functions};
1136        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1137        inst.CheckCreate();
1138        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1139        ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
1140    }
1141}
1142// Make sure that layers disabled by settings file aren't enabled by VK_LOADER_LAYERS_ENABLE
1143TEST(SettingsFile, EnvVarsWork_VK_LOADER_LAYERS_ENABLE) {
1144    FrameworkEnvironment env{};
1145    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1146
1147    const char* explicit_layer_name = "VK_LAYER_Regular_TestLayer1";
1148    env.add_explicit_layer(TestLayerDetails{
1149        ManifestLayer{}.add_layer(
1150            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1151        "explicit_test_layer1.json"});
1152
1153    env.update_loader_settings(
1154        env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1155            LoaderSettingsLayerConfiguration{}
1156                .set_name(explicit_layer_name)
1157                .set_control("off")
1158                .set_path(env.get_shimmed_layer_manifest_path(0).str()))));
1159
1160    EnvVarWrapper vk_instance_layers{"VK_LOADER_LAYERS_ENABLE", explicit_layer_name};
1161    ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
1162
1163    InstWrapper inst{env.vulkan_functions};
1164    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1165    inst.CheckCreate();
1166    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1167    ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
1168}
1169// Make sure that layers enabled by settings file aren't disabled by VK_LOADER_LAYERS_ENABLE
1170TEST(SettingsFile, EnvVarsWork_VK_LOADER_LAYERS_DISABLE) {
1171    FrameworkEnvironment env{};
1172    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1173
1174    const char* explicit_layer_name = "VK_LAYER_Regular_TestLayer1";
1175    env.add_explicit_layer(TestLayerDetails{
1176        ManifestLayer{}.add_layer(
1177            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1178        "explicit_test_layer1.json"});
1179
1180    env.update_loader_settings(
1181        env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1182            LoaderSettingsLayerConfiguration{}
1183                .set_name(explicit_layer_name)
1184                .set_control("on")
1185                .set_path(env.get_shimmed_layer_manifest_path(0).str()))));
1186
1187    EnvVarWrapper vk_instance_layers{"VK_LOADER_LAYERS_DISABLE", explicit_layer_name};
1188    auto layer_props = env.GetLayerProperties(1);
1189    ASSERT_TRUE(string_eq(layer_props.at(0).layerName, explicit_layer_name));
1190
1191    InstWrapper inst{env.vulkan_functions};
1192    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1193    inst.CheckCreate();
1194    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1195    ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
1196}
1197
1198#if defined(WIN32)
1199TEST(SettingsFile, MultipleKeysInRegistryInUnsecureLocation) {
1200    FrameworkEnvironment env{};
1201    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1202    env.platform_shim->add_unsecured_manifest(ManifestCategory::settings, "jank_path");
1203    env.platform_shim->add_unsecured_manifest(ManifestCategory::settings, "jank_path2");
1204
1205    const char* regular_layer_name = "VK_LAYER_TestLayer_0";
1206    env.add_explicit_layer(TestLayerDetails{
1207        ManifestLayer{}.add_layer(
1208            ManifestLayer::LayerDescription{}.set_name(regular_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1209        "regular_test_layer.json"}
1210                               .set_discovery_type(ManifestDiscoveryType::override_folder));
1211    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
1212        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1213            LoaderSettingsLayerConfiguration{}
1214                .set_name(regular_layer_name)
1215                .set_path(env.get_layer_manifest_path().str())
1216                .set_control("on"))));
1217    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
1218
1219    auto layer_props = env.GetLayerProperties(1);
1220    EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name));
1221
1222    InstWrapper inst{env.vulkan_functions};
1223    FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1224    inst.CheckCreate();
1225
1226    ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1227    env.debug_log.clear();
1228    auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1229    ASSERT_TRUE(string_eq(layers.at(0).layerName, regular_layer_name));
1230}
1231
1232TEST(SettingsFile, MultipleKeysInRegistryInSecureLocation) {
1233    FrameworkEnvironment env{FrameworkSettings{}.set_secure_loader_settings(true)};
1234    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1235    env.platform_shim->add_manifest(ManifestCategory::settings, "jank_path");
1236    env.platform_shim->add_manifest(ManifestCategory::settings, "jank_path2");
1237
1238    const char* regular_layer_name = "VK_LAYER_TestLayer_0";
1239    env.add_explicit_layer(TestLayerDetails{
1240        ManifestLayer{}.add_layer(
1241            ManifestLayer::LayerDescription{}.set_name(regular_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1242        "regular_test_layer.json"}
1243                               .set_discovery_type(ManifestDiscoveryType::override_folder));
1244    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
1245        AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1246            LoaderSettingsLayerConfiguration{}
1247                .set_name(regular_layer_name)
1248                .set_path(env.get_layer_manifest_path().str())
1249                .set_control("on"))));
1250    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
1251
1252    // Make sure it works if the settings file is in the HKEY_LOCAL_MACHINE
1253    env.platform_shim->set_elevated_privilege(true);
1254    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2));
1255    {
1256        auto layer_props = env.GetLayerProperties(1);
1257        EXPECT_TRUE(string_eq(layer_props.at(0).layerName, regular_layer_name));
1258
1259        InstWrapper inst{env.vulkan_functions};
1260        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1261        inst.CheckCreate();
1262
1263        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1264        env.debug_log.clear();
1265        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1266        ASSERT_TRUE(string_eq(layers.at(0).layerName, regular_layer_name));
1267    }
1268}
1269#endif
1270
1271// Preinstance functions respect the settings file
1272TEST(SettingsFile, PreInstanceFunctions) {
1273    FrameworkEnvironment env;
1274    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
1275
1276    const char* implicit_layer_name = "VK_LAYER_ImplicitTestLayer";
1277
1278    env.add_implicit_layer(
1279        ManifestLayer{}.set_file_format_version({1, 1, 2}).add_layer(
1280            ManifestLayer::LayerDescription{}
1281                .set_name(implicit_layer_name)
1282                .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1283                .set_disable_environment("DISABLE_ME")
1284                .add_pre_instance_function(ManifestLayer::LayerDescription::FunctionOverride{}
1285                                               .set_vk_func("vkEnumerateInstanceLayerProperties")
1286                                               .set_override_name("test_preinst_vkEnumerateInstanceLayerProperties"))
1287                .add_pre_instance_function(ManifestLayer::LayerDescription::FunctionOverride{}
1288                                               .set_vk_func("vkEnumerateInstanceExtensionProperties")
1289                                               .set_override_name("test_preinst_vkEnumerateInstanceExtensionProperties"))
1290                .add_pre_instance_function(ManifestLayer::LayerDescription::FunctionOverride{}
1291                                               .set_vk_func("vkEnumerateInstanceVersion")
1292                                               .set_override_name("test_preinst_vkEnumerateInstanceVersion"))),
1293        "implicit_test_layer.json");
1294
1295    env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1296        LoaderSettingsLayerConfiguration{}
1297            .set_name(implicit_layer_name)
1298            .set_control("on")
1299            .set_path(env.get_shimmed_layer_manifest_path(0).str())
1300            .set_treat_as_implicit_manifest(true)));
1301    env.update_loader_settings(env.loader_settings);
1302    {
1303        auto& layer = env.get_test_layer(0);
1304        // Check layer props
1305        uint32_t layer_props = 43;
1306        layer.set_reported_layer_props(layer_props);
1307
1308        uint32_t count = 0;
1309        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr));
1310        ASSERT_EQ(count, layer_props);
1311
1312        // check extension props
1313        uint32_t ext_props = 52;
1314        layer.set_reported_extension_props(ext_props);
1315        count = 0;
1316        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr));
1317        ASSERT_EQ(count, ext_props);
1318
1319        // check version
1320        uint32_t layer_version = VK_MAKE_API_VERSION(1, 2, 3, 4);
1321        layer.set_reported_instance_version(layer_version);
1322
1323        uint32_t version = 0;
1324        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceVersion(&version));
1325        ASSERT_EQ(version, layer_version);
1326    }
1327    // control is set to off
1328    env.loader_settings.app_specific_settings.at(0).layer_configurations.at(0).set_control("off");
1329    env.update_loader_settings(env.loader_settings);
1330
1331    {
1332        auto& layer = env.get_test_layer(0);
1333        // Check layer props
1334        uint32_t layer_props = 43;
1335        layer.set_reported_layer_props(layer_props);
1336
1337        uint32_t count = 0;
1338        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr));
1339        ASSERT_EQ(count, 0U);  // dont use the intercepted count
1340
1341        // check extension props
1342        uint32_t ext_props = 52;
1343        layer.set_reported_extension_props(ext_props);
1344        count = 0;
1345        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr));
1346        ASSERT_EQ(count, 4U);  // dont use the intercepted count - use default count
1347
1348        // check version
1349        uint32_t layer_version = VK_MAKE_API_VERSION(1, 2, 3, 4);
1350        layer.set_reported_instance_version(layer_version);
1351
1352        uint32_t version = 0;
1353        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceVersion(&version));
1354        ASSERT_EQ(version, VK_HEADER_VERSION_COMPLETE);
1355    }
1356
1357    // control is set to auto
1358    env.loader_settings.app_specific_settings.at(0).layer_configurations.at(0).set_control("auto");
1359    env.update_loader_settings(env.loader_settings);
1360
1361    {
1362        auto& layer = env.get_test_layer(0);
1363        // Check layer props
1364        uint32_t layer_props = 43;
1365        layer.set_reported_layer_props(layer_props);
1366
1367        uint32_t count = 0;
1368        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceLayerProperties(&count, nullptr));
1369        ASSERT_EQ(count, layer_props);
1370
1371        // check extension props
1372        uint32_t ext_props = 52;
1373        layer.set_reported_extension_props(ext_props);
1374        count = 0;
1375        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr));
1376        ASSERT_EQ(count, ext_props);
1377
1378        // check version
1379        uint32_t layer_version = VK_MAKE_API_VERSION(1, 2, 3, 4);
1380        layer.set_reported_instance_version(layer_version);
1381
1382        uint32_t version = 0;
1383        ASSERT_EQ(VK_SUCCESS, env.vulkan_functions.vkEnumerateInstanceVersion(&version));
1384        ASSERT_EQ(version, layer_version);
1385    }
1386}
1387
1388// If an implicit layer's disable environment variable is set, but the settings file says to turn the layer on, the layer should be
1389// activated.
1390TEST(SettingsFile, ImplicitLayerDisableEnvironmentVariableOverriden) {
1391    auto check_log_for_insert_instance_layer_string = [](FrameworkEnvironment& env, const char* implicit_layer_name,
1392                                                         bool check_for_enable) {
1393        {
1394            InstWrapper inst{env.vulkan_functions};
1395            FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1396            inst.CheckCreate(VK_SUCCESS);
1397            if (check_for_enable) {
1398                ASSERT_TRUE(env.debug_log.find(std::string("Insert instance layer \"") + implicit_layer_name));
1399                auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1400                ASSERT_TRUE(string_eq(layers.at(0).layerName, implicit_layer_name));
1401            } else {
1402                ASSERT_FALSE(env.debug_log.find(std::string("Insert instance layer \"") + implicit_layer_name));
1403                ASSERT_NO_FATAL_FAILURE(inst.GetActiveLayers(inst.GetPhysDev(), 0));
1404            }
1405        }
1406        env.debug_log.clear();
1407    };
1408
1409    FrameworkEnvironment env;
1410    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA)).add_physical_device({});
1411    const char* implicit_layer_name = "VK_LAYER_ImplicitTestLayer";
1412
1413    env.add_implicit_layer(ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1414                                                         .set_name(implicit_layer_name)
1415                                                         .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)
1416                                                         .set_disable_environment("DISABLE_ME")
1417                                                         .set_enable_environment("ENABLE_ME")),
1418                           "implicit_test_layer.json");
1419    env.loader_settings.add_app_specific_setting(AppSpecificSettings{}.add_stderr_log_filter("all").add_layer_configuration(
1420        LoaderSettingsLayerConfiguration{}
1421            .set_name(implicit_layer_name)
1422            .set_path(env.get_shimmed_layer_manifest_path(0).str())
1423            .set_treat_as_implicit_manifest(true)));
1424
1425    // control is set to on
1426    env.loader_settings.app_specific_settings.at(0).layer_configurations.at(0).set_control("on");
1427    env.update_loader_settings(env.loader_settings);
1428    {
1429        EnvVarWrapper enable_env_var{"ENABLE_ME"};
1430        EnvVarWrapper disable_env_var{"DISABLE_ME"};
1431
1432        auto layers = env.GetLayerProperties(1);
1433        ASSERT_TRUE(string_eq(layers[0].layerName, implicit_layer_name));
1434
1435        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1436
1437        enable_env_var.set_new_value("0");
1438        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1439
1440        enable_env_var.set_new_value("1");
1441        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1442
1443        enable_env_var.remove_value();
1444
1445        disable_env_var.set_new_value("0");
1446        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1447
1448        disable_env_var.set_new_value("1");
1449        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1450
1451        enable_env_var.set_new_value("1");
1452        disable_env_var.set_new_value("1");
1453        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1454    }
1455
1456    // control is set to off
1457    env.loader_settings.app_specific_settings.at(0).layer_configurations.at(0).set_control("off");
1458    env.update_loader_settings(env.loader_settings);
1459    {
1460        EnvVarWrapper enable_env_var{"ENABLE_ME"};
1461        EnvVarWrapper disable_env_var{"DISABLE_ME"};
1462
1463        ASSERT_NO_FATAL_FAILURE(env.GetLayerProperties(0));
1464
1465        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1466
1467        enable_env_var.set_new_value("0");
1468        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1469
1470        enable_env_var.set_new_value("1");
1471        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1472
1473        enable_env_var.remove_value();
1474
1475        disable_env_var.set_new_value("0");
1476        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1477
1478        disable_env_var.set_new_value("1");
1479        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1480
1481        enable_env_var.set_new_value("1");
1482        disable_env_var.set_new_value("1");
1483        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1484    }
1485
1486    // control is set to auto
1487    env.loader_settings.app_specific_settings.at(0).layer_configurations.at(0).set_control("auto");
1488    env.update_loader_settings(env.loader_settings);
1489    {
1490        EnvVarWrapper enable_env_var{"ENABLE_ME"};
1491        EnvVarWrapper disable_env_var{"DISABLE_ME"};
1492
1493        auto layers = env.GetLayerProperties(1);
1494        ASSERT_TRUE(string_eq(layers[0].layerName, implicit_layer_name));
1495
1496        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1497
1498        enable_env_var.set_new_value("0");
1499        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1500
1501        enable_env_var.set_new_value("1");
1502        check_log_for_insert_instance_layer_string(env, implicit_layer_name, true);
1503
1504        enable_env_var.remove_value();
1505
1506        disable_env_var.set_new_value("0");
1507        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1508
1509        disable_env_var.set_new_value("1");
1510        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1511
1512        enable_env_var.set_new_value("1");
1513        disable_env_var.set_new_value("1");
1514        check_log_for_insert_instance_layer_string(env, implicit_layer_name, false);
1515    }
1516}
1517
1518// Settings can say which filters to use - make sure those are propagated & treated correctly
1519TEST(SettingsFile, StderrLogFilters) {
1520    FrameworkEnvironment env{};
1521    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1522    const char* explicit_layer_name = "Regular_TestLayer1";
1523    env.add_explicit_layer(TestLayerDetails{
1524        ManifestLayer{}.add_layer(
1525            ManifestLayer::LayerDescription{}.set_name(explicit_layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1526        "explicit_test_layer1.json"});
1527    env.update_loader_settings(env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
1528        AppSpecificSettings{}
1529            .add_layer_configuration(LoaderSettingsLayerConfiguration{}
1530                                         .set_name(explicit_layer_name)
1531                                         .set_path(env.get_shimmed_layer_manifest_path().str())
1532                                         .set_control("on"))
1533            .add_layer_configuration(
1534                LoaderSettingsLayerConfiguration{}.set_name("VK_LAYER_missing").set_path("/road/to/nowhere").set_control("on"))));
1535
1536    std::string expected_output_verbose;
1537    expected_output_verbose += "Layer Configurations count = 2\n";
1538    expected_output_verbose += "---- Layer Configuration [0] ----\n";
1539    expected_output_verbose += std::string("Name: ") + explicit_layer_name + "\n";
1540    expected_output_verbose += "Path: " + env.get_shimmed_layer_manifest_path().str() + "\n";
1541    expected_output_verbose += "Control: on\n";
1542    expected_output_verbose += "---- Layer Configuration [1] ----\n";
1543    expected_output_verbose += "Name: VK_LAYER_missing\n";
1544    expected_output_verbose += "Path: /road/to/nowhere\n";
1545    expected_output_verbose += "Control: on\n";
1546    expected_output_verbose += "---------------------------------\n";
1547
1548    std::string expected_output_info = get_settings_location_log_message(env) + "\n";
1549
1550    std::string expected_output_warning =
1551        "Layer name Regular_TestLayer1 does not conform to naming standard (Policy #LLP_LAYER_3)\n";
1552
1553    std::string expected_output_error = "loader_get_json: Failed to open JSON file /road/to/nowhere\n";
1554
1555    env.loader_settings.app_specific_settings.at(0).stderr_log = {"all"};
1556    env.update_loader_settings(env.loader_settings);
1557    {
1558        InstWrapper inst{env.vulkan_functions};
1559        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1560        inst.CheckCreate();
1561
1562        ASSERT_TRUE(env.debug_log.find(expected_output_verbose));
1563        ASSERT_TRUE(env.debug_log.find(expected_output_info));
1564        ASSERT_TRUE(env.debug_log.find(expected_output_warning));
1565        ASSERT_TRUE(env.debug_log.find(expected_output_error));
1566        auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1567        EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, explicit_layer_name));
1568    }
1569    env.debug_log.clear();
1570    env.debug_log.create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
1571    env.loader_settings.app_specific_settings.at(0).stderr_log = {"info"};
1572    env.update_loader_settings(env.loader_settings);
1573    {
1574        InstWrapper inst{env.vulkan_functions};
1575        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1576        inst.CheckCreate();
1577
1578        ASSERT_TRUE(env.debug_log.find(expected_output_verbose));
1579        ASSERT_FALSE(env.debug_log.find(expected_output_info));
1580        ASSERT_FALSE(env.debug_log.find(expected_output_warning));
1581        ASSERT_FALSE(env.debug_log.find(expected_output_error));
1582        auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1583        EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, explicit_layer_name));
1584    }
1585    env.debug_log.clear();
1586    env.debug_log.create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
1587    env.loader_settings.app_specific_settings.at(0).stderr_log = {"debug"};
1588    env.update_loader_settings(env.loader_settings);
1589    {
1590        InstWrapper inst{env.vulkan_functions};
1591        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1592        inst.CheckCreate();
1593
1594        ASSERT_FALSE(env.debug_log.find(expected_output_verbose));
1595        ASSERT_TRUE(env.debug_log.find(expected_output_info));
1596        ASSERT_FALSE(env.debug_log.find(expected_output_warning));
1597        ASSERT_FALSE(env.debug_log.find(expected_output_error));
1598        auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1599        EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, explicit_layer_name));
1600    }
1601    env.debug_log.clear();
1602    env.debug_log.create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
1603    env.loader_settings.app_specific_settings.at(0).stderr_log = {"warn"};
1604    env.update_loader_settings(env.loader_settings);
1605    {
1606        InstWrapper inst{env.vulkan_functions};
1607        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1608        inst.CheckCreate();
1609
1610        ASSERT_FALSE(env.debug_log.find(expected_output_verbose));
1611        ASSERT_FALSE(env.debug_log.find(expected_output_info));
1612        ASSERT_TRUE(env.debug_log.find(expected_output_warning));
1613        ASSERT_FALSE(env.debug_log.find(expected_output_error));
1614        auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1615        EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, explicit_layer_name));
1616    }
1617    env.debug_log.clear();
1618    env.debug_log.create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
1619    env.loader_settings.app_specific_settings.at(0).stderr_log = {"error"};
1620    env.update_loader_settings(env.loader_settings);
1621    {
1622        InstWrapper inst{env.vulkan_functions};
1623        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1624        inst.CheckCreate();
1625
1626        ASSERT_FALSE(env.debug_log.find(expected_output_verbose));
1627        ASSERT_FALSE(env.debug_log.find(expected_output_info));
1628        ASSERT_FALSE(env.debug_log.find(expected_output_warning));
1629        ASSERT_TRUE(env.debug_log.find(expected_output_error));
1630        auto active_layer_props = inst.GetActiveLayers(inst.GetPhysDev(), 1);
1631        EXPECT_TRUE(string_eq(active_layer_props.at(0).layerName, explicit_layer_name));
1632    }
1633}
1634
1635// Enough layers exist that arrays need to be resized - make sure that works
1636TEST(SettingsFile, TooManyLayers) {
1637    FrameworkEnvironment env{};
1638    env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2)).add_physical_device({});
1639    env.loader_settings.set_file_format_version({1, 0, 0}).add_app_specific_setting(
1640        AppSpecificSettings{}.add_stderr_log_filter("all"));
1641    std::string layer_name = "VK_LAYER_regular_layer_name_";
1642    uint32_t layer_count = 40;
1643    for (uint32_t i = 0; i < layer_count; i++) {
1644        env.add_explicit_layer(TestLayerDetails{ManifestLayer{}.add_layer(ManifestLayer::LayerDescription{}
1645                                                                              .set_name(layer_name + std::to_string(i))
1646                                                                              .set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
1647                                                layer_name + std::to_string(i) + ".json"}
1648                                   .set_discovery_type(ManifestDiscoveryType::override_folder));
1649        env.loader_settings.app_specific_settings.at(0).add_layer_configuration(LoaderSettingsLayerConfiguration{}
1650                                                                                    .set_name(layer_name + std::to_string(i))
1651                                                                                    .set_path(env.get_layer_manifest_path(i).str())
1652                                                                                    .set_control("on"));
1653    }
1654    env.update_loader_settings(env.loader_settings);
1655
1656    {
1657        auto layer_props = env.GetLayerProperties(40);
1658        for (uint32_t i = 0; i < layer_count; i++) {
1659            std::string expected_layer_name = layer_name + std::to_string(i);
1660            EXPECT_TRUE(string_eq(layer_props.at(i).layerName, expected_layer_name.c_str()));
1661        }
1662        InstWrapper inst{env.vulkan_functions};
1663        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1664        inst.CheckCreate();
1665
1666        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1667        env.debug_log.clear();
1668        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 40);
1669        for (uint32_t i = 0; i < layer_count; i++) {
1670            std::string expected_layer_name = layer_name + std::to_string(i);
1671            EXPECT_TRUE(string_eq(layers.at(i).layerName, expected_layer_name.c_str()));
1672        }
1673    }
1674    env.loader_settings.app_specific_settings.at(0).layer_configurations.clear();
1675
1676    // Now reverse the order to make sure adding the 'last' layer first works
1677    for (uint32_t i = 0; i < layer_count; i++) {
1678        env.loader_settings.app_specific_settings.at(0).add_layer_configuration(
1679            LoaderSettingsLayerConfiguration{}
1680                .set_name(layer_name + std::to_string(layer_count - i - 1))
1681                .set_path(env.get_layer_manifest_path(layer_count - i - 1).str())
1682                .set_control("on"));
1683    }
1684    env.update_loader_settings(env.loader_settings);
1685
1686    {
1687        auto layer_props = env.GetLayerProperties(40);
1688        for (uint32_t i = 0; i < layer_count; i++) {
1689            std::string expected_layer_name = layer_name + std::to_string(layer_count - i - 1);
1690            EXPECT_TRUE(string_eq(layer_props.at(i).layerName, expected_layer_name.c_str()));
1691        }
1692        InstWrapper inst{env.vulkan_functions};
1693        FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
1694        inst.CheckCreate();
1695
1696        ASSERT_TRUE(env.debug_log.find(get_settings_location_log_message(env)));
1697        env.debug_log.clear();
1698        auto layers = inst.GetActiveLayers(inst.GetPhysDev(), 40);
1699        for (uint32_t i = 0; i < layer_count; i++) {
1700            std::string expected_layer_name = layer_name + std::to_string(layer_count - i - 1);
1701            EXPECT_TRUE(string_eq(layers.at(i).layerName, expected_layer_name.c_str()));
1702        }
1703    }
1704}
1705