From dc1acf9e37c53ab5ed1d5cc0b30320277c89baa0 Mon Sep 17 00:00:00 2001
From: Christophe <christophe@lunarg.com>
Date: Tue, 19 Sep 2023 13:28:54 +0200
Subject: [PATCH] layer: Add env var prefix override for back compatibility

---
 include/vulkan/layer/vk_layer_settings.h |  3 ++
 scripts/CMakeLists.txt                   |  1 +
 src/layer/layer_settings_manager.cpp     | 46 ++++++++++--------------
 src/layer/layer_settings_manager.hpp     |  3 ++
 src/layer/layer_settings_util.cpp        | 25 +++++++++----
 src/layer/layer_settings_util.hpp        |  2 +-
 src/layer/vk_layer_settings.cpp          |  6 ++++
 tests/layer/test_setting_env.cpp         | 27 ++++++++++++++
 tests/layer/test_setting_util.cpp        | 14 ++++++--
 9 files changed, 88 insertions(+), 39 deletions(-)

diff --git a/include/vulkan/layer/vk_layer_settings.h b/include/vulkan/layer/vk_layer_settings.h
index a3efb10..10deab5 100644
--- a/include/vulkan/layer/vk_layer_settings.h
+++ b/include/vulkan/layer/vk_layer_settings.h
@@ -53,6 +53,9 @@ VkResult vlCreateLayerSettingSet(const char *pLayerName, const VkLayerSettingsCr
 
 void vlDestroyLayerSettingSet(VlLayerSettingSet layerSettingSet, const VkAllocationCallbacks *pAllocator);
 
+// Set a compatibility namespace to find layer settings using environment variables
+void vlSetLayerSettingCompatibilityNamespace(VlLayerSettingSet layerSettingSet, const char *name);
+
 // Check whether a setting was set either programmatically, from vk_layer_settings.txt or an environment variable
 VkBool32 vlHasLayerSetting(VlLayerSettingSet layerSettingSet, const char *pSettingName);
 
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index cf21fe1..091d900 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -119,6 +119,7 @@ function(lunarg_target_compiler_configurations TARGET_NAME WERROR_OPTION)
         target_compile_options(${TARGET_NAME} INTERFACE
             -Wpedantic
             -Wunreachable-code
+            -Wunused-function
             -Wall
             -Wextra
             -Wpointer-arith
diff --git a/src/layer/layer_settings_manager.cpp b/src/layer/layer_settings_manager.cpp
index 5b6e8b4..39ba31c 100644
--- a/src/layer/layer_settings_manager.cpp
+++ b/src/layer/layer_settings_manager.cpp
@@ -64,11 +64,6 @@ static std::string GetEnvironment(const char *variable) {
 #endif
 }
 
-static bool IsEnvironment(const char *variable) {
-    const std::string& result = GetEnvironment(variable);
-    return !result.empty();
-}
-
 #if defined(WIN32)
 // Check for admin rights
 static inline bool IsHighIntegrity() {
@@ -107,7 +102,9 @@ namespace vl {
 
 LayerSettings::LayerSettings(const char *pLayerName, const VkLayerSettingsCreateInfoEXT *pCreateInfo,
                              const VkAllocationCallbacks *pAllocator, VlLayerSettingLogCallback pCallback)
-    : layer_name(pLayerName), create_info(pCreateInfo), pCallback(pCallback) {
+    : layer_name(pLayerName)
+    , create_info(pCreateInfo)
+    , pCallback(pCallback) {
     (void)pAllocator;
     assert(pLayerName != nullptr);
 
@@ -265,21 +262,7 @@ std::vector<std::string> &LayerSettings::GetSettingCache(const std::string &sett
 bool LayerSettings::HasEnvSetting(const char *pSettingName) {
     assert(pSettingName != nullptr);
 
-    std::vector<std::string> layer_names;
-    layer_names.push_back(this->layer_name);
-    ::AddWorkaroundLayerNames(layer_names);
-
-    for (std::size_t layer_index = 0, layer_count = layer_names.size(); layer_index < layer_count; ++layer_index) {
-        const char *cur_layer_name = layer_names[layer_index].c_str();
-        for (int i = TRIM_FIRST, n = TRIM_LAST; i <= n; ++i) {
-            const std::string &env_name = GetEnvSettingName(cur_layer_name, pSettingName, static_cast<TrimMode>(i));
-            if (IsEnvironment(env_name.c_str())) {
-                return true;
-            }
-        }
-    }
-
-    return false;
+    return !GetEnvSetting(pSettingName).empty();
 }
 
 bool LayerSettings::HasFileSetting(const char *pSettingName) { 
@@ -297,24 +280,31 @@ bool LayerSettings::HasAPISetting(const char *pSettingName) {
 }
 
 std::string LayerSettings::GetEnvSetting(const char *pSettingName) {
-    std::string result;
-
     std::vector<std::string> layer_names;
     layer_names.push_back(this->layer_name);
     ::AddWorkaroundLayerNames(layer_names);
 
     for (std::size_t layer_index = 0, layer_count = layer_names.size(); layer_index < layer_count; ++layer_index) {
         const char* cur_layer_name = layer_names[layer_index].c_str();
-        for (int i = TRIM_FIRST, n = TRIM_LAST; i <= n; ++i) {
-            const std::string &env_name = GetEnvSettingName(cur_layer_name, pSettingName, static_cast<TrimMode>(i));
-            result = GetEnvironment(env_name.c_str());
+
+        if (!this->prefix.empty()) {
+            const std::string &env_name = GetEnvSettingName(cur_layer_name, this->prefix.c_str(), pSettingName, TRIM_NAMESPACE);
+            std::string result = GetEnvironment(env_name.c_str());
             if (!result.empty()) {
-                break;
+                return result;
+            }
+        }
+
+        for (int trim_index = TRIM_FIRST; trim_index <= TRIM_LAST; ++trim_index) {
+            const std::string &env_name = GetEnvSettingName(cur_layer_name, this->prefix.c_str(), pSettingName, static_cast<TrimMode>(trim_index));
+            std::string result = GetEnvironment(env_name.c_str());
+            if (!result.empty()) {
+                return result;
             }
         }
     }
 
-    return result;
+    return std::string();
 }
 
 std::string LayerSettings::GetFileSetting(const char *pSettingName) {
diff --git a/src/layer/layer_settings_manager.hpp b/src/layer/layer_settings_manager.hpp
index 99d728a..74dab5c 100644
--- a/src/layer/layer_settings_manager.hpp
+++ b/src/layer/layer_settings_manager.hpp
@@ -22,6 +22,8 @@ namespace vl {
                       const VkAllocationCallbacks *pAllocator, VlLayerSettingLogCallback pCallback);
         ~LayerSettings();
 
+        void SetPrefix(const char *pPrefix) { this->prefix = pPrefix; }
+
 	    bool HasEnvSetting(const char *pSettingName);
 
         bool HasFileSetting(const char *pSettingName);
@@ -52,6 +54,7 @@ namespace vl {
         std::filesystem::path FindSettingsFile();
         void ParseSettingsFile(const std::filesystem::path &filename);
 
+        std::string prefix;
         std::string layer_name;
         const VkLayerSettingsCreateInfoEXT *create_info{nullptr};
         VlLayerSettingLogCallback pCallback{nullptr};
diff --git a/src/layer/layer_settings_util.cpp b/src/layer/layer_settings_util.cpp
index d475406..e0c2f38 100644
--- a/src/layer/layer_settings_util.cpp
+++ b/src/layer/layer_settings_util.cpp
@@ -47,38 +47,49 @@ std::string GetFileSettingName(const char *pLayerName, const char *pSettingName)
     return settingName.str();
 }
 
-std::string GetEnvSettingName(const char *layer_key, const char *setting_key, TrimMode trim_mode) {
+static const char *GetDefaultPrefix() {
+#ifdef __ANDROID__
+    return "vulkan.";
+#else
+    return "";
+#endif
+}
+
+std::string GetEnvSettingName(const char *layer_key, const char *requested_prefix, const char *setting_key, TrimMode trim_mode) {
     std::stringstream result;
+    const std::string prefix = (requested_prefix == nullptr || trim_mode != TRIM_NAMESPACE) ? GetDefaultPrefix() : requested_prefix;
 
 #if defined(__ANDROID__)
+    const std::string full_prefix = std::string("debug.") + prefix + ".";
     switch (trim_mode) {
         default:
         case TRIM_NONE: {
-            result << "debug.vulkan." << GetFileSettingName(layer_key, setting_key);
+            result << full_prefix << GetFileSettingName(layer_key, setting_key);
             break;
         }
         case TRIM_VENDOR: {
-            result << "debug.vulkan." << GetFileSettingName(TrimVendor(layer_key).c_str(), setting_key);
+            result << full_prefix << GetFileSettingName(TrimVendor(layer_key).c_str(), setting_key);
             break;
         }
         case TRIM_NAMESPACE: {
-            result << "debug.vulkan." << setting_key;
+            result << full_prefix << setting_key;
             break;
         }
     }
 #else
+    const std::string full_prefix = std::string("VK_") + (prefix.empty() ? "" : prefix + "_");
     switch (trim_mode) {
         default:
         case TRIM_NONE: {
-            result << "VK_" << vl::ToUpper(TrimPrefix(layer_key)) << "_" << vl::ToUpper(setting_key);
+            result << full_prefix << vl::ToUpper(TrimPrefix(layer_key)) << "_" << vl::ToUpper(setting_key);
             break;
         }
         case TRIM_VENDOR: {
-            result << "VK_" << vl::ToUpper(TrimVendor(layer_key)) << "_" << vl::ToUpper(setting_key);
+            result << full_prefix << vl::ToUpper(TrimVendor(layer_key)) << "_" << vl::ToUpper(setting_key);
             break;
         }
         case TRIM_NAMESPACE: {
-            result << "VK_" << vl::ToUpper(setting_key);
+            result << full_prefix << vl::ToUpper(setting_key);
             break;
         }
     }
diff --git a/src/layer/layer_settings_util.hpp b/src/layer/layer_settings_util.hpp
index ba91022..957773a 100644
--- a/src/layer/layer_settings_util.hpp
+++ b/src/layer/layer_settings_util.hpp
@@ -31,7 +31,7 @@ namespace vl {
         TRIM_LAST = TRIM_NAMESPACE,
     };
 
-    std::string GetEnvSettingName(const char *layer_key, const char *setting_key, TrimMode trim_mode);
+    std::string GetEnvSettingName(const char *layer_key, const char* prefix, const char *setting_key, TrimMode trim_mode);
 
     std::string GetFileSettingName(const char *layer_key, const char *setting_key);
 
diff --git a/src/layer/vk_layer_settings.cpp b/src/layer/vk_layer_settings.cpp
index ffbaef1..f9295b8 100644
--- a/src/layer/vk_layer_settings.cpp
+++ b/src/layer/vk_layer_settings.cpp
@@ -48,6 +48,12 @@ void vlDestroyLayerSettingSet(VlLayerSettingSet layerSettingSet, const VkAllocat
     delete layer_setting_set;
 }
 
+void vlSetLayerSettingCompatibilityNamespace(VlLayerSettingSet layerSettingSet, const char *prefixName) {
+    vl::LayerSettings *layer_setting_set = (vl::LayerSettings *)layerSettingSet;
+
+    layer_setting_set->SetPrefix(prefixName);
+}
+
 VkBool32 vlHasLayerSetting(VlLayerSettingSet layerSettingSet, const char *pSettingName) {
     assert(layerSettingSet != VK_NULL_HANDLE);
     assert(pSettingName);
diff --git a/tests/layer/test_setting_env.cpp b/tests/layer/test_setting_env.cpp
index f701a37..545b0b7 100644
--- a/tests/layer/test_setting_env.cpp
+++ b/tests/layer/test_setting_env.cpp
@@ -96,6 +96,33 @@ TEST(test_layer_setting_env, EnvVar_TrimNamespace) {
     vlDestroyLayerSettingSet(layerSettingSet, nullptr);
 }
 
+TEST(test_layer_setting_env, EnvVar_TrimNamespace_OveriddenPrefix) {
+    SetEnv("VK_POUET_MY_SETTING_C=true,false");
+
+    VlLayerSettingSet layerSettingSet = VK_NULL_HANDLE;
+    vlCreateLayerSettingSet("VK_LAYER_LUNARG_test", nullptr, nullptr, nullptr, &layerSettingSet);
+
+    vlSetLayerSettingCompatibilityNamespace(layerSettingSet, "POUET");
+
+    EXPECT_TRUE(vlHasLayerSetting(layerSettingSet, "my_setting_c"));
+
+    uint32_t value_count_c = 0;
+    VkResult result_count_c =
+        vlGetLayerSettingValues(layerSettingSet, "my_setting_c", VL_LAYER_SETTING_TYPE_BOOL32, &value_count_c, nullptr);
+    EXPECT_EQ(VK_SUCCESS, result_count_c);
+    EXPECT_EQ(2, value_count_c);
+
+    std::vector<VkBool32> values_c(static_cast<std::size_t>(value_count_c));
+    VkResult result_complete_c =
+        vlGetLayerSettingValues(layerSettingSet, "my_setting_c", VL_LAYER_SETTING_TYPE_BOOL32, &value_count_c, &values_c[0]);
+    EXPECT_EQ(VK_SUCCESS, result_complete_c);
+    EXPECT_EQ(VK_TRUE, values_c[0]);
+    EXPECT_EQ(VK_FALSE, values_c[1]);
+    EXPECT_EQ(2, value_count_c);
+
+    vlDestroyLayerSettingSet(layerSettingSet, nullptr);
+}
+
 TEST(test_layer_setting_env, vlGetLayerSettingValues_Bool) {
     SetEnv("VK_LUNARG_TEST_MY_SETTING=true,false");
 
diff --git a/tests/layer/test_setting_util.cpp b/tests/layer/test_setting_util.cpp
index 2428272..627c67d 100644
--- a/tests/layer/test_setting_util.cpp
+++ b/tests/layer/test_setting_util.cpp
@@ -263,7 +263,7 @@ TEST(test_layer_settings_util, TrimVendor) {
 
 TEST(test_layer_settings_util, GetEnvSettingName_TrimNone) {
     {
-        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", "log_mode", vl::TRIM_NONE);
+        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", nullptr, "log_mode", vl::TRIM_NONE);
 
         EXPECT_STREQ("VK_LUNARG_TEST_LOG_MODE", result.c_str());
     }
@@ -271,7 +271,7 @@ TEST(test_layer_settings_util, GetEnvSettingName_TrimNone) {
 
 TEST(test_layer_settings_util, GetEnvSettingName_TrimVendor) {
     {
-        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", "log_mode", vl::TRIM_VENDOR);
+        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", nullptr, "log_mode", vl::TRIM_VENDOR);
 
         EXPECT_STREQ("VK_TEST_LOG_MODE", result.c_str());
     }
@@ -279,12 +279,20 @@ TEST(test_layer_settings_util, GetEnvSettingName_TrimVendor) {
 
 TEST(test_layer_settings_util, GetEnvSettingName_TrimNamespace) {
     {
-        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", "log_mode", vl::TRIM_NAMESPACE);
+        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", nullptr, "log_mode", vl::TRIM_NAMESPACE);
 
         EXPECT_STREQ("VK_LOG_MODE", result.c_str());
     }
 }
 
+TEST(test_layer_settings_util, GetEnvSettingName_TrimAddPrefix) {
+    {
+        const std::string result = vl::GetEnvSettingName("VK_LAYER_LUNARG_test", "LAYER", "log_mode", vl::TRIM_NAMESPACE);
+
+        EXPECT_STREQ("VK_LAYER_LOG_MODE", result.c_str());
+    }
+}
+
 TEST(test_layer_settings_util, GetFileSettingName) {
     {
         const std::string result = vl::GetFileSettingName("VK_LAYER_LUNARG_test", "log_mode");