From 20e51402b0c0221d63c923d049e6a4c706c5e2ba Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Sat, 26 Jun 2021 02:43:38 -0400
Subject: [PATCH 1/9] common: Force defaults for Settings::Setting's

Requires a default value when creating each per-game setting.
---
 src/common/settings.h | 97 ++++++++++++++++++++++++-------------------
 1 file changed, 55 insertions(+), 42 deletions(-)

diff --git a/src/common/settings.h b/src/common/settings.h
index 82ec18e275..dd2d8d4d8c 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -37,8 +37,9 @@ enum class CPUAccuracy : u32 {
 template <typename Type>
 class Setting final {
 public:
-    Setting() = default;
-    explicit Setting(Type val) : global{val} {}
+    explicit Setting(Type val) : global{val} {
+        default_value = val;
+    }
     ~Setting() = default;
     void SetGlobal(bool to_global) {
         use_global = to_global;
@@ -59,11 +60,15 @@ public:
             local = value;
         }
     }
+    Type GetDefault() const {
+        return default_value;
+    }
 
 private:
     bool use_global = true;
     Type global{};
     Type local{};
+    Type default_value{};
 };
 
 /**
@@ -108,14 +113,14 @@ struct Values {
     std::string audio_device_id;
     std::string sink_id;
     bool audio_muted;
-    Setting<bool> enable_audio_stretching;
-    Setting<float> volume;
+    Setting<bool> enable_audio_stretching{true};
+    Setting<float> volume{1.0f};
 
     // Core
-    Setting<bool> use_multi_core;
+    Setting<bool> use_multi_core{true};
 
     // Cpu
-    Setting<CPUAccuracy> cpu_accuracy;
+    Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Accurate};
 
     bool cpuopt_page_tables;
     bool cpuopt_block_linking;
@@ -127,61 +132,69 @@ struct Values {
     bool cpuopt_reduce_misalign_checks;
     bool cpuopt_fastmem;
 
-    Setting<bool> cpuopt_unsafe_unfuse_fma;
-    Setting<bool> cpuopt_unsafe_reduce_fp_error;
-    Setting<bool> cpuopt_unsafe_ignore_standard_fpcr;
-    Setting<bool> cpuopt_unsafe_inaccurate_nan;
-    Setting<bool> cpuopt_unsafe_fastmem_check;
+    Setting<bool> cpuopt_unsafe_unfuse_fma{true};
+    Setting<bool> cpuopt_unsafe_reduce_fp_error{true};
+    Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true};
+    Setting<bool> cpuopt_unsafe_inaccurate_nan{true};
+    Setting<bool> cpuopt_unsafe_fastmem_check{true};
 
     // Renderer
-    Setting<RendererBackend> renderer_backend;
+    Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL};
     bool renderer_debug;
-    Setting<int> vulkan_device;
+    Setting<int> vulkan_device{0};
 
-    Setting<u16> resolution_factor{1};
-    Setting<int> fullscreen_mode;
-    Setting<int> aspect_ratio;
-    Setting<int> max_anisotropy;
-    Setting<bool> use_frame_limit;
-    Setting<u16> frame_limit;
-    Setting<bool> use_disk_shader_cache;
-    Setting<GPUAccuracy> gpu_accuracy;
-    Setting<bool> use_asynchronous_gpu_emulation;
-    Setting<bool> use_nvdec_emulation;
-    Setting<bool> accelerate_astc;
-    Setting<bool> use_vsync;
-    Setting<bool> disable_fps_limit;
-    Setting<bool> use_assembly_shaders;
-    Setting<bool> use_asynchronous_shaders;
-    Setting<bool> use_fast_gpu_time;
-    Setting<bool> use_caches_gc;
+    Setting<u16> resolution_factor{0};
+    // *nix platforms may have issues with the borderless windowed fullscreen mode.
+    // Default to exclusive fullscreen on these platforms for now.
+    Setting<int> fullscreen_mode{
+#ifdef _WIN32
+        0
+#else
+        1
+#endif
+    };
+    Setting<int> aspect_ratio{0};
+    Setting<int> max_anisotropy{0};
+    Setting<bool> use_frame_limit{true};
+    Setting<u16> frame_limit{100};
+    Setting<bool> use_disk_shader_cache{true};
+    Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High};
+    Setting<bool> use_asynchronous_gpu_emulation{true};
+    Setting<bool> use_nvdec_emulation{true};
+    Setting<bool> accelerate_astc{true};
+    Setting<bool> use_vsync{true};
+    Setting<bool> disable_fps_limit{false};
+    Setting<bool> use_assembly_shaders{false};
+    Setting<bool> use_asynchronous_shaders{false};
+    Setting<bool> use_fast_gpu_time{true};
+    Setting<bool> use_caches_gc{false};
 
-    Setting<float> bg_red;
-    Setting<float> bg_green;
-    Setting<float> bg_blue;
+    Setting<float> bg_red{0.0f};
+    Setting<float> bg_green{0.0f};
+    Setting<float> bg_blue{0.0f};
 
     // System
-    Setting<std::optional<u32>> rng_seed;
+    Setting<std::optional<u32>> rng_seed{std::optional<u32>()};
     // Measured in seconds since epoch
     std::optional<std::chrono::seconds> custom_rtc;
     // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
     std::chrono::seconds custom_rtc_differential;
 
     s32 current_user;
-    Setting<s32> language_index;
-    Setting<s32> region_index;
-    Setting<s32> time_zone_index;
-    Setting<s32> sound_index;
+    Setting<s32> language_index{1};
+    Setting<s32> region_index{1};
+    Setting<s32> time_zone_index{0};
+    Setting<s32> sound_index{1};
 
     // Controls
     InputSetting<std::array<PlayerInput, 10>> players;
 
-    Setting<bool> use_docked_mode;
+    Setting<bool> use_docked_mode{true};
 
-    Setting<bool> vibration_enabled;
-    Setting<bool> enable_accurate_vibrations;
+    Setting<bool> vibration_enabled{true};
+    Setting<bool> enable_accurate_vibrations{false};
 
-    Setting<bool> motion_enabled;
+    Setting<bool> motion_enabled{true};
     std::string motion_device;
     std::string udp_input_servers;
 

From 35b17fa5e0a69c019852fed9ede9b64f08dd21a0 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Sat, 26 Jun 2021 02:45:14 -0400
Subject: [PATCH 2/9] configuration: Defer to common/settings for per-game
 settings defaults

Avoids double-setting defaults, and avoids potential accidents when
inconsistently setting the default on new settings.
---
 src/yuzu/configuration/config.cpp | 223 +++++++++++++-----------------
 src/yuzu/configuration/config.h   |   6 +-
 2 files changed, 101 insertions(+), 128 deletions(-)

diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 62bafc453e..2ad0ac32e6 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -491,8 +491,8 @@ void Config::ReadAudioValues() {
                 .toStdString();
     }
     ReadSettingGlobal(Settings::values.enable_audio_stretching,
-                      QStringLiteral("enable_audio_stretching"), true);
-    ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"), 1);
+                      QStringLiteral("enable_audio_stretching"));
+    ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"));
 
     qt_config->endGroup();
 }
@@ -515,7 +515,7 @@ void Config::ReadControlValues() {
     Settings::values.mouse_panning_sensitivity =
         ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
 
-    ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), true);
+    ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"));
 
     // Disable docked mode if handheld is selected
     const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
@@ -523,11 +523,10 @@ void Config::ReadControlValues() {
         Settings::values.use_docked_mode.SetValue(false);
     }
 
-    ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
-                      true);
+    ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"));
     ReadSettingGlobal(Settings::values.enable_accurate_vibrations,
-                      QStringLiteral("enable_accurate_vibrations"), false);
-    ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
+                      QStringLiteral("enable_accurate_vibrations"));
+    ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"));
 
     qt_config->endGroup();
 }
@@ -591,7 +590,7 @@ void Config::ReadMotionTouchValues() {
 void Config::ReadCoreValues() {
     qt_config->beginGroup(QStringLiteral("Core"));
 
-    ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), true);
+    ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"));
 
     qt_config->endGroup();
 }
@@ -751,18 +750,18 @@ void Config::ReadPathValues() {
 void Config::ReadCpuValues() {
     qt_config->beginGroup(QStringLiteral("Cpu"));
 
-    ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0);
+    ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"));
 
     ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma,
-                      QStringLiteral("cpuopt_unsafe_unfuse_fma"), true);
+                      QStringLiteral("cpuopt_unsafe_unfuse_fma"));
     ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error,
-                      QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true);
+                      QStringLiteral("cpuopt_unsafe_reduce_fp_error"));
     ReadSettingGlobal(Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
-                      QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"), true);
+                      QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"));
     ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
-                      QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
+                      QStringLiteral("cpuopt_unsafe_inaccurate_nan"));
     ReadSettingGlobal(Settings::values.cpuopt_unsafe_fastmem_check,
-                      QStringLiteral("cpuopt_unsafe_fastmem_check"), true);
+                      QStringLiteral("cpuopt_unsafe_fastmem_check"));
 
     if (global) {
         Settings::values.cpuopt_page_tables =
@@ -791,41 +790,32 @@ void Config::ReadCpuValues() {
 void Config::ReadRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
-    ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
+    ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"));
     ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
-    ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
-#ifdef _WIN32
-    ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0);
-#else
-    // *nix platforms may have issues with the borderless windowed fullscreen mode.
-    // Default to exclusive fullscreen on these platforms for now.
-    ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1);
-#endif
-    ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
-    ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
-    ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
-    ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"), 100);
+    ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"));
+    ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"));
+    ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"));
+    ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"));
+    ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"));
+    ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"));
     ReadSettingGlobal(Settings::values.use_disk_shader_cache,
-                      QStringLiteral("use_disk_shader_cache"), true);
-    ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 1);
+                      QStringLiteral("use_disk_shader_cache"));
+    ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"));
     ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
-                      QStringLiteral("use_asynchronous_gpu_emulation"), true);
-    ReadSettingGlobal(Settings::values.use_nvdec_emulation, QStringLiteral("use_nvdec_emulation"),
-                      true);
-    ReadSettingGlobal(Settings::values.accelerate_astc, QStringLiteral("accelerate_astc"), true);
-    ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
-    ReadSettingGlobal(Settings::values.disable_fps_limit, QStringLiteral("disable_fps_limit"),
-                      false);
-    ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
-                      false);
+                      QStringLiteral("use_asynchronous_gpu_emulation"));
+    ReadSettingGlobal(Settings::values.use_nvdec_emulation, QStringLiteral("use_nvdec_emulation"));
+    ReadSettingGlobal(Settings::values.accelerate_astc, QStringLiteral("accelerate_astc"));
+    ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"));
+    ReadSettingGlobal(Settings::values.disable_fps_limit, QStringLiteral("disable_fps_limit"));
+    ReadSettingGlobal(Settings::values.use_assembly_shaders,
+                      QStringLiteral("use_assembly_shaders"));
     ReadSettingGlobal(Settings::values.use_asynchronous_shaders,
-                      QStringLiteral("use_asynchronous_shaders"), false);
-    ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
-                      true);
-    ReadSettingGlobal(Settings::values.use_caches_gc, QStringLiteral("use_caches_gc"), false);
-    ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
-    ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
-    ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
+                      QStringLiteral("use_asynchronous_shaders"));
+    ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"));
+    ReadSettingGlobal(Settings::values.use_caches_gc, QStringLiteral("use_caches_gc"));
+    ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"));
+    ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"));
+    ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"));
 
     qt_config->endGroup();
 }
@@ -874,11 +864,11 @@ void Config::ReadSystemValues() {
     Settings::values.current_user =
         std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1);
 
-    ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"), 1);
+    ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"));
 
-    ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"), 1);
+    ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"));
 
-    ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"), 0);
+    ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"));
 
     bool rng_seed_enabled;
     ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
@@ -904,7 +894,7 @@ void Config::ReadSystemValues() {
         }
     }
 
-    ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1);
+    ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"));
 
     qt_config->endGroup();
 }
@@ -1188,8 +1178,8 @@ void Config::SaveAudioValues() {
                      QStringLiteral("auto"));
     }
     WriteSettingGlobal(QStringLiteral("enable_audio_stretching"),
-                       Settings::values.enable_audio_stretching, true);
-    WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume, 1.0f);
+                       Settings::values.enable_audio_stretching);
+    WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume);
 
     qt_config->endGroup();
 }
@@ -1205,12 +1195,11 @@ void Config::SaveControlValues() {
     SaveTouchscreenValues();
     SaveMotionTouchValues();
 
-    WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, true);
-    WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled,
-                       true);
+    WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode);
+    WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled);
     WriteSettingGlobal(QStringLiteral("enable_accurate_vibrations"),
-                       Settings::values.enable_accurate_vibrations, false);
-    WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
+                       Settings::values.enable_accurate_vibrations);
+    WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled);
     WriteSetting(QStringLiteral("motion_device"),
                  QString::fromStdString(Settings::values.motion_device),
                  QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
@@ -1228,7 +1217,7 @@ void Config::SaveControlValues() {
 void Config::SaveCoreValues() {
     qt_config->beginGroup(QStringLiteral("Core"));
 
-    WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, true);
+    WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core);
 
     qt_config->endGroup();
 }
@@ -1339,18 +1328,18 @@ void Config::SaveCpuValues() {
     WriteSettingGlobal(QStringLiteral("cpu_accuracy"),
                        static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
                        Settings::values.cpu_accuracy.UsingGlobal(),
-                       static_cast<u32>(Settings::CPUAccuracy::Accurate));
+                       static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()));
 
     WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
-                       Settings::values.cpuopt_unsafe_unfuse_fma, true);
+                       Settings::values.cpuopt_unsafe_unfuse_fma);
     WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
-                       Settings::values.cpuopt_unsafe_reduce_fp_error, true);
+                       Settings::values.cpuopt_unsafe_reduce_fp_error);
     WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"),
-                       Settings::values.cpuopt_unsafe_ignore_standard_fpcr, true);
+                       Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
     WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
-                       Settings::values.cpuopt_unsafe_inaccurate_nan, true);
+                       Settings::values.cpuopt_unsafe_inaccurate_nan);
     WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_fastmem_check"),
-                       Settings::values.cpuopt_unsafe_fastmem_check, true);
+                       Settings::values.cpuopt_unsafe_fastmem_check);
 
     if (global) {
         WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
@@ -1377,45 +1366,37 @@ void Config::SaveRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
     WriteSettingGlobal(QStringLiteral("backend"),
-                       static_cast<int>(Settings::values.renderer_backend.GetValue(global)),
-                       Settings::values.renderer_backend.UsingGlobal(), 0);
-    WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
-    WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
-#ifdef _WIN32
-    WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0);
-#else
-    // *nix platforms may have issues with the borderless windowed fullscreen mode.
-    // Default to exclusive fullscreen on these platforms for now.
-    WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1);
-#endif
-    WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
-    WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
-    WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
-    WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
+                       static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
+                       Settings::values.renderer_backend.UsingGlobal(),
+                       static_cast<u32>(Settings::values.renderer_backend.GetDefault()));
+    WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug);
+    WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device);
+    WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode);
+    WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio);
+    WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy);
+    WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit);
+    WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit);
     WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"),
-                       Settings::values.use_disk_shader_cache, true);
+                       Settings::values.use_disk_shader_cache);
     WriteSettingGlobal(QStringLiteral("gpu_accuracy"),
-                       static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)),
-                       Settings::values.gpu_accuracy.UsingGlobal(), 1);
+                       static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
+                       Settings::values.gpu_accuracy.UsingGlobal(),
+                       static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()));
     WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
-                       Settings::values.use_asynchronous_gpu_emulation, true);
-    WriteSettingGlobal(QStringLiteral("use_nvdec_emulation"), Settings::values.use_nvdec_emulation,
-                       true);
-    WriteSettingGlobal(QStringLiteral("accelerate_astc"), Settings::values.accelerate_astc, true);
-    WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
-    WriteSettingGlobal(QStringLiteral("disable_fps_limit"), Settings::values.disable_fps_limit,
-                       false);
+                       Settings::values.use_asynchronous_gpu_emulation);
+    WriteSettingGlobal(QStringLiteral("use_nvdec_emulation"), Settings::values.use_nvdec_emulation);
+    WriteSettingGlobal(QStringLiteral("accelerate_astc"), Settings::values.accelerate_astc);
+    WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync);
+    WriteSettingGlobal(QStringLiteral("disable_fps_limit"), Settings::values.disable_fps_limit);
     WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
-                       Settings::values.use_assembly_shaders, false);
+                       Settings::values.use_assembly_shaders);
     WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"),
-                       Settings::values.use_asynchronous_shaders, false);
-    WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
-                       true);
-    WriteSettingGlobal(QStringLiteral("use_caches_gc"), Settings::values.use_caches_gc, false);
-    // Cast to double because Qt's written float values are not human-readable
-    WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
-    WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
-    WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue, 0.0);
+                       Settings::values.use_asynchronous_shaders);
+    WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time);
+    WriteSettingGlobal(QStringLiteral("use_caches_gc"), Settings::values.use_caches_gc);
+    WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red);
+    WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green);
+    WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue);
 
     qt_config->endGroup();
 }
@@ -1454,10 +1435,10 @@ void Config::SaveShortcutValues() {
 void Config::SaveSystemValues() {
     qt_config->beginGroup(QStringLiteral("System"));
 
-    WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
-    WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index, 1);
-    WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index, 1);
-    WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
+    WriteSetting(QStringLiteral("current_user"), Settings::values.current_user);
+    WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index);
+    WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index);
+    WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index);
 
     WriteSettingGlobal(QStringLiteral("rng_seed_enabled"),
                        Settings::values.rng_seed.GetValue(global).has_value(),
@@ -1475,7 +1456,7 @@ void Config::SaveSystemValues() {
                      0);
     }
 
-    WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
+    WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index);
 
     qt_config->endGroup();
 }
@@ -1574,22 +1555,25 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
     return result;
 }
 
+QVariant Config::ReadSetting(const QString& name, Settings::CPUAccuracy default_value) const {
+    return ReadSetting(name, static_cast<u32>(default_value));
+}
+
+QVariant Config::ReadSetting(const QString& name, Settings::GPUAccuracy default_value) const {
+    return ReadSetting(name, static_cast<u32>(default_value));
+}
+
+QVariant Config::ReadSetting(const QString& name, Settings::RendererBackend default_value) const {
+    return ReadSetting(name, static_cast<u32>(default_value));
+}
+
 template <typename Type>
 void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) {
     const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
     setting.SetGlobal(use_global);
+    const Type& default_value = setting.GetDefault();
     if (global || !use_global) {
-        setting.SetValue(ReadSetting(name).value<Type>());
-    }
-}
-
-template <typename Type>
-void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
-                               const QVariant& default_value) {
-    const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
-    setting.SetGlobal(use_global);
-    if (global || !use_global) {
-        setting.SetValue(ReadSetting(name, default_value).value<Type>());
+        setting.SetValue(static_cast<QVariant>(ReadSetting(name, default_value)).value<Type>());
     }
 }
 
@@ -1617,20 +1601,9 @@ void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Typ
     if (!global) {
         qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
     }
-    if (global || !setting.UsingGlobal()) {
-        qt_config->setValue(name, setting.GetValue(global));
-    }
-}
-
-template <typename Type>
-void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
-                                const QVariant& default_value) {
-    if (!global) {
-        qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
-    }
     if (global || !setting.UsingGlobal()) {
         qt_config->setValue(name + QStringLiteral("/default"),
-                            setting.GetValue(global) == default_value.value<Type>());
+                            setting.GetValue(global) == setting.GetDefault());
         qt_config->setValue(name, setting.GetValue(global));
     }
 }
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 3c1de0ac91..62501997cc 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -104,14 +104,14 @@ private:
 
     QVariant ReadSetting(const QString& name) const;
     QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
+    QVariant ReadSetting(const QString& name, Settings::CPUAccuracy default_value) const;
+    QVariant ReadSetting(const QString& name, Settings::GPUAccuracy default_value) const;
+    QVariant ReadSetting(const QString& name, Settings::RendererBackend default_value) const;
     // Templated ReadSettingGlobal functions will also look for the use_global setting and set
     // both the value and the global state properly
     template <typename Type>
     void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
     template <typename Type>
-    void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
-                           const QVariant& default_value);
-    template <typename Type>
     void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
     // Templated WriteSettingGlobal functions will also write the global state if needed and will
     // skip writing the actual setting if it defers to the global value

From b91b76df4fe27d781bd95ddb89b78ff54df57029 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Mon, 28 Jun 2021 15:58:16 -0400
Subject: [PATCH 3/9] general: Make most settings a BasicSetting

Creates a new BasicSettings class in common/settings, and forces setting
a default and label for each setting that uses it in common/settings.
Moves defaults and labels from both frontends into common settings.
Creates a helper function in each frontend to facillitate reading the
settings now with the new default and label properties.

Settings::Setting is also now a subclass of Settings::BasicSetting. Also
adds documentation for both Setting and BasicSetting.
---
 src/audio_core/audio_out.cpp                  |   3 +-
 src/common/settings.cpp                       |  16 +-
 src/common/settings.h                         | 424 +++++++++----
 src/core/core.cpp                             |   6 +-
 src/core/frontend/applets/profile_select.cpp  |   2 +-
 src/core/hle/service/acc/profile_manager.cpp  |   3 +-
 src/core/hle/service/am/am.cpp                |   2 +-
 src/core/hle/service/nifm/nifm.cpp            |   6 +-
 src/core/hle/service/set/set.cpp              |   2 +-
 src/core/loader/nro.cpp                       |   4 +-
 src/core/loader/nso.cpp                       |   4 +-
 src/core/reporter.cpp                         |   2 +-
 src/core/telemetry_session.cpp                |   2 +-
 src/input_common/mouse/mouse_poller.cpp       |   3 +-
 src/input_common/touch_from_button.cpp        |   3 +-
 src/input_common/udp/client.cpp               |   4 +-
 .../renderer_vulkan/renderer_vulkan.cpp       |  15 +-
 src/yuzu/configuration/config.cpp             | 589 ++++++++----------
 src/yuzu/configuration/config.h               |  75 ++-
 src/yuzu/configuration/configure_audio.cpp    |   8 +-
 .../configuration/configure_cpu_debug.cpp     |  21 +-
 src/yuzu/configuration/configure_debug.cpp    |  23 +-
 .../configuration/configure_filesystem.cpp    |  11 +-
 .../configure_input_advanced.cpp              |  12 +-
 .../configuration/configure_motion_touch.cpp  |  11 +-
 .../configure_profile_manager.cpp             |  11 +-
 src/yuzu/configuration/configure_service.cpp  |   2 +-
 src/yuzu/configuration/configure_web.cpp      |  10 +-
 src/yuzu/main.cpp                             |   5 +-
 src/yuzu_cmd/config.cpp                       | 192 +++---
 src/yuzu_cmd/config.h                         |   6 +
 src/yuzu_cmd/yuzu.cpp                         |   2 +-
 32 files changed, 813 insertions(+), 666 deletions(-)

diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index 20a756dcef..44a899d08a 100644
--- a/src/audio_core/audio_out.cpp
+++ b/src/audio_core/audio_out.cpp
@@ -30,7 +30,8 @@ StreamPtr AudioOut::OpenStream(Core::Timing::CoreTiming& core_timing, u32 sample
                                u32 num_channels, std::string&& name,
                                Stream::ReleaseCallback&& release_callback) {
     if (!sink) {
-        sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
+        sink = CreateSinkFromID(Settings::values.sink_id.GetValue(),
+                                Settings::values.audio_device_id.GetValue());
     }
 
     return std::make_shared<Stream>(
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index e1bb4b7ff0..0061e29cca 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -41,7 +41,7 @@ void LogSettings() {
     LOG_INFO(Config, "yuzu Configuration:");
     log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
     log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
-    log_setting("System_CurrentUser", values.current_user);
+    log_setting("System_CurrentUser", values.current_user.GetValue());
     log_setting("System_LanguageIndex", values.language_index.GetValue());
     log_setting("System_RegionIndex", values.region_index.GetValue());
     log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
@@ -61,18 +61,18 @@ void LogSettings() {
     log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
     log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
     log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
-    log_setting("Audio_OutputEngine", values.sink_id);
+    log_setting("Audio_OutputEngine", values.sink_id.GetValue());
     log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
-    log_setting("Audio_OutputDevice", values.audio_device_id);
-    log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
+    log_setting("Audio_OutputDevice", values.audio_device_id.GetValue());
+    log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
     log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
     log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
     log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
     log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
     log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
-    log_setting("Debugging_ProgramArgs", values.program_args);
-    log_setting("Services_BCATBackend", values.bcat_backend);
-    log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local);
+    log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
+    log_setting("Services_BCATBackend", values.bcat_backend.GetValue());
+    log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue());
 }
 
 bool IsConfiguringGlobal() {
@@ -94,7 +94,7 @@ bool IsGPULevelHigh() {
 
 bool IsFastmemEnabled() {
     if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
-        return values.cpuopt_fastmem;
+        return static_cast<bool>(values.cpuopt_fastmem);
     }
     return true;
 }
diff --git a/src/common/settings.h b/src/common/settings.h
index dd2d8d4d8c..13896debf0 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -10,10 +10,12 @@
 #include <map>
 #include <optional>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "common/common_types.h"
 #include "common/settings_input.h"
+#include "input_common/udp/client.h"
 
 namespace Settings {
 
@@ -34,73 +36,236 @@ enum class CPUAccuracy : u32 {
     DebugMode = 2,
 };
 
+/** The BasicSetting class is a simple resource manager. It defines a label and default value
+ * alongside the actual value of the setting for simpler and less-error prone use with frontend
+ * configurations. Setting a default value and label is required, though subclasses may deviate from
+ * this requirement.
+ */
 template <typename Type>
-class Setting final {
+class BasicSetting {
+protected:
+    BasicSetting() = default;
+
+    /**
+     * Only sets the setting to the given initializer, leaving the other members to their default
+     * initializers.
+     *
+     * @param global_val Initial value of the setting
+     */
+    explicit BasicSetting(const Type& global_val) : global{global_val} {}
+
 public:
-    explicit Setting(Type val) : global{val} {
-        default_value = val;
-    }
-    ~Setting() = default;
-    void SetGlobal(bool to_global) {
-        use_global = to_global;
-    }
-    bool UsingGlobal() const {
-        return use_global;
-    }
-    Type GetValue(bool need_global = false) const {
-        if (use_global || need_global) {
-            return global;
-        }
-        return local;
+    /**
+     * Sets a default value, label, and setting value.
+     *
+     * @param default_val Intial value of the setting, and default value of the setting
+     * @param name Label for the setting
+     */
+    explicit BasicSetting(const Type& default_val, const std::string& name)
+        : default_value{default_val}, global{default_val}, label{name} {}
+    ~BasicSetting() = default;
+
+    /**
+     *  Returns a reference to the setting's value.
+     *
+     * @returns A reference to the setting
+     */
+    [[nodiscard]] const Type& GetValue() const {
+        return global;
     }
+
+    /**
+     * Sets the setting to the given value.
+     *
+     * @param value The desired value
+     */
     void SetValue(const Type& value) {
-        if (use_global) {
-            global = value;
-        } else {
-            local = value;
-        }
+        Type temp{value};
+        std::swap(global, temp);
     }
-    Type GetDefault() const {
+
+    /**
+     * Returns the value that this setting was created with.
+     *
+     * @returns A reference to the default value
+     */
+    [[nodiscard]] const Type& GetDefault() const {
         return default_value;
     }
 
-private:
-    bool use_global = true;
-    Type global{};
-    Type local{};
-    Type default_value{};
+    /**
+     * Returns the label this setting was created with.
+     *
+     * @returns A reference to the label
+     */
+    [[nodiscard]] const std::string& GetLabel() const {
+        return label;
+    }
+
+    /**
+     * Assigns a value to the setting.
+     *
+     * @param value The desired setting value
+     *
+     * @returns A reference to the setting
+     */
+    const Type& operator=(const Type& value) {
+        Type temp{value};
+        std::swap(global, temp);
+        return global;
+    }
+
+    /**
+     * Returns a reference to the setting.
+     *
+     * @returns A reference to the setting
+     */
+    explicit operator const Type&() const {
+        return global;
+    }
+
+protected:
+    const Type default_value{}; ///< The default value
+    Type global{};              ///< The setting
+    const std::string label{};  ///< The setting's label
 };
 
 /**
- * The InputSetting class allows for getting a reference to either the global or local members.
+ * The Setting class is a slightly more complex version of the BasicSetting class. This adds a
+ * custom setting to switch to when a guest application specifically requires it. The effect is that
+ * other components of the emulator can access the setting's intended value without any need for the
+ * component to ask whether the custom or global setting is needed at the moment.
+ *
+ * By default, the global setting is used.
+ *
+ * Like the BasicSetting, this requires setting a default value and label to use.
+ */
+template <typename Type>
+class Setting final : public BasicSetting<Type> {
+public:
+    /**
+     * Sets a default value, label, and setting value.
+     *
+     * @param default_val Intial value of the setting, and default value of the setting
+     * @param name Label for the setting
+     */
+    explicit Setting(const Type& default_val, const std::string& name)
+        : BasicSetting<Type>(default_val, name) {}
+    ~Setting() = default;
+
+    /**
+     * Tells this setting to represent either the global or custom setting when other member
+     * functions are used. Setting to_global to true means using the global setting, to false
+     * false for the custom setting.
+     *
+     * @param to_global Whether to use the global or custom setting.
+     */
+    void SetGlobal(bool to_global) {
+        use_global = to_global;
+    }
+
+    /**
+     * Returns whether this setting is using the global setting or not.
+     *
+     * @returns The global state
+     */
+    [[nodiscard]] bool UsingGlobal() const {
+        return use_global;
+    }
+
+    /**
+     * Returns either the global or custom setting depending on the values of this setting's global
+     * state or if the global value was specifically requested.
+     *
+     * @param need_global Request global value regardless of setting's state; defaults to false
+     *
+     * @returns The required value of the setting
+     */
+    [[nodiscard]] const Type& GetValue(bool need_global = false) const {
+        if (use_global || need_global) {
+            return this->global;
+        }
+        return custom;
+    }
+
+    /**
+     * Sets the current setting value depending on the global state.
+     *
+     * @param value The new value
+     */
+    void SetValue(const Type& value) {
+        Type temp{value};
+        if (use_global) {
+            std::swap(this->global, temp);
+        } else {
+            std::swap(custom, temp);
+        }
+    }
+
+    /**
+     * Assigns the current setting value depending on the global state.
+     *
+     * @param value The new value
+     *
+     * @returns A reference to the current setting value
+     */
+    const Type& operator=(const Type& value) {
+        Type temp{value};
+        if (use_global) {
+            std::swap(this->global, temp);
+            return this->global;
+        }
+        std::swap(custom, temp);
+        return custom;
+    }
+
+    /**
+     * Returns the current setting value depending on the global state.
+     *
+     * @returns A reference to the current setting value
+     */
+    explicit operator const Type&() const {
+        if (use_global) {
+            return this->global;
+        }
+        return custom;
+    }
+
+private:
+    bool use_global{true}; ///< The setting's global state
+    Type custom{};         ///< The custom value of the setting
+};
+
+/**
+ * The InputSetting class allows for getting a reference to either the global or custom members.
  * This is required as we cannot easily modify the values of user-defined types within containers
  * using the SetValue() member function found in the Setting class. The primary purpose of this
- * class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
- * setting and allows for easily accessing and modifying both settings.
+ * class is to store an array of 10 PlayerInput structs for both the global and custom setting and
+ * allows for easily accessing and modifying both settings.
  */
 template <typename Type>
 class InputSetting final {
 public:
     InputSetting() = default;
-    explicit InputSetting(Type val) : global{val} {}
+    explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
     ~InputSetting() = default;
     void SetGlobal(bool to_global) {
         use_global = to_global;
     }
-    bool UsingGlobal() const {
+    [[nodiscard]] bool UsingGlobal() const {
         return use_global;
     }
-    Type& GetValue(bool need_global = false) {
+    [[nodiscard]] Type& GetValue(bool need_global = false) {
         if (use_global || need_global) {
             return global;
         }
-        return local;
+        return custom;
     }
 
 private:
-    bool use_global = true;
-    Type global{};
-    Type local{};
+    bool use_global{true}; ///< The setting's global state
+    Type global{};         ///< The setting
+    Type custom{};         ///< The custom setting value
 };
 
 struct TouchFromButtonMap {
@@ -110,152 +275,155 @@ struct TouchFromButtonMap {
 
 struct Values {
     // Audio
-    std::string audio_device_id;
-    std::string sink_id;
-    bool audio_muted;
-    Setting<bool> enable_audio_stretching{true};
-    Setting<float> volume{1.0f};
+    BasicSetting<std::string> audio_device_id{"auto", "output_device"};
+    BasicSetting<std::string> sink_id{"auto", "output_engine"};
+    BasicSetting<bool> audio_muted{false, "audio_muted"};
+    Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
+    Setting<float> volume{1.0f, "volume"};
 
     // Core
-    Setting<bool> use_multi_core{true};
+    Setting<bool> use_multi_core{true, "use_multi_core"};
 
     // Cpu
-    Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Accurate};
+    Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Accurate, "cpu_accuracy"};
 
-    bool cpuopt_page_tables;
-    bool cpuopt_block_linking;
-    bool cpuopt_return_stack_buffer;
-    bool cpuopt_fast_dispatcher;
-    bool cpuopt_context_elimination;
-    bool cpuopt_const_prop;
-    bool cpuopt_misc_ir;
-    bool cpuopt_reduce_misalign_checks;
-    bool cpuopt_fastmem;
+    BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
+    BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
+    BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
+    BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
+    BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
+    BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
+    BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
+    BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
+    BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
 
-    Setting<bool> cpuopt_unsafe_unfuse_fma{true};
-    Setting<bool> cpuopt_unsafe_reduce_fp_error{true};
-    Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true};
-    Setting<bool> cpuopt_unsafe_inaccurate_nan{true};
-    Setting<bool> cpuopt_unsafe_fastmem_check{true};
+    Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
+    Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
+    Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
+    Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
+    Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
 
     // Renderer
-    Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL};
-    bool renderer_debug;
-    Setting<int> vulkan_device{0};
+    Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
+    BasicSetting<bool> renderer_debug{false, "debug"};
+    Setting<int> vulkan_device{0, "vulkan_device"};
 
-    Setting<u16> resolution_factor{0};
+    Setting<u16> resolution_factor{0, "resolution_factor"};
     // *nix platforms may have issues with the borderless windowed fullscreen mode.
     // Default to exclusive fullscreen on these platforms for now.
     Setting<int> fullscreen_mode{
 #ifdef _WIN32
-        0
+        0,
 #else
-        1
+        1,
 #endif
-    };
-    Setting<int> aspect_ratio{0};
-    Setting<int> max_anisotropy{0};
-    Setting<bool> use_frame_limit{true};
-    Setting<u16> frame_limit{100};
-    Setting<bool> use_disk_shader_cache{true};
-    Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High};
-    Setting<bool> use_asynchronous_gpu_emulation{true};
-    Setting<bool> use_nvdec_emulation{true};
-    Setting<bool> accelerate_astc{true};
-    Setting<bool> use_vsync{true};
-    Setting<bool> disable_fps_limit{false};
-    Setting<bool> use_assembly_shaders{false};
-    Setting<bool> use_asynchronous_shaders{false};
-    Setting<bool> use_fast_gpu_time{true};
-    Setting<bool> use_caches_gc{false};
+        "fullscreen_mode"};
+    Setting<int> aspect_ratio{0, "aspect_ratio"};
+    Setting<int> max_anisotropy{0, "max_anisotropy"};
+    Setting<bool> use_frame_limit{true, "use_frame_limit"};
+    Setting<u16> frame_limit{100, "frame_limit"};
+    Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
+    Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
+    Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
+    Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
+    Setting<bool> accelerate_astc{true, "accelerate_astc"};
+    Setting<bool> use_vsync{true, "use_vsync"};
+    Setting<bool> disable_fps_limit{false, "disable_fps_limit"};
+    Setting<bool> use_assembly_shaders{false, "use_assembly_shaders"};
+    Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
+    Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
+    Setting<bool> use_caches_gc{false, "use_caches_gc"};
 
-    Setting<float> bg_red{0.0f};
-    Setting<float> bg_green{0.0f};
-    Setting<float> bg_blue{0.0f};
+    Setting<float> bg_red{0.0f, "bg_red"};
+    Setting<float> bg_green{0.0f, "bg_green"};
+    Setting<float> bg_blue{0.0f, "bg_blue"};
 
     // System
-    Setting<std::optional<u32>> rng_seed{std::optional<u32>()};
+    Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
     // Measured in seconds since epoch
     std::optional<std::chrono::seconds> custom_rtc;
     // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
     std::chrono::seconds custom_rtc_differential;
 
-    s32 current_user;
-    Setting<s32> language_index{1};
-    Setting<s32> region_index{1};
-    Setting<s32> time_zone_index{0};
-    Setting<s32> sound_index{1};
+    BasicSetting<s32> current_user{0, "current_user"};
+    Setting<s32> language_index{1, "language_index"};
+    Setting<s32> region_index{1, "region_index"};
+    Setting<s32> time_zone_index{0, "time_zone_index"};
+    Setting<s32> sound_index{1, "sound_index"};
 
     // Controls
     InputSetting<std::array<PlayerInput, 10>> players;
 
-    Setting<bool> use_docked_mode{true};
+    Setting<bool> use_docked_mode{true, "use_docked_mode"};
 
-    Setting<bool> vibration_enabled{true};
-    Setting<bool> enable_accurate_vibrations{false};
+    Setting<bool> vibration_enabled{true, "vibration_enabled"};
+    Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
 
-    Setting<bool> motion_enabled{true};
-    std::string motion_device;
-    std::string udp_input_servers;
+    Setting<bool> motion_enabled{true, "motion_enabled"};
+    BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
+                                            "motion_device"};
+    BasicSetting<std::string> udp_input_servers{InputCommon::CemuhookUDP::DEFAULT_SRV,
+                                                "udp_input_servers"};
 
-    bool mouse_panning;
-    float mouse_panning_sensitivity;
-    bool mouse_enabled;
+    BasicSetting<bool> mouse_panning{false, "mouse_panning"};
+    BasicSetting<float> mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"};
+    BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
     std::string mouse_device;
     MouseButtonsRaw mouse_buttons;
 
-    bool emulate_analog_keyboard;
-    bool keyboard_enabled;
+    BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
+    BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
     KeyboardKeysRaw keyboard_keys;
     KeyboardModsRaw keyboard_mods;
 
-    bool debug_pad_enabled;
+    BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
     ButtonsRaw debug_pad_buttons;
     AnalogsRaw debug_pad_analogs;
 
     TouchscreenInput touchscreen;
 
-    bool use_touch_from_button;
-    std::string touch_device;
-    int touch_from_button_map_index;
+    BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
+    BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
+                                           "touch_device"};
+    BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
     std::vector<TouchFromButtonMap> touch_from_button_maps;
 
     std::atomic_bool is_device_reload_pending{true};
 
     // Data Storage
-    bool use_virtual_sd;
-    bool gamecard_inserted;
-    bool gamecard_current_game;
-    std::string gamecard_path;
+    BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
+    BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
+    BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"};
+    BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"};
 
     // Debugging
     bool record_frame_times;
-    bool use_gdbstub;
-    u16 gdbstub_port;
-    std::string program_args;
-    bool dump_exefs;
-    bool dump_nso;
-    bool enable_fs_access_log;
-    bool reporting_services;
-    bool quest_flag;
-    bool disable_macro_jit;
-    bool extended_logging;
-    bool use_debug_asserts;
-    bool use_auto_stub;
+    BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
+    BasicSetting<u16> gdbstub_port{0, "gdbstub_port"};
+    BasicSetting<std::string> program_args{std::string(), "program_args"};
+    BasicSetting<bool> dump_exefs{false, "dump_exefs"};
+    BasicSetting<bool> dump_nso{false, "dump_nso"};
+    BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
+    BasicSetting<bool> reporting_services{false, "reporting_services"};
+    BasicSetting<bool> quest_flag{false, "quest_flag"};
+    BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"};
+    BasicSetting<bool> extended_logging{false, "extended_logging"};
+    BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
+    BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
 
     // Miscellaneous
-    std::string log_filter;
-    bool use_dev_keys;
+    BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
+    BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
 
     // Services
-    std::string bcat_backend;
-    bool bcat_boxcat_local;
+    BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
+    BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
 
     // WebService
-    bool enable_telemetry;
-    std::string web_api_url;
-    std::string yuzu_username;
-    std::string yuzu_token;
+    BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
+    BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
+    BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"};
+    BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"};
 
     // Add-Ons
     std::map<u64, std::vector<std::string>> disabled_addons;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index e6f1aa0e7b..fc6ec95124 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -263,9 +263,9 @@ struct System::Impl {
         if (Settings::values.gamecard_inserted) {
             if (Settings::values.gamecard_current_game) {
                 fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
-            } else if (!Settings::values.gamecard_path.empty()) {
-                fs_controller.SetGameCard(
-                    GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
+            } else if (!Settings::values.gamecard_path.GetValue().empty()) {
+                fs_controller.SetGameCard(GetGameFileFromPath(
+                    virtual_filesystem, static_cast<std::string>(Settings::values.gamecard_path)));
             }
         }
 
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp
index 8d960d1ca9..4c58c310f8 100644
--- a/src/core/frontend/applets/profile_select.cpp
+++ b/src/core/frontend/applets/profile_select.cpp
@@ -13,7 +13,7 @@ ProfileSelectApplet::~ProfileSelectApplet() = default;
 void DefaultProfileSelectApplet::SelectProfile(
     std::function<void(std::optional<Common::UUID>)> callback) const {
     Service::Account::ProfileManager manager;
-    callback(manager.GetUser(Settings::values.current_user).value_or(Common::UUID{}));
+    callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
     LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
 }
 
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index f72d5d5611..24a1c91572 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -48,7 +48,8 @@ ProfileManager::ProfileManager() {
         CreateNewUser(UUID::Generate(), "yuzu");
     }
 
-    auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1);
+    auto current =
+        std::clamp<int>(static_cast<s32>(Settings::values.current_user), 0, MAX_USERS - 1);
 
     // If user index don't exist. Load the first user and change the active user
     if (!UserExistsIndex(current)) {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index b578153d36..23ebc11382 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1443,7 +1443,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
         params.is_account_selected = 1;
 
         Account::ProfileManager profile_manager{};
-        const auto uuid = profile_manager.GetUser(Settings::values.current_user);
+        const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
         ASSERT(uuid);
         params.current_user = uuid->uuid;
 
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index f03b2666a7..e742db48f3 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -179,7 +179,7 @@ private:
         IPC::ResponseBuilder rb{ctx, 3};
         rb.Push(ResultSuccess);
 
-        if (Settings::values.bcat_backend == "none") {
+        if (Settings::values.bcat_backend.GetValue() == "none") {
             rb.PushEnum(RequestState::NotSubmitted);
         } else {
             rb.PushEnum(RequestState::Connected);
@@ -384,7 +384,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 3};
         rb.Push(ResultSuccess);
-        if (Settings::values.bcat_backend == "none") {
+        if (Settings::values.bcat_backend.GetValue() == "none") {
             rb.Push<u8>(0);
         } else {
             rb.Push<u8>(1);
@@ -395,7 +395,7 @@ private:
 
         IPC::ResponseBuilder rb{ctx, 3};
         rb.Push(ResultSuccess);
-        if (Settings::values.bcat_backend == "none") {
+        if (Settings::values.bcat_backend.GetValue() == "none") {
             rb.Push<u8>(0);
         } else {
             rb.Push<u8>(1);
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index ece2a74c61..522a604a59 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -160,7 +160,7 @@ void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.Push(static_cast<u32>(Settings::values.quest_flag));
+    rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
 }
 
 void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 6185552022..951ea966ea 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -155,8 +155,8 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
         codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
     }
 
-    if (!Settings::values.program_args.empty()) {
-        const auto arg_data = Settings::values.program_args;
+    if (!Settings::values.program_args.GetValue().empty()) {
+        const auto arg_data = Settings::values.program_args.GetValue();
         codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
         NSOArgumentHeader args_header{
             NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 0f5cfda682..4a2224c029 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -104,8 +104,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
         codeset.segments[i].size = nso_header.segments[i].size;
     }
 
-    if (should_pass_arguments && !Settings::values.program_args.empty()) {
-        const auto arg_data{Settings::values.program_args};
+    if (should_pass_arguments && !Settings::values.program_args.GetValue().empty()) {
+        const auto arg_data{Settings::values.program_args.GetValue()};
 
         codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
         NSOArgumentHeader args_header{
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 82b0f535aa..cfaf50105a 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -397,7 +397,7 @@ void Reporter::ClearFSAccessLog() const {
 }
 
 bool Reporter::IsReportingEnabled() const {
-    return Settings::values.reporting_services;
+    return Settings::values.reporting_services.GetValue();
 }
 
 } // namespace Core
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index d4c23ced2d..44b8bab5bd 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -212,7 +212,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
 
     // Log user configuration information
     constexpr auto field_type = Telemetry::FieldType::UserConfig;
-    AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
+    AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
     AddField(field_type, "Audio_EnableAudioStretching",
              Settings::values.enable_audio_stretching.GetValue());
     AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 758f7af1fd..4861a131e6 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -84,7 +84,8 @@ public:
         std::lock_guard lock{mutex};
         const auto axis_value =
             static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
-        return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
+        return axis_value * Settings::values.mouse_panning_sensitivity.GetValue() /
+               (100.0f * range);
     }
 
     std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
index 5b24fd8bf1..87207f48f7 100644
--- a/src/input_common/touch_from_button.cpp
+++ b/src/input_common/touch_from_button.cpp
@@ -12,8 +12,7 @@ namespace InputCommon {
 class TouchFromButtonDevice final : public Input::TouchDevice {
 public:
     TouchFromButtonDevice() {
-        const auto button_index =
-            static_cast<std::size_t>(Settings::values.touch_from_button_map_index);
+        const auto button_index = Settings::values.touch_from_button_map_index.GetValue();
         const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
 
         for (const auto& config_entry : buttons) {
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index bc1dfab3d5..9b0aec7970 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -201,7 +201,7 @@ bool Client::DeviceConnected(std::size_t pad) const {
 void Client::ReloadSockets() {
     Reset();
 
-    std::stringstream servers_ss(Settings::values.udp_input_servers);
+    std::stringstream servers_ss(static_cast<std::string>(Settings::values.udp_input_servers));
     std::string server_token;
     std::size_t client = 0;
     while (std::getline(servers_ss, server_token, ',')) {
@@ -370,7 +370,7 @@ std::optional<std::size_t> Client::GetUnusedFingerID() const {
 
 void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
     // TODO: Use custom calibration per device
-    const Common::ParamPackage touch_param(Settings::values.touch_device);
+    const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
     const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
     const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
     const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 3986eb172a..2bab2b4f51 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -97,19 +97,14 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
                                Core::Frontend::EmuWindow& emu_window,
                                Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
                                std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
-    : RendererBase(emu_window, std::move(context_)),
-      telemetry_session(telemetry_session_),
-      cpu_memory(cpu_memory_),
-      gpu(gpu_),
-      library(OpenLibrary()),
+    : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
+      cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary()),
       instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
-                              true, Settings::values.renderer_debug)),
+                              true, Settings::values.renderer_debug.GetValue())),
       debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
       surface(CreateSurface(instance, render_window)),
-      device(CreateDevice(instance, dld, *surface)),
-      memory_allocator(device, false),
-      state_tracker(gpu),
-      scheduler(device, state_tracker),
+      device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
+      state_tracker(gpu), scheduler(device, state_tracker),
       swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
                 render_window.GetFramebufferLayout().height, false),
       blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 2ad0ac32e6..d36aaade2e 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -272,6 +272,82 @@ void Config::Initialize(const std::string& config_name) {
     }
 }
 
+// Explicity std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
+// can it implicitly convert a QVariant back to a {std::,Q}string
+template <>
+void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
+    const QString name = QString::fromStdString(setting.GetLabel());
+    if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
+        setting.SetValue(setting.GetDefault());
+    } else {
+        setting.SetValue(qt_config->value(name, QString::fromStdString(setting.GetDefault()))
+                             .toString()
+                             .toStdString());
+    }
+}
+template <typename Type>
+void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
+    const QString name = QString::fromStdString(setting.GetLabel());
+    if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
+        setting.SetValue(setting.GetDefault());
+    } else {
+        setting.SetValue(
+            static_cast<QVariant>(qt_config->value(name, setting.GetDefault())).value<Type>());
+    }
+}
+
+// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant
+template <>
+void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& setting) {
+    const QString name = QString::fromStdString(setting.GetLabel());
+    qt_config->setValue(name + QStringLiteral("/default"),
+                        setting.GetValue() == setting.GetDefault());
+    qt_config->setValue(name, QString::fromStdString(setting.GetValue()));
+}
+// Explicit float definition: use a double as Qt doesn't write legible floats to config files
+template <>
+void Config::WriteBasicSetting(const Settings::BasicSetting<float>& setting) {
+    const QString name = QString::fromStdString(setting.GetLabel());
+    const double value = setting.GetValue();
+    qt_config->setValue(name + QStringLiteral("/default"),
+                        setting.GetValue() == setting.GetDefault());
+    qt_config->setValue(name, value);
+}
+template <typename Type>
+void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
+    const QString name = QString::fromStdString(setting.GetLabel());
+    qt_config->setValue(name + QStringLiteral("/default"),
+                        setting.GetValue() == setting.GetDefault());
+    qt_config->setValue(name, setting.GetValue());
+}
+
+// Explicit float definition: use a double as Qt doesn't write legible floats to config files
+template <>
+void Config::WriteGlobalSetting(const Settings::Setting<float>& setting) {
+    const QString name = QString::fromStdString(setting.GetLabel());
+    const double value = setting.GetValue(global);
+    if (!global) {
+        qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+    }
+    if (global || !setting.UsingGlobal()) {
+        qt_config->setValue(name + QStringLiteral("/default"),
+                            setting.GetValue(global) == setting.GetDefault());
+        qt_config->setValue(name, value);
+    }
+}
+template <typename Type>
+void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) {
+    QString name = QString::fromStdString(setting.GetLabel());
+    if (!global) {
+        qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+    }
+    if (global || !setting.UsingGlobal()) {
+        qt_config->setValue(name + QStringLiteral("/default"),
+                            setting.GetValue(global) == setting.GetDefault());
+        qt_config->setValue(name, setting.GetValue(global));
+    }
+}
+
 void Config::ReadPlayerValue(std::size_t player_index) {
     const QString player_prefix = [this, player_index] {
         if (type == ConfigType::InputProfile) {
@@ -395,8 +471,7 @@ void Config::ReadPlayerValue(std::size_t player_index) {
 }
 
 void Config::ReadDebugValues() {
-    Settings::values.debug_pad_enabled =
-        ReadSetting(QStringLiteral("debug_pad_enabled"), false).toBool();
+    ReadBasicSetting(Settings::values.debug_pad_enabled);
 
     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
@@ -432,8 +507,7 @@ void Config::ReadDebugValues() {
 }
 
 void Config::ReadKeyboardValues() {
-    Settings::values.keyboard_enabled =
-        ReadSetting(QStringLiteral("keyboard_enabled"), false).toBool();
+    ReadBasicSetting(Settings::values.keyboard_enabled);
 
     std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
                    Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
@@ -446,7 +520,7 @@ void Config::ReadKeyboardValues() {
 }
 
 void Config::ReadMouseValues() {
-    Settings::values.mouse_enabled = ReadSetting(QStringLiteral("mouse_enabled"), false).toBool();
+    ReadBasicSetting(Settings::values.mouse_enabled);
 
     for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
         const std::string default_param =
@@ -481,18 +555,11 @@ void Config::ReadAudioValues() {
     qt_config->beginGroup(QStringLiteral("Audio"));
 
     if (global) {
-        Settings::values.sink_id =
-            ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
-                .toString()
-                .toStdString();
-        Settings::values.audio_device_id =
-            ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
-                .toString()
-                .toStdString();
+        ReadBasicSetting(Settings::values.audio_device_id);
+        ReadBasicSetting(Settings::values.sink_id);
     }
-    ReadSettingGlobal(Settings::values.enable_audio_stretching,
-                      QStringLiteral("enable_audio_stretching"));
-    ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"));
+    ReadGlobalSetting(Settings::values.enable_audio_stretching);
+    ReadGlobalSetting(Settings::values.volume);
 
     qt_config->endGroup();
 }
@@ -509,13 +576,11 @@ void Config::ReadControlValues() {
     ReadTouchscreenValues();
     ReadMotionTouchValues();
 
-    Settings::values.emulate_analog_keyboard =
-        ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
+    ReadBasicSetting(Settings::values.emulate_analog_keyboard);
     Settings::values.mouse_panning = false;
-    Settings::values.mouse_panning_sensitivity =
-        ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
+    ReadBasicSetting(Settings::values.mouse_panning_sensitivity);
 
-    ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"));
+    ReadGlobalSetting(Settings::values.use_docked_mode);
 
     // Disable docked mode if handheld is selected
     const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
@@ -523,10 +588,9 @@ void Config::ReadControlValues() {
         Settings::values.use_docked_mode.SetValue(false);
     }
 
-    ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"));
-    ReadSettingGlobal(Settings::values.enable_accurate_vibrations,
-                      QStringLiteral("enable_accurate_vibrations"));
-    ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"));
+    ReadGlobalSetting(Settings::values.vibration_enabled);
+    ReadGlobalSetting(Settings::values.enable_accurate_vibrations);
+    ReadGlobalSetting(Settings::values.motion_enabled);
 
     qt_config->endGroup();
 }
@@ -564,33 +628,19 @@ void Config::ReadMotionTouchValues() {
     }
     qt_config->endArray();
 
-    Settings::values.motion_device =
-        ReadSetting(QStringLiteral("motion_device"),
-                    QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"))
-            .toString()
-            .toStdString();
-    Settings::values.touch_device =
-        ReadSetting(QStringLiteral("touch_device"),
-                    QStringLiteral("min_x:100,min_y:50,max_x:1800,max_y:850"))
-            .toString()
-            .toStdString();
-    Settings::values.use_touch_from_button =
-        ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool();
-    Settings::values.touch_from_button_map_index =
-        ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
-    Settings::values.touch_from_button_map_index =
-        std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
-    Settings::values.udp_input_servers =
-        ReadSetting(QStringLiteral("udp_input_servers"),
-                    QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV))
-            .toString()
-            .toStdString();
+    ReadBasicSetting(Settings::values.motion_device);
+    ReadBasicSetting(Settings::values.touch_device);
+    ReadBasicSetting(Settings::values.use_touch_from_button);
+    ReadBasicSetting(Settings::values.touch_from_button_map_index);
+    Settings::values.touch_from_button_map_index = std::clamp(
+        Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
+    ReadBasicSetting(Settings::values.udp_input_servers);
 }
 
 void Config::ReadCoreValues() {
     qt_config->beginGroup(QStringLiteral("Core"));
 
-    ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"));
+    ReadGlobalSetting(Settings::values.use_multi_core);
 
     qt_config->endGroup();
 }
@@ -598,7 +648,7 @@ void Config::ReadCoreValues() {
 void Config::ReadDataStorageValues() {
     qt_config->beginGroup(QStringLiteral("Data Storage"));
 
-    Settings::values.use_virtual_sd = ReadSetting(QStringLiteral("use_virtual_sd"), true).toBool();
+    ReadBasicSetting(Settings::values.use_virtual_sd);
     FS::SetYuzuPath(
         FS::YuzuPath::NANDDir,
         qt_config
@@ -627,12 +677,9 @@ void Config::ReadDataStorageValues() {
                     QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)))
             .toString()
             .toStdString());
-    Settings::values.gamecard_inserted =
-        ReadSetting(QStringLiteral("gamecard_inserted"), false).toBool();
-    Settings::values.gamecard_current_game =
-        ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
-    Settings::values.gamecard_path =
-        ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString();
+    ReadBasicSetting(Settings::values.gamecard_inserted);
+    ReadBasicSetting(Settings::values.gamecard_current_game);
+    ReadBasicSetting(Settings::values.gamecard_path);
 
     qt_config->endGroup();
 }
@@ -643,34 +690,24 @@ void Config::ReadDebuggingValues() {
     // Intentionally not using the QT default setting as this is intended to be changed in the ini
     Settings::values.record_frame_times =
         qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
-    Settings::values.program_args =
-        ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString();
-    Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool();
-    Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool();
-    Settings::values.enable_fs_access_log =
-        ReadSetting(QStringLiteral("enable_fs_access_log"), false).toBool();
-    Settings::values.reporting_services =
-        ReadSetting(QStringLiteral("reporting_services"), false).toBool();
-    Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool();
-    Settings::values.disable_macro_jit =
-        ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
-    Settings::values.extended_logging =
-        ReadSetting(QStringLiteral("extended_logging"), false).toBool();
-    Settings::values.use_debug_asserts =
-        ReadSetting(QStringLiteral("use_debug_asserts"), false).toBool();
-    Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
+    ReadBasicSetting(Settings::values.program_args);
+    ReadBasicSetting(Settings::values.dump_exefs);
+    ReadBasicSetting(Settings::values.dump_nso);
+    ReadBasicSetting(Settings::values.enable_fs_access_log);
+    ReadBasicSetting(Settings::values.reporting_services);
+    ReadBasicSetting(Settings::values.quest_flag);
+    ReadBasicSetting(Settings::values.disable_macro_jit);
+    ReadBasicSetting(Settings::values.extended_logging);
+    ReadBasicSetting(Settings::values.use_debug_asserts);
+    ReadBasicSetting(Settings::values.use_auto_stub);
 
     qt_config->endGroup();
 }
 
 void Config::ReadServiceValues() {
     qt_config->beginGroup(QStringLiteral("Services"));
-    Settings::values.bcat_backend =
-        ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("none"))
-            .toString()
-            .toStdString();
-    Settings::values.bcat_boxcat_local =
-        ReadSetting(QStringLiteral("bcat_boxcat_local"), false).toBool();
+    ReadBasicSetting(Settings::values.bcat_backend);
+    ReadBasicSetting(Settings::values.bcat_boxcat_local);
     qt_config->endGroup();
 }
 
@@ -696,11 +733,8 @@ void Config::ReadDisabledAddOnValues() {
 void Config::ReadMiscellaneousValues() {
     qt_config->beginGroup(QStringLiteral("Miscellaneous"));
 
-    Settings::values.log_filter =
-        ReadSetting(QStringLiteral("log_filter"), QStringLiteral("*:Info"))
-            .toString()
-            .toStdString();
-    Settings::values.use_dev_keys = ReadSetting(QStringLiteral("use_dev_keys"), false).toBool();
+    ReadBasicSetting(Settings::values.log_filter);
+    ReadBasicSetting(Settings::values.use_dev_keys);
 
     qt_config->endGroup();
 }
@@ -750,38 +784,24 @@ void Config::ReadPathValues() {
 void Config::ReadCpuValues() {
     qt_config->beginGroup(QStringLiteral("Cpu"));
 
-    ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"));
+    ReadGlobalSetting(Settings::values.cpu_accuracy);
 
-    ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma,
-                      QStringLiteral("cpuopt_unsafe_unfuse_fma"));
-    ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error,
-                      QStringLiteral("cpuopt_unsafe_reduce_fp_error"));
-    ReadSettingGlobal(Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
-                      QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"));
-    ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
-                      QStringLiteral("cpuopt_unsafe_inaccurate_nan"));
-    ReadSettingGlobal(Settings::values.cpuopt_unsafe_fastmem_check,
-                      QStringLiteral("cpuopt_unsafe_fastmem_check"));
+    ReadGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
+    ReadGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
+    ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
+    ReadGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
+    ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
 
     if (global) {
-        Settings::values.cpuopt_page_tables =
-            ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
-        Settings::values.cpuopt_block_linking =
-            ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool();
-        Settings::values.cpuopt_return_stack_buffer =
-            ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool();
-        Settings::values.cpuopt_fast_dispatcher =
-            ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool();
-        Settings::values.cpuopt_context_elimination =
-            ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool();
-        Settings::values.cpuopt_const_prop =
-            ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool();
-        Settings::values.cpuopt_misc_ir =
-            ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
-        Settings::values.cpuopt_reduce_misalign_checks =
-            ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
-        Settings::values.cpuopt_fastmem =
-            ReadSetting(QStringLiteral("cpuopt_fastmem"), true).toBool();
+        ReadBasicSetting(Settings::values.cpuopt_page_tables);
+        ReadBasicSetting(Settings::values.cpuopt_block_linking);
+        ReadBasicSetting(Settings::values.cpuopt_return_stack_buffer);
+        ReadBasicSetting(Settings::values.cpuopt_fast_dispatcher);
+        ReadBasicSetting(Settings::values.cpuopt_context_elimination);
+        ReadBasicSetting(Settings::values.cpuopt_const_prop);
+        ReadBasicSetting(Settings::values.cpuopt_misc_ir);
+        ReadBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
+        ReadBasicSetting(Settings::values.cpuopt_fastmem);
     }
 
     qt_config->endGroup();
@@ -790,32 +810,28 @@ void Config::ReadCpuValues() {
 void Config::ReadRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
-    ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"));
-    ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
-    ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"));
-    ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"));
-    ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"));
-    ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"));
-    ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"));
-    ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"));
-    ReadSettingGlobal(Settings::values.use_disk_shader_cache,
-                      QStringLiteral("use_disk_shader_cache"));
-    ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"));
-    ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
-                      QStringLiteral("use_asynchronous_gpu_emulation"));
-    ReadSettingGlobal(Settings::values.use_nvdec_emulation, QStringLiteral("use_nvdec_emulation"));
-    ReadSettingGlobal(Settings::values.accelerate_astc, QStringLiteral("accelerate_astc"));
-    ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"));
-    ReadSettingGlobal(Settings::values.disable_fps_limit, QStringLiteral("disable_fps_limit"));
-    ReadSettingGlobal(Settings::values.use_assembly_shaders,
-                      QStringLiteral("use_assembly_shaders"));
-    ReadSettingGlobal(Settings::values.use_asynchronous_shaders,
-                      QStringLiteral("use_asynchronous_shaders"));
-    ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"));
-    ReadSettingGlobal(Settings::values.use_caches_gc, QStringLiteral("use_caches_gc"));
-    ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"));
-    ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"));
-    ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"));
+    ReadGlobalSetting(Settings::values.renderer_backend);
+    ReadBasicSetting(Settings::values.renderer_debug);
+    ReadGlobalSetting(Settings::values.vulkan_device);
+    ReadGlobalSetting(Settings::values.fullscreen_mode);
+    ReadGlobalSetting(Settings::values.aspect_ratio);
+    ReadGlobalSetting(Settings::values.max_anisotropy);
+    ReadGlobalSetting(Settings::values.use_frame_limit);
+    ReadGlobalSetting(Settings::values.frame_limit);
+    ReadGlobalSetting(Settings::values.use_disk_shader_cache);
+    ReadGlobalSetting(Settings::values.gpu_accuracy);
+    ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
+    ReadGlobalSetting(Settings::values.use_nvdec_emulation);
+    ReadGlobalSetting(Settings::values.accelerate_astc);
+    ReadGlobalSetting(Settings::values.use_vsync);
+    ReadGlobalSetting(Settings::values.disable_fps_limit);
+    ReadGlobalSetting(Settings::values.use_assembly_shaders);
+    ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
+    ReadGlobalSetting(Settings::values.use_fast_gpu_time);
+    ReadGlobalSetting(Settings::values.use_caches_gc);
+    ReadGlobalSetting(Settings::values.bg_red);
+    ReadGlobalSetting(Settings::values.bg_green);
+    ReadGlobalSetting(Settings::values.bg_blue);
 
     qt_config->endGroup();
 }
@@ -860,15 +876,15 @@ void Config::ReadShortcutValues() {
 void Config::ReadSystemValues() {
     qt_config->beginGroup(QStringLiteral("System"));
 
-    ReadSettingGlobal(Settings::values.current_user, QStringLiteral("current_user"), 0);
-    Settings::values.current_user =
-        std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1);
+    ReadBasicSetting(Settings::values.current_user);
+    Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
+                                                    Service::Account::MAX_USERS - 1);
 
-    ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"));
+    ReadGlobalSetting(Settings::values.language_index);
 
-    ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"));
+    ReadGlobalSetting(Settings::values.region_index);
 
-    ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"));
+    ReadGlobalSetting(Settings::values.time_zone_index);
 
     bool rng_seed_enabled;
     ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
@@ -894,7 +910,7 @@ void Config::ReadSystemValues() {
         }
     }
 
-    ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"));
+    ReadGlobalSetting(Settings::values.sound_index);
 
     qt_config->endGroup();
 }
@@ -978,16 +994,10 @@ void Config::ReadUILayoutValues() {
 void Config::ReadWebServiceValues() {
     qt_config->beginGroup(QStringLiteral("WebService"));
 
-    Settings::values.enable_telemetry =
-        ReadSetting(QStringLiteral("enable_telemetry"), true).toBool();
-    Settings::values.web_api_url =
-        ReadSetting(QStringLiteral("web_api_url"), QStringLiteral("https://api.yuzu-emu.org"))
-            .toString()
-            .toStdString();
-    Settings::values.yuzu_username =
-        ReadSetting(QStringLiteral("yuzu_username")).toString().toStdString();
-    Settings::values.yuzu_token =
-        ReadSetting(QStringLiteral("yuzu_token")).toString().toStdString();
+    ReadBasicSetting(Settings::values.enable_telemetry);
+    ReadBasicSetting(Settings::values.web_api_url);
+    ReadBasicSetting(Settings::values.yuzu_username);
+    ReadBasicSetting(Settings::values.yuzu_token);
 
     qt_config->endGroup();
 }
@@ -1073,7 +1083,7 @@ void Config::SavePlayerValue(std::size_t player_index) {
 }
 
 void Config::SaveDebugValues() {
-    WriteSetting(QStringLiteral("debug_pad_enabled"), Settings::values.debug_pad_enabled, false);
+    WriteBasicSetting(Settings::values.debug_pad_enabled);
     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
         WriteSetting(QStringLiteral("debug_pad_") +
@@ -1093,7 +1103,7 @@ void Config::SaveDebugValues() {
 }
 
 void Config::SaveMouseValues() {
-    WriteSetting(QStringLiteral("mouse_enabled"), Settings::values.mouse_enabled, false);
+    WriteBasicSetting(Settings::values.mouse_enabled);
 
     for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
         const std::string default_param =
@@ -1116,19 +1126,11 @@ void Config::SaveTouchscreenValues() {
 }
 
 void Config::SaveMotionTouchValues() {
-    WriteSetting(QStringLiteral("motion_device"),
-                 QString::fromStdString(Settings::values.motion_device),
-                 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
-    WriteSetting(QStringLiteral("touch_device"),
-                 QString::fromStdString(Settings::values.touch_device),
-                 QStringLiteral("engine:emu_window"));
-    WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button,
-                 false);
-    WriteSetting(QStringLiteral("touch_from_button_map"),
-                 Settings::values.touch_from_button_map_index, 0);
-    WriteSetting(QStringLiteral("udp_input_servers"),
-                 QString::fromStdString(Settings::values.udp_input_servers),
-                 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV));
+    WriteBasicSetting(Settings::values.motion_device);
+    WriteBasicSetting(Settings::values.touch_device);
+    WriteBasicSetting(Settings::values.use_touch_from_button);
+    WriteBasicSetting(Settings::values.touch_from_button_map_index);
+    WriteBasicSetting(Settings::values.udp_input_servers);
 
     qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
     for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
@@ -1171,15 +1173,11 @@ void Config::SaveAudioValues() {
     qt_config->beginGroup(QStringLiteral("Audio"));
 
     if (global) {
-        WriteSetting(QStringLiteral("output_engine"),
-                     QString::fromStdString(Settings::values.sink_id), QStringLiteral("auto"));
-        WriteSetting(QStringLiteral("output_device"),
-                     QString::fromStdString(Settings::values.audio_device_id),
-                     QStringLiteral("auto"));
+        WriteBasicSetting(Settings::values.sink_id);
+        WriteBasicSetting(Settings::values.audio_device_id);
     }
-    WriteSettingGlobal(QStringLiteral("enable_audio_stretching"),
-                       Settings::values.enable_audio_stretching);
-    WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume);
+    WriteGlobalSetting(Settings::values.enable_audio_stretching);
+    WriteGlobalSetting(Settings::values.volume);
 
     qt_config->endGroup();
 }
@@ -1195,29 +1193,21 @@ void Config::SaveControlValues() {
     SaveTouchscreenValues();
     SaveMotionTouchValues();
 
-    WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode);
-    WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled);
-    WriteSettingGlobal(QStringLiteral("enable_accurate_vibrations"),
-                       Settings::values.enable_accurate_vibrations);
-    WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled);
-    WriteSetting(QStringLiteral("motion_device"),
-                 QString::fromStdString(Settings::values.motion_device),
-                 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
-    WriteSetting(QStringLiteral("touch_device"),
-                 QString::fromStdString(Settings::values.touch_device),
-                 QStringLiteral("engine:emu_window"));
-    WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
-    WriteSetting(QStringLiteral("emulate_analog_keyboard"),
-                 Settings::values.emulate_analog_keyboard, false);
-    WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
-                 Settings::values.mouse_panning_sensitivity, 1.0f);
+    WriteGlobalSetting(Settings::values.use_docked_mode);
+    WriteGlobalSetting(Settings::values.vibration_enabled);
+    WriteGlobalSetting(Settings::values.enable_accurate_vibrations);
+    WriteGlobalSetting(Settings::values.motion_enabled);
+    WriteBasicSetting(Settings::values.keyboard_enabled);
+    WriteBasicSetting(Settings::values.emulate_analog_keyboard);
+    WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
+
     qt_config->endGroup();
 }
 
 void Config::SaveCoreValues() {
     qt_config->beginGroup(QStringLiteral("Core"));
 
-    WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core);
+    WriteGlobalSetting(Settings::values.use_multi_core);
 
     qt_config->endGroup();
 }
@@ -1225,7 +1215,7 @@ void Config::SaveCoreValues() {
 void Config::SaveDataStorageValues() {
     qt_config->beginGroup(QStringLiteral("Data Storage"));
 
-    WriteSetting(QStringLiteral("use_virtual_sd"), Settings::values.use_virtual_sd, true);
+    WriteBasicSetting(Settings::values.use_virtual_sd);
     WriteSetting(QStringLiteral("nand_directory"),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -1238,11 +1228,9 @@ void Config::SaveDataStorageValues() {
     WriteSetting(QStringLiteral("dump_directory"),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
-    WriteSetting(QStringLiteral("gamecard_inserted"), Settings::values.gamecard_inserted, false);
-    WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game,
-                 false);
-    WriteSetting(QStringLiteral("gamecard_path"),
-                 QString::fromStdString(Settings::values.gamecard_path), QString{});
+    WriteBasicSetting(Settings::values.gamecard_inserted);
+    WriteBasicSetting(Settings::values.gamecard_current_game);
+    WriteBasicSetting(Settings::values.gamecard_path);
 
     qt_config->endGroup();
 }
@@ -1252,24 +1240,23 @@ void Config::SaveDebuggingValues() {
 
     // Intentionally not using the QT default setting as this is intended to be changed in the ini
     qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
-    WriteSetting(QStringLiteral("program_args"),
-                 QString::fromStdString(Settings::values.program_args), QString{});
-    WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
-    WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
-    WriteSetting(QStringLiteral("enable_fs_access_log"), Settings::values.enable_fs_access_log,
-                 false);
-    WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
-    WriteSetting(QStringLiteral("use_debug_asserts"), Settings::values.use_debug_asserts, false);
-    WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
+    WriteBasicSetting(Settings::values.program_args);
+    WriteBasicSetting(Settings::values.dump_exefs);
+    WriteBasicSetting(Settings::values.dump_nso);
+    WriteBasicSetting(Settings::values.enable_fs_access_log);
+    WriteBasicSetting(Settings::values.quest_flag);
+    WriteBasicSetting(Settings::values.use_debug_asserts);
+    WriteBasicSetting(Settings::values.disable_macro_jit);
 
     qt_config->endGroup();
 }
 
 void Config::SaveServiceValues() {
     qt_config->beginGroup(QStringLiteral("Services"));
-    WriteSetting(QStringLiteral("bcat_backend"),
-                 QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("none"));
-    WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false);
+
+    WriteBasicSetting(Settings::values.bcat_backend);
+    WriteBasicSetting(Settings::values.bcat_boxcat_local);
+
     qt_config->endGroup();
 }
 
@@ -1295,9 +1282,8 @@ void Config::SaveDisabledAddOnValues() {
 void Config::SaveMiscellaneousValues() {
     qt_config->beginGroup(QStringLiteral("Miscellaneous"));
 
-    WriteSetting(QStringLiteral("log_filter"), QString::fromStdString(Settings::values.log_filter),
-                 QStringLiteral("*:Info"));
-    WriteSetting(QStringLiteral("use_dev_keys"), Settings::values.use_dev_keys, false);
+    WriteBasicSetting(Settings::values.log_filter);
+    WriteBasicSetting(Settings::values.use_dev_keys);
 
     qt_config->endGroup();
 }
@@ -1325,38 +1311,27 @@ void Config::SavePathValues() {
 void Config::SaveCpuValues() {
     qt_config->beginGroup(QStringLiteral("Cpu"));
 
-    WriteSettingGlobal(QStringLiteral("cpu_accuracy"),
-                       static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
-                       Settings::values.cpu_accuracy.UsingGlobal(),
-                       static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()));
+    WriteSetting(QStringLiteral("cpu_accuracy"),
+                 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
+                 static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()),
+                 Settings::values.cpu_accuracy.UsingGlobal());
 
-    WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
-                       Settings::values.cpuopt_unsafe_unfuse_fma);
-    WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
-                       Settings::values.cpuopt_unsafe_reduce_fp_error);
-    WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"),
-                       Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
-    WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
-                       Settings::values.cpuopt_unsafe_inaccurate_nan);
-    WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_fastmem_check"),
-                       Settings::values.cpuopt_unsafe_fastmem_check);
+    WriteGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
+    WriteGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
+    WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
+    WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
+    WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
 
     if (global) {
-        WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
-                     true);
-        WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
-                     true);
-        WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"),
-                     Settings::values.cpuopt_return_stack_buffer, true);
-        WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"),
-                     Settings::values.cpuopt_fast_dispatcher, true);
-        WriteSetting(QStringLiteral("cpuopt_context_elimination"),
-                     Settings::values.cpuopt_context_elimination, true);
-        WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true);
-        WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
-        WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
-                     Settings::values.cpuopt_reduce_misalign_checks, true);
-        WriteSetting(QStringLiteral("cpuopt_fastmem"), Settings::values.cpuopt_fastmem, true);
+        WriteBasicSetting(Settings::values.cpuopt_page_tables);
+        WriteBasicSetting(Settings::values.cpuopt_block_linking);
+        WriteBasicSetting(Settings::values.cpuopt_return_stack_buffer);
+        WriteBasicSetting(Settings::values.cpuopt_fast_dispatcher);
+        WriteBasicSetting(Settings::values.cpuopt_context_elimination);
+        WriteBasicSetting(Settings::values.cpuopt_const_prop);
+        WriteBasicSetting(Settings::values.cpuopt_misc_ir);
+        WriteBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
+        WriteBasicSetting(Settings::values.cpuopt_fastmem);
     }
 
     qt_config->endGroup();
@@ -1365,38 +1340,34 @@ void Config::SaveCpuValues() {
 void Config::SaveRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
-    WriteSettingGlobal(QStringLiteral("backend"),
-                       static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
-                       Settings::values.renderer_backend.UsingGlobal(),
-                       static_cast<u32>(Settings::values.renderer_backend.GetDefault()));
-    WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug);
-    WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device);
-    WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode);
-    WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio);
-    WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy);
-    WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit);
-    WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit);
-    WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"),
-                       Settings::values.use_disk_shader_cache);
-    WriteSettingGlobal(QStringLiteral("gpu_accuracy"),
-                       static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
-                       Settings::values.gpu_accuracy.UsingGlobal(),
-                       static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()));
-    WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
-                       Settings::values.use_asynchronous_gpu_emulation);
-    WriteSettingGlobal(QStringLiteral("use_nvdec_emulation"), Settings::values.use_nvdec_emulation);
-    WriteSettingGlobal(QStringLiteral("accelerate_astc"), Settings::values.accelerate_astc);
-    WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync);
-    WriteSettingGlobal(QStringLiteral("disable_fps_limit"), Settings::values.disable_fps_limit);
-    WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
-                       Settings::values.use_assembly_shaders);
-    WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"),
-                       Settings::values.use_asynchronous_shaders);
-    WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time);
-    WriteSettingGlobal(QStringLiteral("use_caches_gc"), Settings::values.use_caches_gc);
-    WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red);
-    WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green);
-    WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue);
+    WriteSetting(QString::fromStdString(Settings::values.renderer_backend.GetLabel()),
+                 static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
+                 static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
+                 Settings::values.renderer_backend.UsingGlobal());
+    WriteBasicSetting(Settings::values.renderer_debug);
+    WriteGlobalSetting(Settings::values.vulkan_device);
+    WriteGlobalSetting(Settings::values.fullscreen_mode);
+    WriteGlobalSetting(Settings::values.aspect_ratio);
+    WriteGlobalSetting(Settings::values.max_anisotropy);
+    WriteGlobalSetting(Settings::values.use_frame_limit);
+    WriteGlobalSetting(Settings::values.frame_limit);
+    WriteGlobalSetting(Settings::values.use_disk_shader_cache);
+    WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
+                 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
+                 static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()),
+                 Settings::values.gpu_accuracy.UsingGlobal());
+    WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
+    WriteGlobalSetting(Settings::values.use_nvdec_emulation);
+    WriteGlobalSetting(Settings::values.accelerate_astc);
+    WriteGlobalSetting(Settings::values.use_vsync);
+    WriteGlobalSetting(Settings::values.disable_fps_limit);
+    WriteGlobalSetting(Settings::values.use_assembly_shaders);
+    WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
+    WriteGlobalSetting(Settings::values.use_fast_gpu_time);
+    WriteGlobalSetting(Settings::values.use_caches_gc);
+    WriteGlobalSetting(Settings::values.bg_red);
+    WriteGlobalSetting(Settings::values.bg_green);
+    WriteGlobalSetting(Settings::values.bg_blue);
 
     qt_config->endGroup();
 }
@@ -1435,17 +1406,16 @@ void Config::SaveShortcutValues() {
 void Config::SaveSystemValues() {
     qt_config->beginGroup(QStringLiteral("System"));
 
-    WriteSetting(QStringLiteral("current_user"), Settings::values.current_user);
-    WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index);
-    WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index);
-    WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index);
+    WriteBasicSetting(Settings::values.current_user);
+    WriteGlobalSetting(Settings::values.language_index);
+    WriteGlobalSetting(Settings::values.region_index);
+    WriteGlobalSetting(Settings::values.time_zone_index);
 
-    WriteSettingGlobal(QStringLiteral("rng_seed_enabled"),
-                       Settings::values.rng_seed.GetValue(global).has_value(),
-                       Settings::values.rng_seed.UsingGlobal(), false);
-    WriteSettingGlobal(QStringLiteral("rng_seed"),
-                       Settings::values.rng_seed.GetValue(global).value_or(0),
-                       Settings::values.rng_seed.UsingGlobal(), 0);
+    WriteSetting(QStringLiteral("rng_seed_enabled"),
+                 Settings::values.rng_seed.GetValue(global).has_value(),
+                 Settings::values.rng_seed.UsingGlobal(), false);
+    WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0),
+                 Settings::values.rng_seed.UsingGlobal(), 0);
 
     if (global) {
         WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
@@ -1456,7 +1426,7 @@ void Config::SaveSystemValues() {
                      0);
     }
 
-    WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index);
+    WriteGlobalSetting(Settings::values.sound_index);
 
     qt_config->endGroup();
 }
@@ -1530,13 +1500,10 @@ void Config::SaveUILayoutValues() {
 void Config::SaveWebServiceValues() {
     qt_config->beginGroup(QStringLiteral("WebService"));
 
-    WriteSetting(QStringLiteral("enable_telemetry"), Settings::values.enable_telemetry, true);
-    WriteSetting(QStringLiteral("web_api_url"),
-                 QString::fromStdString(Settings::values.web_api_url),
-                 QStringLiteral("https://api.yuzu-emu.org"));
-    WriteSetting(QStringLiteral("yuzu_username"),
-                 QString::fromStdString(Settings::values.yuzu_username));
-    WriteSetting(QStringLiteral("yuzu_token"), QString::fromStdString(Settings::values.yuzu_token));
+    WriteBasicSetting(Settings::values.enable_telemetry);
+    WriteBasicSetting(Settings::values.web_api_url);
+    WriteBasicSetting(Settings::values.yuzu_username);
+    WriteBasicSetting(Settings::values.yuzu_token);
 
     qt_config->endGroup();
 }
@@ -1555,25 +1522,15 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
     return result;
 }
 
-QVariant Config::ReadSetting(const QString& name, Settings::CPUAccuracy default_value) const {
-    return ReadSetting(name, static_cast<u32>(default_value));
-}
-
-QVariant Config::ReadSetting(const QString& name, Settings::GPUAccuracy default_value) const {
-    return ReadSetting(name, static_cast<u32>(default_value));
-}
-
-QVariant Config::ReadSetting(const QString& name, Settings::RendererBackend default_value) const {
-    return ReadSetting(name, static_cast<u32>(default_value));
-}
-
 template <typename Type>
-void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) {
+void Config::ReadGlobalSetting(Settings::Setting<Type>& setting) {
+    QString name = QString::fromStdString(setting.GetLabel());
     const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
     setting.SetGlobal(use_global);
-    const Type& default_value = setting.GetDefault();
     if (global || !use_global) {
-        setting.SetValue(static_cast<QVariant>(ReadSetting(name, default_value)).value<Type>());
+        setting.SetValue(static_cast<QVariant>(
+                             ReadSetting(name, QVariant::fromValue<Type>(setting.GetDefault())))
+                             .value<Type>());
     }
 }
 
@@ -1596,20 +1553,8 @@ void Config::WriteSetting(const QString& name, const QVariant& value,
     qt_config->setValue(name, value);
 }
 
-template <typename Type>
-void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting) {
-    if (!global) {
-        qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
-    }
-    if (global || !setting.UsingGlobal()) {
-        qt_config->setValue(name + QStringLiteral("/default"),
-                            setting.GetValue(global) == setting.GetDefault());
-        qt_config->setValue(name, setting.GetValue(global));
-    }
-}
-
-void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
-                                const QVariant& default_value) {
+void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
+                          bool use_global) {
     if (!global) {
         qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
     }
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 62501997cc..96f9b6de1d 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -102,28 +102,75 @@ private:
     void SaveUILayoutValues();
     void SaveWebServiceValues();
 
+    /**
+     * Reads a setting from the qt_config.
+     *
+     * @param name The setting's identifier
+     * @param default_value The value to use when the setting is not already present in the config
+     */
     QVariant ReadSetting(const QString& name) const;
     QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
-    QVariant ReadSetting(const QString& name, Settings::CPUAccuracy default_value) const;
-    QVariant ReadSetting(const QString& name, Settings::GPUAccuracy default_value) const;
-    QVariant ReadSetting(const QString& name, Settings::RendererBackend default_value) const;
-    // Templated ReadSettingGlobal functions will also look for the use_global setting and set
-    // both the value and the global state properly
-    template <typename Type>
-    void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
+
+    /**
+     * Only reads a setting from the qt_config if the current config is a global config, or if the
+     * current config is a custom config and the setting is overriding the global setting. Otherwise
+     * it does nothing.
+     *
+     * @param setting The variable to be modified
+     * @param name The setting's identifier
+     * @param default_value The value to use when the setting is not already present in the config
+     */
     template <typename Type>
     void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
-    // Templated WriteSettingGlobal functions will also write the global state if needed and will
-    // skip writing the actual setting if it defers to the global value
+
+    /**
+     * Writes a setting to the qt_config.
+     *
+     * @param name The setting's idetentifier
+     * @param value Value of the setting
+     * @param default_value Default of the setting if not present in qt_config
+     * @param use_global Specifies if the custom or global config should be in use, for custom
+     * configs
+     */
     void WriteSetting(const QString& name, const QVariant& value);
     void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
+    void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
+                      bool use_global);
+
+    /**
+     * Reads a value from the qt_config and applies it to the setting, using its label and default
+     * value. If the config is a custom config, this will also read the global state of the setting
+     * and apply that information to it.
+     *
+     * @param The setting
+     */
     template <typename Type>
-    void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting);
+    void ReadGlobalSetting(Settings::Setting<Type>& setting);
+
+    /**
+     * Sets a value to the qt_config using the setting's label and default value. If the config is a
+     * custom config, it will apply the global state, and the custom value if needed.
+     *
+     * @param The setting
+     */
     template <typename Type>
-    void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
-                            const QVariant& default_value);
-    void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
-                            const QVariant& default_value);
+    void WriteGlobalSetting(const Settings::Setting<Type>& setting);
+
+    /**
+     * Reads a value from the qt_config using the setting's label and default value and applies the
+     * value to the setting.
+     *
+     * @param The setting
+     */
+    template <typename Type>
+    void ReadBasicSetting(Settings::BasicSetting<Type>& setting);
+
+    /** Sets a value from the setting in the qt_config using the setting's label and default value.
+     *
+     * @param The setting
+     */
+    template <typename Type>
+    void WriteBasicSetting(const Settings::BasicSetting<Type>& setting);
 
     ConfigType type;
     std::unique_ptr<QSettings> qt_config;
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index fc01914320..5aba1a3b2f 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -69,7 +69,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
     [[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box);
 
     int new_sink_index = 0;
-    const QString sink_id = QString::fromStdString(Settings::values.sink_id);
+    const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
     for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
         if (ui->output_sink_combo_box->itemText(index) == sink_id) {
             new_sink_index = index;
@@ -83,7 +83,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
 void ConfigureAudio::SetAudioDeviceFromDeviceID() {
     int new_device_index = -1;
 
-    const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
+    const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue());
     for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
         if (ui->audio_device_combo_box->itemText(index) == device_id) {
             new_device_index = index;
@@ -106,9 +106,9 @@ void ConfigureAudio::ApplyConfiguration() {
         Settings::values.sink_id =
             ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
                 .toStdString();
-        Settings::values.audio_device_id =
+        Settings::values.audio_device_id.SetValue(
             ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
-                .toStdString();
+                .toStdString());
 
         // Guard if during game and set to game-specific value
         if (Settings::values.volume.UsingGlobal()) {
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
index e25c52baf4..98e2d2be59 100644
--- a/src/yuzu/configuration/configure_cpu_debug.cpp
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -24,23 +24,26 @@ void ConfigureCpuDebug::SetConfiguration() {
     const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
 
     ui->cpuopt_page_tables->setEnabled(runtime_lock);
-    ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables);
+    ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue());
     ui->cpuopt_block_linking->setEnabled(runtime_lock);
-    ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking);
+    ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking.GetValue());
     ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
-    ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer);
+    ui->cpuopt_return_stack_buffer->setChecked(
+        Settings::values.cpuopt_return_stack_buffer.GetValue());
     ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
-    ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher);
+    ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher.GetValue());
     ui->cpuopt_context_elimination->setEnabled(runtime_lock);
-    ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination);
+    ui->cpuopt_context_elimination->setChecked(
+        Settings::values.cpuopt_context_elimination.GetValue());
     ui->cpuopt_const_prop->setEnabled(runtime_lock);
-    ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop);
+    ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop.GetValue());
     ui->cpuopt_misc_ir->setEnabled(runtime_lock);
-    ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
+    ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir.GetValue());
     ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
-    ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
+    ui->cpuopt_reduce_misalign_checks->setChecked(
+        Settings::values.cpuopt_reduce_misalign_checks.GetValue());
     ui->cpuopt_fastmem->setEnabled(runtime_lock);
-    ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem);
+    ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue());
 }
 
 void ConfigureCpuDebug::ApplyConfiguration() {
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 15d6a5ad79..7d15d54b8b 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -32,19 +32,20 @@ void ConfigureDebug::SetConfiguration() {
 
     ui->toggle_console->setEnabled(runtime_lock);
     ui->toggle_console->setChecked(UISettings::values.show_console);
-    ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
-    ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
+    ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
+    ui->homebrew_args_edit->setText(
+        QString::fromStdString(Settings::values.program_args.GetValue()));
     ui->fs_access_log->setEnabled(runtime_lock);
-    ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log);
-    ui->reporting_services->setChecked(Settings::values.reporting_services);
-    ui->quest_flag->setChecked(Settings::values.quest_flag);
-    ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts);
-    ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
+    ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log.GetValue());
+    ui->reporting_services->setChecked(Settings::values.reporting_services.GetValue());
+    ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue());
+    ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue());
+    ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue());
     ui->enable_graphics_debugging->setEnabled(runtime_lock);
-    ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
+    ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
     ui->disable_macro_jit->setEnabled(runtime_lock);
-    ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit);
-    ui->extended_logging->setChecked(Settings::values.extended_logging);
+    ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
+    ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
 }
 
 void ConfigureDebug::ApplyConfiguration() {
@@ -61,7 +62,7 @@ void ConfigureDebug::ApplyConfiguration() {
     Settings::values.extended_logging = ui->extended_logging->isChecked();
     Debugger::ToggleConsole();
     Common::Log::Filter filter;
-    filter.ParseFilterString(Settings::values.log_filter);
+    filter.ParseFilterString(Settings::values.log_filter.GetValue());
     Common::Log::SetGlobalFilter(filter);
 }
 
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index d223c40ea2..d0b5c6efe1 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -43,16 +43,17 @@ void ConfigureFilesystem::setConfiguration() {
         QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir)));
     ui->sdmc_directory_edit->setText(
         QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir)));
-    ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path));
+    ui->gamecard_path_edit->setText(
+        QString::fromStdString(Settings::values.gamecard_path.GetValue()));
     ui->dump_path_edit->setText(
         QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
     ui->load_path_edit->setText(
         QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
 
-    ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted);
-    ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game);
-    ui->dump_exefs->setChecked(Settings::values.dump_exefs);
-    ui->dump_nso->setChecked(Settings::values.dump_nso);
+    ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue());
+    ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue());
+    ui->dump_exefs->setChecked(Settings::values.dump_exefs.GetValue());
+    ui->dump_nso->setChecked(Settings::values.dump_nso.GetValue());
 
     ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
 
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index d8d3b83dc7..2f1419b5bb 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -148,12 +148,12 @@ void ConfigureInputAdvanced::LoadConfiguration() {
         }
     }
 
-    ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
-    ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
-    ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
-    ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard);
-    ui->mouse_panning->setChecked(Settings::values.mouse_panning);
-    ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity);
+    ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled.GetValue());
+    ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue());
+    ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue());
+    ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue());
+    ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue());
+    ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
     ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
 
     UpdateUIEnabled();
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 6a5d625dfd..f8e08c4222 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -101,15 +101,16 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
 ConfigureMotionTouch::~ConfigureMotionTouch() = default;
 
 void ConfigureMotionTouch::SetConfiguration() {
-    const Common::ParamPackage motion_param(Settings::values.motion_device);
-    const Common::ParamPackage touch_param(Settings::values.touch_device);
+    const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue());
+    const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
 
-    ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
+    ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue());
     touch_from_button_maps = Settings::values.touch_from_button_maps;
     for (const auto& touch_map : touch_from_button_maps) {
         ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
     }
-    ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index);
+    ui->touch_from_button_map->setCurrentIndex(
+        Settings::values.touch_from_button_map_index.GetValue());
     ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
 
     min_x = touch_param.Get("min_x", 100);
@@ -124,7 +125,7 @@ void ConfigureMotionTouch::SetConfiguration() {
     udp_server_list_model->setStringList({});
     ui->udp_server_list->setModel(udp_server_list_model);
 
-    std::stringstream ss(Settings::values.udp_input_servers);
+    std::stringstream ss(Settings::values.udp_input_servers.GetValue());
     std::string token;
 
     while (std::getline(ss, token, ',')) {
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index f5881e58dc..ac849b01d3 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -166,7 +166,7 @@ void ConfigureProfileManager::PopulateUserList() {
 void ConfigureProfileManager::UpdateCurrentUser() {
     ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
 
-    const auto& current_user = profile_manager->GetUser(Settings::values.current_user);
+    const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
     ASSERT(current_user);
     const auto username = GetAccountUsername(*profile_manager, *current_user);
 
@@ -245,15 +245,18 @@ void ConfigureProfileManager::DeleteUser() {
         this, tr("Confirm Delete"),
         tr("You are about to delete user with name \"%1\". Are you sure?").arg(username));
 
-    if (confirm == QMessageBox::No)
+    if (confirm == QMessageBox::No) {
         return;
+    }
 
-    if (Settings::values.current_user == tree_view->currentIndex().row())
+    if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) {
         Settings::values.current_user = 0;
+    }
     UpdateCurrentUser();
 
-    if (!profile_manager->RemoveUser(*uuid))
+    if (!profile_manager->RemoveUser(*uuid)) {
         return;
+    }
 
     item_model->removeRows(tree_view->currentIndex().row(), 1);
     tree_view->clearSelection();
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp
index 6d954a67f6..4aa4248033 100644
--- a/src/yuzu/configuration/configure_service.cpp
+++ b/src/yuzu/configuration/configure_service.cpp
@@ -65,7 +65,7 @@ void ConfigureService::RetranslateUi() {
 
 void ConfigureService::SetConfiguration() {
     const int index =
-        ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend));
+        ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
     ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
 }
 
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index f3f3b54d63..0fd76dc2c4 100644
--- a/src/yuzu/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -88,15 +88,15 @@ void ConfigureWeb::SetConfiguration() {
     ui->web_signup_link->setOpenExternalLinks(true);
     ui->web_token_info_link->setOpenExternalLinks(true);
 
-    if (Settings::values.yuzu_username.empty()) {
+    if (Settings::values.yuzu_username.GetValue().empty()) {
         ui->username->setText(tr("Unspecified"));
     } else {
-        ui->username->setText(QString::fromStdString(Settings::values.yuzu_username));
+        ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
     }
 
-    ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry);
-    ui->edit_token->setText(QString::fromStdString(
-        GenerateDisplayToken(Settings::values.yuzu_username, Settings::values.yuzu_token)));
+    ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry.GetValue());
+    ui->edit_token->setText(QString::fromStdString(GenerateDisplayToken(
+        Settings::values.yuzu_username.GetValue(), Settings::values.yuzu_token.GetValue())));
 
     // Connect after setting the values, to avoid calling OnLoginChanged now
     connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 6f5b2f6d6c..d9375fc773 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -176,7 +176,7 @@ static void InitializeLogging() {
     using namespace Common;
 
     Log::Filter log_filter;
-    log_filter.ParseFilterString(Settings::values.log_filter);
+    log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
     Log::SetGlobalFilter(log_filter);
 
     const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
@@ -2443,7 +2443,8 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
 }
 
 void GMainWindow::OnMenuReportCompatibility() {
-    if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) {
+    if (!Settings::values.yuzu_token.GetValue().empty() &&
+        !Settings::values.yuzu_username.GetValue().empty()) {
         CompatDB compatdb{this};
         compatdb.exec();
     } else {
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 60bf66ec04..2c8d3f6839 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -241,6 +241,24 @@ static const std::array<int, 8> keyboard_mods{
     SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
 };
 
+template <>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<float> setting) {
+    setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
+}
+template <>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string> setting) {
+    setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
+}
+template <>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool> setting) {
+    setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
+}
+template <typename Type>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type> setting) {
+    setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
+                                                        static_cast<long>(setting.GetDefault())));
+}
+
 void Config::ReadValues() {
     // Controls
     for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
@@ -264,8 +282,7 @@ void Config::ReadValues() {
         }
     }
 
-    Settings::values.mouse_enabled =
-        sdl2_config->GetBoolean("ControlsGeneral", "mouse_enabled", false);
+    ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
     for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
         std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
         Settings::values.mouse_buttons[i] = sdl2_config->Get(
@@ -275,14 +292,11 @@ void Config::ReadValues() {
             Settings::values.mouse_buttons[i] = default_param;
     }
 
-    Settings::values.motion_device = sdl2_config->Get(
-        "ControlsGeneral", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01");
+    ReadSetting("ControlsGeneral", Settings::values.motion_device);
 
-    Settings::values.keyboard_enabled =
-        sdl2_config->GetBoolean("ControlsGeneral", "keyboard_enabled", false);
+    ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
 
-    Settings::values.debug_pad_enabled =
-        sdl2_config->GetBoolean("ControlsGeneral", "debug_pad_enabled", false);
+    ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
         std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
         Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
@@ -303,12 +317,9 @@ void Config::ReadValues() {
             Settings::values.debug_pad_analogs[i] = default_param;
     }
 
-    Settings::values.vibration_enabled.SetValue(
-        sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
-    Settings::values.enable_accurate_vibrations.SetValue(
-        sdl2_config->GetBoolean("ControlsGeneral", "enable_accurate_vibrations", false));
-    Settings::values.motion_enabled.SetValue(
-        sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
+    ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
+    ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
+    ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
     Settings::values.touchscreen.enabled =
         sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
     Settings::values.touchscreen.rotation_angle =
@@ -349,13 +360,11 @@ void Config::ReadValues() {
             Settings::TouchFromButtonMap{"default", {}});
         num_touch_from_button_maps = 1;
     }
-    Settings::values.use_touch_from_button =
-        sdl2_config->GetBoolean("ControlsGeneral", "use_touch_from_button", false);
-    Settings::values.touch_from_button_map_index =
-        std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
+    ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button);
+    Settings::values.touch_from_button_map_index = std::clamp(
+        Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
 
-    Settings::values.udp_input_servers =
-        sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV);
+    ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
 
     std::transform(keyboard_keys.begin(), keyboard_keys.end(),
                    Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
@@ -367,8 +376,7 @@ void Config::ReadValues() {
                    Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
 
     // Data Storage
-    Settings::values.use_virtual_sd =
-        sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
+    ReadSetting("Data Storage", Settings::values.use_virtual_sd);
     FS::SetYuzuPath(FS::YuzuPath::NANDDir,
                     sdl2_config->Get("Data Storage", "nand_directory",
                                      FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -381,18 +389,16 @@ void Config::ReadValues() {
     FS::SetYuzuPath(FS::YuzuPath::DumpDir,
                     sdl2_config->Get("Data Storage", "dump_directory",
                                      FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
-    Settings::values.gamecard_inserted =
-        sdl2_config->GetBoolean("Data Storage", "gamecard_inserted", false);
-    Settings::values.gamecard_current_game =
-        sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
-    Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
+    ReadSetting("Data Storage", Settings::values.gamecard_inserted);
+    ReadSetting("Data Storage", Settings::values.gamecard_current_game);
+    ReadSetting("Data Storage", Settings::values.gamecard_path);
 
     // System
-    Settings::values.use_docked_mode.SetValue(
-        sdl2_config->GetBoolean("System", "use_docked_mode", true));
+    ReadSetting("System", Settings::values.use_docked_mode);
 
-    Settings::values.current_user = std::clamp<int>(
-        sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
+    ReadSetting("System", Settings::values.current_user);
+    Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
+                                                    Service::Account::MAX_USERS - 1);
 
     const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
     if (rng_seed_enabled) {
@@ -409,89 +415,60 @@ void Config::ReadValues() {
         Settings::values.custom_rtc = std::nullopt;
     }
 
-    Settings::values.language_index.SetValue(
-        sdl2_config->GetInteger("System", "language_index", 1));
-    Settings::values.time_zone_index.SetValue(
-        sdl2_config->GetInteger("System", "time_zone_index", 0));
+    ReadSetting("System", Settings::values.language_index);
+    ReadSetting("System", Settings::values.time_zone_index);
 
     // Core
-    Settings::values.use_multi_core.SetValue(
-        sdl2_config->GetBoolean("Core", "use_multi_core", true));
+    ReadSetting("Core", Settings::values.use_multi_core);
 
     // Renderer
-    const int renderer_backend = sdl2_config->GetInteger(
-        "Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL));
-    Settings::values.renderer_backend.SetValue(
-        static_cast<Settings::RendererBackend>(renderer_backend));
-    Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false);
-    Settings::values.vulkan_device.SetValue(
-        sdl2_config->GetInteger("Renderer", "vulkan_device", 0));
+    ReadSetting("Renderer", Settings::values.renderer_backend);
+    ReadSetting("Renderer", Settings::values.renderer_debug);
+    ReadSetting("Renderer", Settings::values.vulkan_device);
 
-    Settings::values.aspect_ratio.SetValue(
-        static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
-    Settings::values.max_anisotropy.SetValue(
-        static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
-    Settings::values.use_frame_limit.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_frame_limit", true));
-    Settings::values.frame_limit.SetValue(
-        static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)));
-    Settings::values.use_disk_shader_cache.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
-    const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 1);
-    Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
-    Settings::values.use_asynchronous_gpu_emulation.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", true));
-    Settings::values.use_vsync.SetValue(
-        static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
-    Settings::values.disable_fps_limit.SetValue(
-        sdl2_config->GetBoolean("Renderer", "disable_fps_limit", false));
-    Settings::values.use_assembly_shaders.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true));
-    Settings::values.use_asynchronous_shaders.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
-    Settings::values.use_nvdec_emulation.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_nvdec_emulation", true));
-    Settings::values.accelerate_astc.SetValue(
-        sdl2_config->GetBoolean("Renderer", "accelerate_astc", true));
-    Settings::values.use_fast_gpu_time.SetValue(
-        sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
+    ReadSetting("Renderer", Settings::values.aspect_ratio);
+    ReadSetting("Renderer", Settings::values.max_anisotropy);
+    ReadSetting("Renderer", Settings::values.use_frame_limit);
+    ReadSetting("Renderer", Settings::values.frame_limit);
+    ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
+    ReadSetting("Renderer", Settings::values.gpu_accuracy);
+    ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
+    ReadSetting("Renderer", Settings::values.use_vsync);
+    ReadSetting("Renderer", Settings::values.disable_fps_limit);
+    ReadSetting("Renderer", Settings::values.use_assembly_shaders);
+    ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
+    ReadSetting("Renderer", Settings::values.use_nvdec_emulation);
+    ReadSetting("Renderer", Settings::values.accelerate_astc);
+    ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
 
-    Settings::values.bg_red.SetValue(
-        static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
-    Settings::values.bg_green.SetValue(
-        static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
-    Settings::values.bg_blue.SetValue(
-        static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
+    ReadSetting("Renderer", Settings::values.bg_red);
+    ReadSetting("Renderer", Settings::values.bg_green);
+    ReadSetting("Renderer", Settings::values.bg_blue);
 
     // Audio
-    Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
-    Settings::values.enable_audio_stretching.SetValue(
-        sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true));
-    Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
-    Settings::values.volume.SetValue(
-        static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)));
+    ReadSetting("Audio", Settings::values.sink_id);
+    ReadSetting("Audio", Settings::values.enable_audio_stretching);
+    ReadSetting("Audio", Settings::values.audio_device_id);
+    ReadSetting("Audio", Settings::values.volume);
 
     // Miscellaneous
-    Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
-    Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false);
+    // log_filter has a different default here than from common
+    Settings::values.log_filter =
+        sdl2_config->Get("Miscellaneous", Settings::values.log_filter.GetLabel(), "*:Trace");
+    ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
 
     // Debugging
     Settings::values.record_frame_times =
         sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
-    Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
-    Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
-    Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
-    Settings::values.enable_fs_access_log =
-        sdl2_config->GetBoolean("Debugging", "enable_fs_access_log", false);
-    Settings::values.reporting_services =
-        sdl2_config->GetBoolean("Debugging", "reporting_services", false);
-    Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
-    Settings::values.use_debug_asserts =
-        sdl2_config->GetBoolean("Debugging", "use_debug_asserts", false);
-    Settings::values.use_auto_stub = sdl2_config->GetBoolean("Debugging", "use_auto_stub", false);
-
-    Settings::values.disable_macro_jit =
-        sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
+    ReadSetting("Debugging", Settings::values.program_args);
+    ReadSetting("Debugging", Settings::values.dump_exefs);
+    ReadSetting("Debugging", Settings::values.dump_nso);
+    ReadSetting("Debugging", Settings::values.enable_fs_access_log);
+    ReadSetting("Debugging", Settings::values.reporting_services);
+    ReadSetting("Debugging", Settings::values.quest_flag);
+    ReadSetting("Debugging", Settings::values.use_debug_asserts);
+    ReadSetting("Debugging", Settings::values.use_auto_stub);
+    ReadSetting("Debugging", Settings::values.disable_macro_jit);
 
     const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
     std::stringstream ss(title_list);
@@ -511,17 +488,14 @@ void Config::ReadValues() {
     }
 
     // Web Service
-    Settings::values.enable_telemetry =
-        sdl2_config->GetBoolean("WebService", "enable_telemetry", true);
-    Settings::values.web_api_url =
-        sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org");
-    Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", "");
-    Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", "");
+    ReadSetting("WebService", Settings::values.enable_telemetry);
+    ReadSetting("WebService", Settings::values.web_api_url);
+    ReadSetting("WebService", Settings::values.yuzu_username);
+    ReadSetting("WebService", Settings::values.yuzu_token);
 
     // Services
-    Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "none");
-    Settings::values.bcat_boxcat_local =
-        sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false);
+    ReadSetting("Services", Settings::values.bcat_backend);
+    ReadSetting("Services", Settings::values.bcat_boxcat_local);
 }
 
 void Config::Reload() {
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index 8071992784..bf0103dee6 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <string>
 
+#include "common/settings.h"
+
 class INIReader;
 
 class Config {
@@ -22,4 +24,8 @@ public:
     ~Config();
 
     void Reload();
+
+private:
+    template <typename Type>
+    void ReadSetting(const std::string& group, Settings::BasicSetting<Type> setting);
 };
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 50e3883122..9607cdcb12 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -78,7 +78,7 @@ static void InitializeLogging() {
     using namespace Common;
 
     Log::Filter log_filter(Log::Level::Debug);
-    log_filter.ParseFilterString(Settings::values.log_filter);
+    log_filter.ParseFilterString(static_cast<std::string>(Settings::values.log_filter));
     Log::SetGlobalFilter(log_filter);
 
     Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());

From 7a8de138df35aecf760402a6b8097b4d6e0e8178 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Mon, 28 Jun 2021 17:32:24 -0400
Subject: [PATCH 4/9] yuzu qt: Make most UISettings a BasicSetting

For simple primitive settings, moves their defaults and labels to
definition time.

Also fixes typo and clang-format

yuzu qt: config: Fix rng_seed
---
 .../renderer_vulkan/renderer_vulkan.cpp       | 13 +++--
 src/yuzu/configuration/config.cpp             | 58 +++++++++----------
 src/yuzu/configuration/configure_debug.cpp    |  2 +-
 .../configuration/configure_filesystem.cpp    |  2 +-
 src/yuzu/configuration/configure_general.cpp  |  8 +--
 src/yuzu/configuration/configure_ui.cpp       | 11 ++--
 src/yuzu/configuration/configure_web.cpp      |  2 +-
 src/yuzu/debugger/console.cpp                 |  4 +-
 src/yuzu/game_list.cpp                        |  3 +-
 src/yuzu/game_list_p.h                        | 15 +++--
 src/yuzu/main.cpp                             | 37 +++++++-----
 src/yuzu/uisettings.h                         | 43 +++++++-------
 12 files changed, 107 insertions(+), 91 deletions(-)

diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 2bab2b4f51..bec3a81d91 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -97,14 +97,19 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
                                Core::Frontend::EmuWindow& emu_window,
                                Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
                                std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
-    : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
-      cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary()),
+    : RendererBase(emu_window, std::move(context_)),
+      telemetry_session(telemetry_session_),
+      cpu_memory(cpu_memory_),
+      gpu(gpu_),
+      library(OpenLibrary()),
       instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
                               true, Settings::values.renderer_debug.GetValue())),
       debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
       surface(CreateSurface(instance, render_window)),
-      device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
-      state_tracker(gpu), scheduler(device, state_tracker),
+      device(CreateDevice(instance, dld, *surface)),
+      memory_allocator(device, false),
+      state_tracker(gpu),
+      scheduler(device, state_tracker),
       swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
                 render_window.GetFramebufferLayout().height, false),
       blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d36aaade2e..0802b14a1f 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -272,7 +272,12 @@ void Config::Initialize(const std::string& config_name) {
     }
 }
 
-// Explicity std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
+/* {Read,Write}BasicSetting and WriteGlobalSetting templates must be defined here before their
+ * usages later in this file. This allows explicit definition of some types that don't work
+ * nicely with the general version.
+ */
+
+// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
 // can it implicitly convert a QVariant back to a {std::,Q}string
 template <>
 void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
@@ -1375,8 +1380,7 @@ void Config::SaveRendererValues() {
 void Config::SaveScreenshotValues() {
     qt_config->beginGroup(QStringLiteral("Screenshots"));
 
-    WriteSetting(QStringLiteral("enable_screenshot_save_as"),
-                 UISettings::values.enable_screenshot_save_as);
+    WriteBasicSetting(UISettings::values.enable_screenshot_save_as);
     WriteSetting(QStringLiteral("screenshot_path"),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)));
 
@@ -1412,10 +1416,10 @@ void Config::SaveSystemValues() {
     WriteGlobalSetting(Settings::values.time_zone_index);
 
     WriteSetting(QStringLiteral("rng_seed_enabled"),
-                 Settings::values.rng_seed.GetValue(global).has_value(),
-                 Settings::values.rng_seed.UsingGlobal(), false);
+                 Settings::values.rng_seed.GetValue(global).has_value(), false,
+                 Settings::values.rng_seed.UsingGlobal());
     WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0),
-                 Settings::values.rng_seed.UsingGlobal(), 0);
+                 0, Settings::values.rng_seed.UsingGlobal());
 
     if (global) {
         WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
@@ -1436,10 +1440,8 @@ void Config::SaveUIValues() {
 
     WriteSetting(QStringLiteral("theme"), UISettings::values.theme,
                  QString::fromUtf8(UISettings::themes[0].second));
-    WriteSetting(QStringLiteral("enable_discord_presence"),
-                 UISettings::values.enable_discord_presence, true);
-    WriteSetting(QStringLiteral("select_user_on_boot"), UISettings::values.select_user_on_boot,
-                 false);
+    WriteBasicSetting(UISettings::values.enable_discord_presence);
+    WriteBasicSetting(UISettings::values.select_user_on_boot);
 
     SaveUIGamelistValues();
     SaveUILayoutValues();
@@ -1447,18 +1449,17 @@ void Config::SaveUIValues() {
     SaveScreenshotValues();
     SaveShortcutValues();
 
-    WriteSetting(QStringLiteral("singleWindowMode"), UISettings::values.single_window_mode, true);
-    WriteSetting(QStringLiteral("fullscreen"), UISettings::values.fullscreen, false);
-    WriteSetting(QStringLiteral("displayTitleBars"), UISettings::values.display_titlebar, true);
-    WriteSetting(QStringLiteral("showFilterBar"), UISettings::values.show_filter_bar, true);
-    WriteSetting(QStringLiteral("showStatusBar"), UISettings::values.show_status_bar, true);
-    WriteSetting(QStringLiteral("confirmClose"), UISettings::values.confirm_before_closing, true);
-    WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true);
-    WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0);
-    WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false);
-    WriteSetting(QStringLiteral("pauseWhenInBackground"),
-                 UISettings::values.pause_when_in_background, false);
-    WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false);
+    WriteBasicSetting(UISettings::values.single_window_mode);
+    WriteBasicSetting(UISettings::values.fullscreen);
+    WriteBasicSetting(UISettings::values.display_titlebar);
+    WriteBasicSetting(UISettings::values.show_filter_bar);
+    WriteBasicSetting(UISettings::values.show_status_bar);
+    WriteBasicSetting(UISettings::values.confirm_before_closing);
+    WriteBasicSetting(UISettings::values.first_start);
+    WriteBasicSetting(UISettings::values.callout_flags);
+    WriteBasicSetting(UISettings::values.show_console);
+    WriteBasicSetting(UISettings::values.pause_when_in_background);
+    WriteBasicSetting(UISettings::values.hide_mouse);
 
     qt_config->endGroup();
 }
@@ -1466,11 +1467,11 @@ void Config::SaveUIValues() {
 void Config::SaveUIGamelistValues() {
     qt_config->beginGroup(QStringLiteral("UIGameList"));
 
-    WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true);
-    WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64);
-    WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3);
-    WriteSetting(QStringLiteral("row_2_text_id"), UISettings::values.row_2_text_id, 2);
-    WriteSetting(QStringLiteral("cache_game_list"), UISettings::values.cache_game_list, true);
+    WriteBasicSetting(UISettings::values.show_add_ons);
+    WriteBasicSetting(UISettings::values.icon_size);
+    WriteBasicSetting(UISettings::values.row_1_text_id);
+    WriteBasicSetting(UISettings::values.row_2_text_id);
+    WriteBasicSetting(UISettings::values.cache_game_list);
     qt_config->beginWriteArray(QStringLiteral("favorites"));
     for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
         qt_config->setArrayIndex(i);
@@ -1491,8 +1492,7 @@ void Config::SaveUILayoutValues() {
     WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state);
     WriteSetting(QStringLiteral("microProfileDialogGeometry"),
                  UISettings::values.microprofile_geometry);
-    WriteSetting(QStringLiteral("microProfileDialogVisible"),
-                 UISettings::values.microprofile_visible, false);
+    WriteBasicSetting(UISettings::values.microprofile_visible);
 
     qt_config->endGroup();
 }
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 7d15d54b8b..cbe45a3050 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -31,7 +31,7 @@ void ConfigureDebug::SetConfiguration() {
     const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
 
     ui->toggle_console->setEnabled(runtime_lock);
-    ui->toggle_console->setChecked(UISettings::values.show_console);
+    ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
     ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
     ui->homebrew_args_edit->setText(
         QString::fromStdString(Settings::values.program_args.GetValue()));
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index d0b5c6efe1..9cb3178229 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -55,7 +55,7 @@ void ConfigureFilesystem::setConfiguration() {
     ui->dump_exefs->setChecked(Settings::values.dump_exefs.GetValue());
     ui->dump_nso->setChecked(Settings::values.dump_nso.GetValue());
 
-    ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
+    ui->cache_game_list->setChecked(UISettings::values.cache_game_list.GetValue());
 
     UpdateEnabledControls();
 }
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 38edb4d8d4..18f25def62 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -40,10 +40,10 @@ void ConfigureGeneral::SetConfiguration() {
     ui->use_multi_core->setEnabled(runtime_lock);
     ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
 
-    ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
-    ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
-    ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
-    ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
+    ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
+    ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
+    ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
+    ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
 
     ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
     ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 9674119e12..e8f41bf654 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -113,11 +113,12 @@ void ConfigureUi::SetConfiguration() {
     ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
     ui->language_combobox->setCurrentIndex(
         ui->language_combobox->findData(UISettings::values.language));
-    ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
+    ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
     ui->icon_size_combobox->setCurrentIndex(
-        ui->icon_size_combobox->findData(UISettings::values.icon_size));
+        ui->icon_size_combobox->findData(UISettings::values.icon_size.GetValue()));
 
-    ui->enable_screenshot_save_as->setChecked(UISettings::values.enable_screenshot_save_as);
+    ui->enable_screenshot_save_as->setChecked(
+        UISettings::values.enable_screenshot_save_as.GetValue());
     ui->screenshot_path_edit->setText(QString::fromStdString(
         Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
 }
@@ -178,7 +179,7 @@ void ConfigureUi::InitializeRowComboBoxes() {
 
 void ConfigureUi::UpdateFirstRowComboBox(bool init) {
     const int currentIndex =
-        init ? UISettings::values.row_1_text_id
+        init ? UISettings::values.row_1_text_id.GetValue()
              : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
 
     ui->row_1_text_combobox->clear();
@@ -197,7 +198,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
 
 void ConfigureUi::UpdateSecondRowComboBox(bool init) {
     const int currentIndex =
-        init ? UISettings::values.row_2_text_id
+        init ? UISettings::values.row_2_text_id.GetValue()
              : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
 
     ui->row_2_text_combobox->clear();
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index 0fd76dc2c4..d779251b42 100644
--- a/src/yuzu/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -103,7 +103,7 @@ void ConfigureWeb::SetConfiguration() {
 
     user_verified = true;
 
-    ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence);
+    ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
 }
 
 void ConfigureWeb::ApplyConfiguration() {
diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp
index c11a326acb..22ca1285dd 100644
--- a/src/yuzu/debugger/console.cpp
+++ b/src/yuzu/debugger/console.cpp
@@ -15,10 +15,10 @@
 namespace Debugger {
 void ToggleConsole() {
     static bool console_shown = false;
-    if (console_shown == UISettings::values.show_console) {
+    if (console_shown == UISettings::values.show_console.GetValue()) {
         return;
     } else {
-        console_shown = UISettings::values.show_console;
+        console_shown = UISettings::values.show_console.GetValue();
     }
 
 #if defined(_WIN32) && !defined(_DEBUG)
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index da956c99b3..9c5aeb833e 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -244,7 +244,8 @@ void GameList::OnUpdateThemedIcons() {
     for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) {
         QStandardItem* child = item_model->invisibleRootItem()->child(i);
 
-        const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+        const int icon_size =
+            std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
         switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) {
         case GameListItemType::SdmcDir:
             child->setData(
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 978d273257..982c0789df 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -80,7 +80,7 @@ public:
         setData(qulonglong(program_id), ProgramIdRole);
         setData(game_type, FileTypeRole);
 
-        const u32 size = UISettings::values.icon_size;
+        const u32 size = UISettings::values.icon_size.GetValue();
 
         QPixmap picture;
         if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
@@ -108,8 +108,8 @@ public:
                 data(TitleRole).toString(),
             }};
 
-            const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
-            const int row2_id = UISettings::values.row_2_text_id;
+            const auto& row1 = row_data.at(UISettings::values.row_1_text_id.GetValue());
+            const int row2_id = UISettings::values.row_2_text_id.GetValue();
 
             if (role == SortRole) {
                 return row1.toLower();
@@ -233,7 +233,8 @@ public:
         UISettings::GameDir* game_dir = &directory;
         setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole);
 
-        const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+        const int icon_size =
+            std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
         switch (dir_type) {
         case GameListItemType::SdmcDir:
             setData(
@@ -294,7 +295,8 @@ public:
     explicit GameListAddDir() {
         setData(type(), TypeRole);
 
-        const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+        const int icon_size =
+            std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
         setData(QIcon::fromTheme(QStringLiteral("plus"))
                     .pixmap(icon_size)
                     .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
@@ -316,7 +318,8 @@ public:
     explicit GameListFavorites() {
         setData(type(), TypeRole);
 
-        const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+        const int icon_size =
+            std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
         setData(QIcon::fromTheme(QStringLiteral("star"))
                     .pixmap(icon_size)
                     .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index d9375fc773..cb9d7a8633 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -155,11 +155,13 @@ enum class CalloutFlag : uint32_t {
 };
 
 void GMainWindow::ShowTelemetryCallout() {
-    if (UISettings::values.callout_flags & static_cast<uint32_t>(CalloutFlag::Telemetry)) {
+    if (UISettings::values.callout_flags.GetValue() &
+        static_cast<uint32_t>(CalloutFlag::Telemetry)) {
         return;
     }
 
-    UISettings::values.callout_flags |= static_cast<uint32_t>(CalloutFlag::Telemetry);
+    UISettings::values.callout_flags =
+        UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
     const QString telemetry_message =
         tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
            "data is collected</a> to help improve yuzu. "
@@ -215,7 +217,7 @@ GMainWindow::GMainWindow()
     default_theme_paths = QIcon::themeSearchPaths();
     UpdateUITheme();
 
-    SetDiscordEnabled(UISettings::values.enable_discord_presence);
+    SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
     discord_rpc->Update();
 
     RegisterMetaTypes();
@@ -1059,23 +1061,24 @@ void GMainWindow::RestoreUIState() {
     render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
 #if MICROPROFILE_ENABLED
     microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
-    microProfileDialog->setVisible(UISettings::values.microprofile_visible);
+    microProfileDialog->setVisible(UISettings::values.microprofile_visible.GetValue());
 #endif
 
     game_list->LoadInterfaceLayout();
 
-    ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
+    ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue());
     ToggleWindowMode();
 
-    ui.action_Fullscreen->setChecked(UISettings::values.fullscreen);
+    ui.action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue());
 
-    ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
+    ui.action_Display_Dock_Widget_Headers->setChecked(
+        UISettings::values.display_titlebar.GetValue());
     OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
 
-    ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
+    ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue());
     game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
 
-    ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
+    ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
     statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
     Debugger::ToggleConsole();
 }
@@ -1242,13 +1245,14 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
     const Core::System::ResultStatus result{
         system.Load(*render_window, filename.toStdString(), program_index)};
 
-    const auto drd_callout =
-        (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
+    const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
+                              static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
 
     if (result == Core::System::ResultStatus::Success &&
         system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
         drd_callout) {
-        UISettings::values.callout_flags |= static_cast<u32>(CalloutFlag::DRDDeprecation);
+        UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() |
+                                           static_cast<u32>(CalloutFlag::DRDDeprecation);
         QMessageBox::warning(
             this, tr("Warning Outdated Game Format"),
             tr("You are using the deconstructed ROM directory format for this game, which is an "
@@ -2609,7 +2613,7 @@ void GMainWindow::ResetWindowSize1080() {
 
 void GMainWindow::OnConfigure() {
     const auto old_theme = UISettings::values.theme;
-    const bool old_discord_presence = UISettings::values.enable_discord_presence;
+    const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
 
     ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
     connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
@@ -2666,8 +2670,8 @@ void GMainWindow::OnConfigure() {
     if (UISettings::values.theme != old_theme) {
         UpdateUITheme();
     }
-    if (UISettings::values.enable_discord_presence != old_discord_presence) {
-        SetDiscordEnabled(UISettings::values.enable_discord_presence);
+    if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) {
+        SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
     }
     emit UpdateThemedIcons();
 
@@ -2823,7 +2827,8 @@ void GMainWindow::OnCaptureScreenshot() {
         }
     }
 #endif
-    render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename);
+    render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(),
+                                     filename);
     OnStartGame();
 }
 
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index cdcb83f9fc..7b9d2dd531 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -13,6 +13,7 @@
 #include <QStringList>
 #include <QVector>
 #include "common/common_types.h"
+#include "common/settings.h"
 
 namespace UISettings {
 
@@ -48,26 +49,26 @@ struct Values {
     QByteArray gamelist_header_state;
 
     QByteArray microprofile_geometry;
-    bool microprofile_visible;
+    Settings::BasicSetting<bool> microprofile_visible{false, "microProfileDialogVisible"};
 
-    bool single_window_mode;
-    bool fullscreen;
-    bool display_titlebar;
-    bool show_filter_bar;
-    bool show_status_bar;
+    Settings::BasicSetting<bool> single_window_mode{true, "singleWindowMode"};
+    Settings::BasicSetting<bool> fullscreen{false, "fullscreen"};
+    Settings::BasicSetting<bool> display_titlebar{true, "displayTitleBars"};
+    Settings::BasicSetting<bool> show_filter_bar{true, "showFilterBar"};
+    Settings::BasicSetting<bool> show_status_bar{true, "showStatusBar"};
 
-    bool confirm_before_closing;
-    bool first_start;
-    bool pause_when_in_background;
-    bool hide_mouse;
+    Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
+    Settings::BasicSetting<bool> first_start{true, "firstStart"};
+    Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
+    Settings::BasicSetting<bool> hide_mouse{false, "hideInactiveMouse"};
 
-    bool select_user_on_boot;
+    Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};
 
     // Discord RPC
-    bool enable_discord_presence;
+    Settings::BasicSetting<bool> enable_discord_presence{true, "enable_discord_presence"};
 
-    bool enable_screenshot_save_as;
-    u16 screenshot_resolution_factor;
+    Settings::BasicSetting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
+    Settings::BasicSetting<u16> screenshot_resolution_factor{0, "screenshot_resolution_factor"};
 
     QString roms_path;
     QString symbols_path;
@@ -83,18 +84,18 @@ struct Values {
     // Shortcut name <Shortcut, context>
     std::vector<Shortcut> shortcuts;
 
-    uint32_t callout_flags;
+    Settings::BasicSetting<uint32_t> callout_flags{0, "calloutFlags"};
 
     // logging
-    bool show_console;
+    Settings::BasicSetting<bool> show_console{false, "showConsole"};
 
     // Game List
-    bool show_add_ons;
-    uint32_t icon_size;
-    uint8_t row_1_text_id;
-    uint8_t row_2_text_id;
+    Settings::BasicSetting<bool> show_add_ons{true, "show_add_ons"};
+    Settings::BasicSetting<uint32_t> icon_size{64, "icon_size"};
+    Settings::BasicSetting<uint8_t> row_1_text_id{3, "row_1_text_id"};
+    Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"};
     std::atomic_bool is_game_list_reload_pending{false};
-    bool cache_game_list;
+    Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"};
 
     bool configuration_applied;
     bool reset_to_defaults;

From 0e5c74bc9e18974f3169766aec2dee0effdc8df1 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Mon, 28 Jun 2021 19:41:39 -0400
Subject: [PATCH 5/9] core, input_common: Miscellaneous fixes

bcat: Fix settings access

telemetry_session: Fix settings accesses

So this is what I get for testing with the web service disabled.

touch_from_button: Fix settings access for clang
---
 src/core/hle/service/bcat/module.cpp   | 2 +-
 src/core/telemetry_session.cpp         | 8 +++++---
 src/input_common/touch_from_button.cpp | 3 ++-
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 44e4d0509c..f85444da80 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -579,7 +579,7 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
 std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
                                                    DirectoryGetter getter) {
 #ifdef YUZU_ENABLE_BOXCAT
-    if (Settings::values.bcat_backend == "boxcat") {
+    if (Settings::values.bcat_backend.GetValue() == "boxcat") {
         return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
     }
 #endif
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 44b8bab5bd..066cb23e4e 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -135,7 +135,7 @@ u64 RegenerateTelemetryId() {
 
 bool VerifyLogin(const std::string& username, const std::string& token) {
 #ifdef ENABLE_WEB_SERVICE
-    return WebService::VerifyLogin(Settings::values.web_api_url, username, token);
+    return WebService::VerifyLogin(Settings::values.web_api_url.GetValue(), username, token);
 #else
     return false;
 #endif
@@ -152,7 +152,8 @@ TelemetrySession::~TelemetrySession() {
 
 #ifdef ENABLE_WEB_SERVICE
     auto backend = std::make_unique<WebService::TelemetryJson>(
-        Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
+        Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
+        Settings::values.yuzu_token.GetValue());
 #else
     auto backend = std::make_unique<Telemetry::NullVisitor>();
 #endif
@@ -242,7 +243,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
 bool TelemetrySession::SubmitTestcase() {
 #ifdef ENABLE_WEB_SERVICE
     auto backend = std::make_unique<WebService::TelemetryJson>(
-        Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
+        Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
+        Settings::values.yuzu_token.GetValue());
     field_collection.Accept(*backend);
     return backend->SubmitTestcase();
 #else
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
index 87207f48f7..7878a56d77 100644
--- a/src/input_common/touch_from_button.cpp
+++ b/src/input_common/touch_from_button.cpp
@@ -12,7 +12,8 @@ namespace InputCommon {
 class TouchFromButtonDevice final : public Input::TouchDevice {
 public:
     TouchFromButtonDevice() {
-        const auto button_index = Settings::values.touch_from_button_map_index.GetValue();
+        const auto button_index =
+            static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
         const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
 
         for (const auto& config_entry : buttons) {

From 299c5594e6b36cef70b164e00eb671ed32c0d705 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Wed, 30 Jun 2021 20:16:01 -0400
Subject: [PATCH 6/9] yuzu_cmd: config: Pass a reference in

Also adds documentation for the ReadSetting function.

Address review comments.

Co-authored-by: Mai M. <mathew1800@gmail.com>
---
 src/yuzu_cmd/config.cpp | 8 ++++----
 src/yuzu_cmd/config.h   | 8 +++++++-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 2c8d3f6839..325584a1a7 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -242,19 +242,19 @@ static const std::array<int, 8> keyboard_mods{
 };
 
 template <>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<float> setting) {
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<float>& setting) {
     setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
 }
 template <>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string> setting) {
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
     setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
 }
 template <>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool> setting) {
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) {
     setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
 }
 template <typename Type>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type> setting) {
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting) {
     setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
                                                         static_cast<long>(setting.GetDefault())));
 }
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index bf0103dee6..1ee932be2e 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -26,6 +26,12 @@ public:
     void Reload();
 
 private:
+    /**
+     * Applies a value read from the sdl2_config to a BasicSetting.
+     *
+     * @param group The name of the INI group
+     * @param setting The yuzu setting to modify
+     */
     template <typename Type>
-    void ReadSetting(const std::string& group, Settings::BasicSetting<Type> setting);
+    void ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting);
 };

From cf1cd3321d12ef96062c3b59b98542e3155822d4 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Thu, 1 Jul 2021 12:06:12 -0400
Subject: [PATCH 7/9] settings: Set resolution_factor default to 1

Fixes Disgaea 6 Demo issues.
---
 src/common/settings.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/common/settings.h b/src/common/settings.h
index 13896debf0..c799e62438 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -308,7 +308,7 @@ struct Values {
     BasicSetting<bool> renderer_debug{false, "debug"};
     Setting<int> vulkan_device{0, "vulkan_device"};
 
-    Setting<u16> resolution_factor{0, "resolution_factor"};
+    Setting<u16> resolution_factor{1, "resolution_factor"};
     // *nix platforms may have issues with the borderless windowed fullscreen mode.
     // Default to exclusive fullscreen on these platforms for now.
     Setting<int> fullscreen_mode{

From 38f658d21ec9f350e674d830f1c942e958a63181 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Fri, 2 Jul 2021 01:06:30 -0400
Subject: [PATCH 8/9] config: Read UISettings as basic settings

I must have been asleep or something. These need to be read with the new
ReadBasicSetting function.
---
 src/yuzu/configuration/config.cpp | 49 ++++++++++++-------------------
 1 file changed, 19 insertions(+), 30 deletions(-)

diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 0802b14a1f..e21f15c726 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -926,10 +926,8 @@ void Config::ReadUIValues() {
     UISettings::values.theme =
         ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second))
             .toString();
-    UISettings::values.enable_discord_presence =
-        ReadSetting(QStringLiteral("enable_discord_presence"), true).toBool();
-    UISettings::values.select_user_on_boot =
-        ReadSetting(QStringLiteral("select_user_on_boot"), false).toBool();
+    ReadBasicSetting(UISettings::values.enable_discord_presence);
+    ReadBasicSetting(UISettings::values.select_user_on_boot);
 
     ReadUIGamelistValues();
     ReadUILayoutValues();
@@ -937,24 +935,17 @@ void Config::ReadUIValues() {
     ReadScreenshotValues();
     ReadShortcutValues();
 
-    UISettings::values.single_window_mode =
-        ReadSetting(QStringLiteral("singleWindowMode"), true).toBool();
-    UISettings::values.fullscreen = ReadSetting(QStringLiteral("fullscreen"), false).toBool();
-    UISettings::values.display_titlebar =
-        ReadSetting(QStringLiteral("displayTitleBars"), true).toBool();
-    UISettings::values.show_filter_bar =
-        ReadSetting(QStringLiteral("showFilterBar"), true).toBool();
-    UISettings::values.show_status_bar =
-        ReadSetting(QStringLiteral("showStatusBar"), true).toBool();
-    UISettings::values.confirm_before_closing =
-        ReadSetting(QStringLiteral("confirmClose"), true).toBool();
-    UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool();
-    UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt();
-    UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool();
-    UISettings::values.pause_when_in_background =
-        ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool();
-    UISettings::values.hide_mouse =
-        ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool();
+    ReadBasicSetting(UISettings::values.single_window_mode);
+    ReadBasicSetting(UISettings::values.fullscreen);
+    ReadBasicSetting(UISettings::values.display_titlebar);
+    ReadBasicSetting(UISettings::values.show_filter_bar);
+    ReadBasicSetting(UISettings::values.show_status_bar);
+    ReadBasicSetting(UISettings::values.confirm_before_closing);
+    ReadBasicSetting(UISettings::values.first_start);
+    ReadBasicSetting(UISettings::values.callout_flags);
+    ReadBasicSetting(UISettings::values.show_console);
+    ReadBasicSetting(UISettings::values.pause_when_in_background);
+    ReadBasicSetting(UISettings::values.hide_mouse);
 
     qt_config->endGroup();
 }
@@ -962,12 +953,11 @@ void Config::ReadUIValues() {
 void Config::ReadUIGamelistValues() {
     qt_config->beginGroup(QStringLiteral("UIGameList"));
 
-    UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool();
-    UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt();
-    UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt();
-    UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt();
-    UISettings::values.cache_game_list =
-        ReadSetting(QStringLiteral("cache_game_list"), true).toBool();
+    ReadBasicSetting(UISettings::values.show_add_ons);
+    ReadBasicSetting(UISettings::values.icon_size);
+    ReadBasicSetting(UISettings::values.row_1_text_id);
+    ReadBasicSetting(UISettings::values.row_2_text_id);
+    ReadBasicSetting(UISettings::values.cache_game_list);
     const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites"));
     for (int i = 0; i < favorites_size; i++) {
         qt_config->setArrayIndex(i);
@@ -990,8 +980,7 @@ void Config::ReadUILayoutValues() {
         ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray();
     UISettings::values.microprofile_geometry =
         ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray();
-    UISettings::values.microprofile_visible =
-        ReadSetting(QStringLiteral("microProfileDialogVisible"), false).toBool();
+    ReadBasicSetting(UISettings::values.microprofile_visible);
 
     qt_config->endGroup();
 }

From a949ee0410fcce9144806d7b64e9ae4bffd4fee9 Mon Sep 17 00:00:00 2001
From: lat9nq <22451773+lat9nq@users.noreply.github.com>
Date: Thu, 8 Jul 2021 14:07:10 -0400
Subject: [PATCH 9/9] general: Code formatting improvements

Slight improvements to readability.

Dropped suggestions for string_view (settings.h:101), pass by value
(settings.h:82), reverting double to a float (config.cpp:316), and other
smaller ones, some out of scope.

Addresses review feedback.

Co-authored-by: Ameer J <52414509+ameerj@users.noreply.github.com>
---
 src/common/settings.h                   |  3 +--
 src/core/core.cpp                       |  4 +--
 src/input_common/mouse/mouse_poller.cpp |  4 +--
 src/yuzu/configuration/config.cpp       | 36 ++++++++++++++-----------
 4 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/src/common/settings.h b/src/common/settings.h
index c799e62438..bf83186f50 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -155,8 +155,7 @@ public:
 
     /**
      * Tells this setting to represent either the global or custom setting when other member
-     * functions are used. Setting to_global to true means using the global setting, to false
-     * false for the custom setting.
+     * functions are used.
      *
      * @param to_global Whether to use the global or custom setting.
      */
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fc6ec95124..891f1cb491 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -264,8 +264,8 @@ struct System::Impl {
             if (Settings::values.gamecard_current_game) {
                 fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
             } else if (!Settings::values.gamecard_path.GetValue().empty()) {
-                fs_controller.SetGameCard(GetGameFileFromPath(
-                    virtual_filesystem, static_cast<std::string>(Settings::values.gamecard_path)));
+                const auto gamecard_path = Settings::values.gamecard_path.GetValue();
+                fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, gamecard_path));
             }
         }
 
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 4861a131e6..45b3d73402 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -84,8 +84,8 @@ public:
         std::lock_guard lock{mutex};
         const auto axis_value =
             static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
-        return axis_value * Settings::values.mouse_panning_sensitivity.GetValue() /
-               (100.0f * range);
+        const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue();
+        return axis_value * sensitivity / (100.0f * range);
     }
 
     std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index e21f15c726..1a0f75373d 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -282,22 +282,23 @@ void Config::Initialize(const std::string& config_name) {
 template <>
 void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
     const QString name = QString::fromStdString(setting.GetLabel());
+    const auto default_value = QString::fromStdString(setting.GetDefault());
     if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
-        setting.SetValue(setting.GetDefault());
+        setting.SetValue(default_value.toStdString());
     } else {
-        setting.SetValue(qt_config->value(name, QString::fromStdString(setting.GetDefault()))
-                             .toString()
-                             .toStdString());
+        setting.SetValue(qt_config->value(name, default_value).toString().toStdString());
     }
 }
+
 template <typename Type>
 void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
     const QString name = QString::fromStdString(setting.GetLabel());
+    const Type default_value = setting.GetDefault();
     if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
-        setting.SetValue(setting.GetDefault());
+        setting.SetValue(default_value);
     } else {
         setting.SetValue(
-            static_cast<QVariant>(qt_config->value(name, setting.GetDefault())).value<Type>());
+            static_cast<QVariant>(qt_config->value(name, default_value)).value<Type>());
     }
 }
 
@@ -305,10 +306,11 @@ void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
 template <>
 void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& setting) {
     const QString name = QString::fromStdString(setting.GetLabel());
-    qt_config->setValue(name + QStringLiteral("/default"),
-                        setting.GetValue() == setting.GetDefault());
-    qt_config->setValue(name, QString::fromStdString(setting.GetValue()));
+    const std::string& value = setting.GetValue();
+    qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
+    qt_config->setValue(name, QString::fromStdString(value));
 }
+
 // Explicit float definition: use a double as Qt doesn't write legible floats to config files
 template <>
 void Config::WriteBasicSetting(const Settings::BasicSetting<float>& setting) {
@@ -318,12 +320,13 @@ void Config::WriteBasicSetting(const Settings::BasicSetting<float>& setting) {
                         setting.GetValue() == setting.GetDefault());
     qt_config->setValue(name, value);
 }
+
 template <typename Type>
 void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
     const QString name = QString::fromStdString(setting.GetLabel());
-    qt_config->setValue(name + QStringLiteral("/default"),
-                        setting.GetValue() == setting.GetDefault());
-    qt_config->setValue(name, setting.GetValue());
+    const Type value = setting.GetValue();
+    qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
+    qt_config->setValue(name, value);
 }
 
 // Explicit float definition: use a double as Qt doesn't write legible floats to config files
@@ -340,16 +343,17 @@ void Config::WriteGlobalSetting(const Settings::Setting<float>& setting) {
         qt_config->setValue(name, value);
     }
 }
+
 template <typename Type>
 void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) {
-    QString name = QString::fromStdString(setting.GetLabel());
+    const QString name = QString::fromStdString(setting.GetLabel());
+    const Type& value = setting.GetValue(global);
     if (!global) {
         qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
     }
     if (global || !setting.UsingGlobal()) {
-        qt_config->setValue(name + QStringLiteral("/default"),
-                            setting.GetValue(global) == setting.GetDefault());
-        qt_config->setValue(name, setting.GetValue(global));
+        qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
+        qt_config->setValue(name, value);
     }
 }