From bc016aff47b0ca359d07d84ecf77a0f4e151bfab Mon Sep 17 00:00:00 2001
From: lynxnb <niccolo.betto@gmail.com>
Date: Tue, 18 Oct 2022 19:47:23 +0200
Subject: [PATCH] Make the vulkan validation layer toggleable via setting

As part of this commit, a new preference category for debug settings is being introduced. All future settings only relevant for debugging purposes will be put there. The category is hidden on release builds.
---
 .../main/cpp/skyline/common/android_settings.h    |  1 +
 app/src/main/cpp/skyline/common/settings.h        |  3 +++
 app/src/main/cpp/skyline/gpu.cpp                  | 12 +++++-------
 app/src/main/java/emu/skyline/SettingsActivity.kt |  5 +++++
 .../main/java/emu/skyline/utils/NativeSettings.kt |  9 +++++++++
 .../java/emu/skyline/utils/PreferenceSettings.kt  |  3 +++
 app/src/main/res/values/strings.xml               |  5 +++++
 app/src/main/res/xml/preferences.xml              | 15 +++++++++++++--
 8 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/app/src/main/cpp/skyline/common/android_settings.h b/app/src/main/cpp/skyline/common/android_settings.h
index a3f766e4..1e350f62 100644
--- a/app/src/main/cpp/skyline/common/android_settings.h
+++ b/app/src/main/cpp/skyline/common/android_settings.h
@@ -38,6 +38,7 @@ namespace skyline {
             disableFrameThrottling = ktSettings.GetBool("disableFrameThrottling");
             gpuDriver = ktSettings.GetString("gpuDriver");
             gpuDriverLibraryName = ktSettings.GetString("gpuDriverLibraryName");
+            validationLayer = ktSettings.GetBool("validationLayer");
         };
     };
 }
diff --git a/app/src/main/cpp/skyline/common/settings.h b/app/src/main/cpp/skyline/common/settings.h
index 79a62c41..8d2efc34 100644
--- a/app/src/main/cpp/skyline/common/settings.h
+++ b/app/src/main/cpp/skyline/common/settings.h
@@ -71,6 +71,9 @@ namespace skyline {
         Setting<std::string> gpuDriver; //!< The label of the GPU driver to use
         Setting<std::string> gpuDriverLibraryName; //!< The name of the GPU driver library to use
 
+        // Debug
+        Setting<bool> validationLayer; //!< If the vulkan validation layer is enabled
+
         Settings() = default;
 
         virtual ~Settings() = default;
diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp
index 4009f38e..b541bbb7 100644
--- a/app/src/main/cpp/skyline/gpu.cpp
+++ b/app/src/main/cpp/skyline/gpu.cpp
@@ -17,12 +17,10 @@ namespace skyline::gpu {
             .apiVersion = VkApiVersion,
         };
 
-        #ifdef NDEBUG
-        constexpr std::array<const char *, 0> requiredLayers{};
-        #else
-        constexpr std::array<const char *, 1> requiredLayers{
-            "VK_LAYER_KHRONOS_validation"
-        };
+        std::vector<const char *> requiredLayers{};
+        #ifndef NDEBUG
+        if (*state.settings->validationLayer)
+            requiredLayers.push_back("VK_LAYER_KHRONOS_validation");
         #endif
 
         auto instanceLayers{context.enumerateInstanceLayerProperties()};
@@ -63,7 +61,7 @@ namespace skyline::gpu {
 
         return vk::raii::Instance(context, vk::InstanceCreateInfo{
             .pApplicationInfo = &applicationInfo,
-            .enabledLayerCount = requiredLayers.size(),
+            .enabledLayerCount = static_cast<u32>(requiredLayers.size()),
             .ppEnabledLayerNames = requiredLayers.data(),
             .enabledExtensionCount = requiredInstanceExtensions.size(),
             .ppEnabledExtensionNames = requiredInstanceExtensions.data(),
diff --git a/app/src/main/java/emu/skyline/SettingsActivity.kt b/app/src/main/java/emu/skyline/SettingsActivity.kt
index d1aa9a05..12d1dadb 100644
--- a/app/src/main/java/emu/skyline/SettingsActivity.kt
+++ b/app/src/main/java/emu/skyline/SettingsActivity.kt
@@ -91,6 +91,11 @@ class SettingsActivity : AppCompatActivity() {
                     disableFrameThrottlingPref.isChecked = false
                 true
             }
+
+            // Only show debug settings in debug builds
+            @Suppress("SENSELESS_COMPARISON")
+            if (BuildConfig.BUILD_TYPE != "release")
+                findPreference<Preference>("category_debug")?.isVisible = true
         }
 
         override fun onDisplayPreferenceDialog(preference : Preference) {
diff --git a/app/src/main/java/emu/skyline/utils/NativeSettings.kt b/app/src/main/java/emu/skyline/utils/NativeSettings.kt
index 3e9e70b7..80bc9d39 100644
--- a/app/src/main/java/emu/skyline/utils/NativeSettings.kt
+++ b/app/src/main/java/emu/skyline/utils/NativeSettings.kt
@@ -6,19 +6,28 @@
 package emu.skyline.utils
 
 import android.content.Context
+import emu.skyline.BuildConfig
 
 /**
  * The settings that will be passed to libskyline when running and executable
  */
 class NativeSettings(context : Context, pref : PreferenceSettings) {
+    // System
     var isDocked : Boolean = pref.isDocked
     var usernameValue : String = pref.usernameValue
     var systemLanguage : Int = pref.systemLanguage
+
+    // Display
     var forceTripleBuffering : Boolean = pref.forceTripleBuffering
     var disableFrameThrottling : Boolean = pref.disableFrameThrottling
+
+    // GPU
     var gpuDriver : String = if (pref.gpuDriver == PreferenceSettings.SYSTEM_GPU_DRIVER) "" else pref.gpuDriver
     var gpuDriverLibraryName : String = if (pref.gpuDriver == PreferenceSettings.SYSTEM_GPU_DRIVER) "" else GpuDriverHelper.getLibraryName(context, pref.gpuDriver)
 
+    // Debug
+    var validationLayer : Boolean = BuildConfig.BUILD_TYPE != "release" && pref.validationLayer
+
     /**
      * Updates settings in libskyline during emulation
      */
diff --git a/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt b/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt
index e427c933..7a32800c 100644
--- a/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt
+++ b/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt
@@ -38,6 +38,9 @@ class PreferenceSettings @Inject constructor(@ApplicationContext private val con
     // GPU
     var gpuDriver by sharedPreferences(context, SYSTEM_GPU_DRIVER)
 
+    // Debug
+    var validationLayer by sharedPreferences(context, false)
+
     // Input
     var onScreenControl by sharedPreferences(context, true)
     var onScreenControlRecenterSticks by sharedPreferences(context, true)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 933f3239..5f27e701 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -69,6 +69,11 @@
     <string name="respect_display_cutout">Respect Display Cutout</string>
     <string name="respect_display_cutout_enabled">Do not draw UI elements in the cutout area</string>
     <string name="respect_display_cutout_disabled">Allow UI elements to be drawn in the cutout area</string>
+    <!-- Settings - Debug -->
+    <string name="debug">Debug</string>
+    <string name="validation_layer">Enable validation layer</string>
+    <string name="validation_layer_enabled">The Vulkan validation layer is enabled, major slowdowns are to be expected</string>
+    <string name="validation_layer_disabled">The Vulkan validation layer is disabled</string>
     <!-- Gpu Driver Activity -->
     <string name="gpu_driver">GPU Driver</string>
     <string name="add_gpu_driver">Add a GPU driver</string>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 1d1276ec..b68e4ca5 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -8,8 +8,8 @@
             app:title="@string/search_location" />
         <emu.skyline.preference.DocumentsProviderPreference
             app:key="document_provider"
-            app:title="@string/open_data_directory"
-            app:summary="@string/open_data_directory_summary"/>
+            app:summary="@string/open_data_directory_summary"
+            app:title="@string/open_data_directory" />
         <emu.skyline.preference.ThemePreference
             android:defaultValue="2"
             android:entries="@array/app_theme"
@@ -121,6 +121,17 @@
             app:key="respect_display_cutout"
             app:title="@string/respect_display_cutout" />
     </PreferenceCategory>
+    <PreferenceCategory
+        android:key="category_debug"
+        android:title="@string/debug"
+        app:isPreferenceVisible="false">
+        <CheckBoxPreference
+            android:defaultValue="false"
+            android:summaryOff="@string/validation_layer_disabled"
+            android:summaryOn="@string/validation_layer_enabled"
+            app:key="validation_layer"
+            app:title="@string/validation_layer" />
+    </PreferenceCategory>
     <PreferenceCategory
         android:key="category_input"
         android:title="@string/input"