summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt15
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/common/settings.cpp248
-rw-r--r--src/common/settings.h860
-rw-r--r--src/common/settings_common.cpp58
-rw-r--r--src/common/settings_common.h256
-rw-r--r--src/common/settings_enums.h214
-rw-r--r--src/common/settings_setting.h394
8 files changed, 1455 insertions, 592 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 3adf13a3f..bf97d9ba2 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -110,8 +110,12 @@ add_library(common STATIC
110 scratch_buffer.h 110 scratch_buffer.h
111 settings.cpp 111 settings.cpp
112 settings.h 112 settings.h
113 settings_common.cpp
114 settings_common.h
115 settings_enums.h
113 settings_input.cpp 116 settings_input.cpp
114 settings_input.h 117 settings_input.h
118 settings_setting.h
115 socket_types.h 119 socket_types.h
116 spin_lock.cpp 120 spin_lock.cpp
117 spin_lock.h 121 spin_lock.h
@@ -193,9 +197,16 @@ if (MSVC)
193 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 197 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
194 /we4800 # Implicit conversion from 'type' to bool. Possible information loss 198 /we4800 # Implicit conversion from 'type' to bool. Possible information loss
195 ) 199 )
196else() 200endif()
201
202if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
197 target_compile_options(common PRIVATE 203 target_compile_options(common PRIVATE
198 $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> 204 -fsized-deallocation
205 -Werror=unreachable-code-aggressive
206 )
207 target_compile_definitions(common PRIVATE
208 # Clang 14 and earlier have errors when explicitly instantiating Settings::Setting
209 $<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>
199 ) 210 )
200endif() 211endif()
201 212
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 6e8e8eb36..d4f27197c 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -108,7 +108,7 @@ public:
108 108
109 using namespace Common::Literals; 109 using namespace Common::Literals;
110 // Prevent logs from exceeding a set maximum size in the event that log entries are spammed. 110 // Prevent logs from exceeding a set maximum size in the event that log entries are spammed.
111 const auto write_limit = Settings::values.extended_logging ? 1_GiB : 100_MiB; 111 const auto write_limit = Settings::values.extended_logging.GetValue() ? 1_GiB : 100_MiB;
112 const bool write_limit_exceeded = bytes_written > write_limit; 112 const bool write_limit_exceeded = bytes_written > write_limit;
113 if (entry.log_level >= Level::Error || write_limit_exceeded) { 113 if (entry.log_level >= Level::Error || write_limit_exceeded) {
114 if (write_limit_exceeded) { 114 if (write_limit_exceeded) {
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index d4e55f988..15fd2e222 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -7,9 +7,16 @@
7#include <exception> 7#include <exception>
8#include <stdexcept> 8#include <stdexcept>
9#endif 9#endif
10#include <compare>
11#include <cstddef>
12#include <filesystem>
13#include <functional>
10#include <string_view> 14#include <string_view>
15#include <type_traits>
16#include <fmt/core.h>
11 17
12#include "common/assert.h" 18#include "common/assert.h"
19#include "common/fs/fs_util.h"
13#include "common/fs/path_util.h" 20#include "common/fs/path_util.h"
14#include "common/logging/log.h" 21#include "common/logging/log.h"
15#include "common/settings.h" 22#include "common/settings.h"
@@ -17,11 +24,50 @@
17 24
18namespace Settings { 25namespace Settings {
19 26
27// Clang 14 and earlier have errors when explicitly instantiating these classes
28#ifndef CANNOT_EXPLICITLY_INSTANTIATE
29#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
30#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
31
32SETTING(AudioEngine, false);
33SETTING(bool, false);
34SETTING(int, false);
35SETTING(std::string, false);
36SETTING(u16, false);
37SWITCHABLE(AnisotropyMode, true);
38SWITCHABLE(AntiAliasing, false);
39SWITCHABLE(AspectRatio, true);
40SWITCHABLE(AstcDecodeMode, true);
41SWITCHABLE(AstcRecompression, true);
42SWITCHABLE(AudioMode, true);
43SWITCHABLE(CpuAccuracy, true);
44SWITCHABLE(FullscreenMode, true);
45SWITCHABLE(GpuAccuracy, true);
46SWITCHABLE(Language, true);
47SWITCHABLE(NvdecEmulation, false);
48SWITCHABLE(Region, true);
49SWITCHABLE(RendererBackend, true);
50SWITCHABLE(ScalingFilter, false);
51SWITCHABLE(ShaderBackend, true);
52SWITCHABLE(TimeZone, true);
53SETTING(VSyncMode, true);
54SWITCHABLE(bool, false);
55SWITCHABLE(int, false);
56SWITCHABLE(int, true);
57SWITCHABLE(s64, false);
58SWITCHABLE(u16, true);
59SWITCHABLE(u32, false);
60SWITCHABLE(u8, false);
61SWITCHABLE(u8, true);
62
63#undef SETTING
64#undef SWITCHABLE
65#endif
66
20Values values; 67Values values;
21static bool configuring_global = true;
22 68
23std::string GetTimeZoneString() { 69std::string GetTimeZoneString(TimeZone time_zone) {
24 const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue()); 70 const auto time_zone_index = static_cast<std::size_t>(time_zone);
25 ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size()); 71 ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size());
26 72
27 std::string location_name; 73 std::string location_name;
@@ -61,73 +107,35 @@ void LogSettings() {
61 }; 107 };
62 108
63 LOG_INFO(Config, "yuzu Configuration:"); 109 LOG_INFO(Config, "yuzu Configuration:");
64 log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue()); 110 for (auto& [category, settings] : values.linkage.by_category) {
65 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); 111 for (const auto& setting : settings) {
66 log_setting("System_DeviceName", values.device_name.GetValue()); 112 if (setting->Id() == values.yuzu_token.Id()) {
67 log_setting("System_CurrentUser", values.current_user.GetValue()); 113 // Hide the token secret, for security reasons.
68 log_setting("System_LanguageIndex", values.language_index.GetValue()); 114 continue;
69 log_setting("System_RegionIndex", values.region_index.GetValue()); 115 }
70 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 116
71 log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue()); 117 const auto name = fmt::format(
72 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 118 "{:c}{:c} {}.{}", setting->ToString() == setting->DefaultToString() ? '-' : 'M',
73 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); 119 setting->UsingGlobal() ? '-' : 'C', TranslateCategory(category),
74 log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue()); 120 setting->GetLabel());
75 log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue()); 121
76 log_setting("Renderer_FSRSlider", values.fsr_sharpening_slider.GetValue()); 122 log_setting(name, setting->Canonicalize());
77 log_setting("Renderer_AntiAliasing", values.anti_aliasing.GetValue()); 123 }
78 log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue()); 124 }
79 log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
80 log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
81 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
82 log_setting("Renderer_UseAsynchronousGpuEmulation",
83 values.use_asynchronous_gpu_emulation.GetValue());
84 log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
85 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
86 log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
87 log_setting("Renderer_AstcRecompression", values.astc_recompression.GetValue());
88 log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
89 log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
90 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
91 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
92 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
93 log_setting("Audio_OutputEngine", values.sink_id.GetValue());
94 log_setting("Audio_OutputDevice", values.audio_output_device_id.GetValue());
95 log_setting("Audio_InputDevice", values.audio_input_device_id.GetValue());
96 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
97 log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir)); 125 log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
98 log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir)); 126 log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
99 log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir)); 127 log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
100 log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir)); 128 log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
101 log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); 129 log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
102 log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
103 log_setting("Debugging_GDBStub", values.use_gdbstub.GetValue());
104 log_setting("Input_EnableMotion", values.motion_enabled.GetValue());
105 log_setting("Input_EnableVibration", values.vibration_enabled.GetValue());
106 log_setting("Input_EnableTouch", values.touchscreen.enabled);
107 log_setting("Input_EnableMouse", values.mouse_enabled.GetValue());
108 log_setting("Input_EnableKeyboard", values.keyboard_enabled.GetValue());
109 log_setting("Input_EnableRingController", values.enable_ring_controller.GetValue());
110 log_setting("Input_EnableIrSensor", values.enable_ir_sensor.GetValue());
111 log_setting("Input_EnableCustomJoycon", values.enable_joycon_driver.GetValue());
112 log_setting("Input_EnableCustomProController", values.enable_procon_driver.GetValue());
113 log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue());
114}
115
116bool IsConfiguringGlobal() {
117 return configuring_global;
118}
119
120void SetConfiguringGlobal(bool is_global) {
121 configuring_global = is_global;
122} 130}
123 131
124bool IsGPULevelExtreme() { 132bool IsGPULevelExtreme() {
125 return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme; 133 return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme;
126} 134}
127 135
128bool IsGPULevelHigh() { 136bool IsGPULevelHigh() {
129 return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme || 137 return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme ||
130 values.gpu_accuracy.GetValue() == GPUAccuracy::High; 138 values.gpu_accuracy.GetValue() == GpuAccuracy::High;
131} 139}
132 140
133bool IsFastmemEnabled() { 141bool IsFastmemEnabled() {
@@ -144,6 +152,61 @@ float Volume() {
144 return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault()); 152 return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault());
145} 153}
146 154
155const char* TranslateCategory(Category category) {
156 switch (category) {
157 case Category::Audio:
158 return "Audio";
159 case Category::Core:
160 return "Core";
161 case Category::Cpu:
162 case Category::CpuDebug:
163 case Category::CpuUnsafe:
164 return "Cpu";
165 case Category::Renderer:
166 case Category::RendererAdvanced:
167 case Category::RendererDebug:
168 return "Renderer";
169 case Category::System:
170 case Category::SystemAudio:
171 return "System";
172 case Category::DataStorage:
173 return "Data Storage";
174 case Category::Debugging:
175 case Category::DebuggingGraphics:
176 return "Debugging";
177 case Category::Miscellaneous:
178 return "Miscellaneous";
179 case Category::Network:
180 return "Network";
181 case Category::WebService:
182 return "WebService";
183 case Category::AddOns:
184 return "DisabledAddOns";
185 case Category::Controls:
186 return "Controls";
187 case Category::Ui:
188 case Category::UiGeneral:
189 return "UI";
190 case Category::UiLayout:
191 return "UiLayout";
192 case Category::UiGameList:
193 return "UiGameList";
194 case Category::Screenshots:
195 return "Screenshots";
196 case Category::Shortcuts:
197 return "Shortcuts";
198 case Category::Multiplayer:
199 return "Multiplayer";
200 case Category::Services:
201 return "Services";
202 case Category::Paths:
203 return "Paths";
204 case Category::MaxEnum:
205 break;
206 }
207 return "Miscellaneous";
208}
209
147void UpdateRescalingInfo() { 210void UpdateRescalingInfo() {
148 const auto setup = values.resolution_setup.GetValue(); 211 const auto setup = values.resolution_setup.GetValue();
149 auto& info = values.resolution_info; 212 auto& info = values.resolution_info;
@@ -212,66 +275,19 @@ void RestoreGlobalState(bool is_powered_on) {
212 return; 275 return;
213 } 276 }
214 277
215 // Audio 278 for (const auto& reset : values.linkage.restore_functions) {
216 values.volume.SetGlobal(true); 279 reset();
217 280 }
218 // Core 281}
219 values.use_multi_core.SetGlobal(true);
220 values.use_unsafe_extended_memory_layout.SetGlobal(true);
221
222 // CPU
223 values.cpu_accuracy.SetGlobal(true);
224 values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
225 values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
226 values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
227 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
228 values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
229 values.cpuopt_unsafe_ignore_global_monitor.SetGlobal(true);
230 282
231 // Renderer 283static bool configuring_global = true;
232 values.fsr_sharpening_slider.SetGlobal(true);
233 values.renderer_backend.SetGlobal(true);
234 values.async_presentation.SetGlobal(true);
235 values.renderer_force_max_clock.SetGlobal(true);
236 values.vulkan_device.SetGlobal(true);
237 values.fullscreen_mode.SetGlobal(true);
238 values.aspect_ratio.SetGlobal(true);
239 values.resolution_setup.SetGlobal(true);
240 values.scaling_filter.SetGlobal(true);
241 values.anti_aliasing.SetGlobal(true);
242 values.max_anisotropy.SetGlobal(true);
243 values.use_speed_limit.SetGlobal(true);
244 values.speed_limit.SetGlobal(true);
245 values.use_disk_shader_cache.SetGlobal(true);
246 values.gpu_accuracy.SetGlobal(true);
247 values.use_asynchronous_gpu_emulation.SetGlobal(true);
248 values.nvdec_emulation.SetGlobal(true);
249 values.accelerate_astc.SetGlobal(true);
250 values.async_astc.SetGlobal(true);
251 values.astc_recompression.SetGlobal(true);
252 values.use_reactive_flushing.SetGlobal(true);
253 values.shader_backend.SetGlobal(true);
254 values.use_asynchronous_shaders.SetGlobal(true);
255 values.use_fast_gpu_time.SetGlobal(true);
256 values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
257 values.bg_red.SetGlobal(true);
258 values.bg_green.SetGlobal(true);
259 values.bg_blue.SetGlobal(true);
260 values.enable_compute_pipelines.SetGlobal(true);
261 values.use_video_framerate.SetGlobal(true);
262 284
263 // System 285bool IsConfiguringGlobal() {
264 values.language_index.SetGlobal(true); 286 return configuring_global;
265 values.region_index.SetGlobal(true); 287}
266 values.time_zone_index.SetGlobal(true);
267 values.rng_seed.SetGlobal(true);
268 values.sound_index.SetGlobal(true);
269 288
270 // Controls 289void SetConfiguringGlobal(bool is_global) {
271 values.players.SetGlobal(true); 290 configuring_global = is_global;
272 values.use_docked_mode.SetGlobal(true);
273 values.vibration_enabled.SetGlobal(true);
274 values.motion_enabled.SetGlobal(true);
275} 291}
276 292
277} // namespace Settings 293} // namespace Settings
diff --git a/src/common/settings.h b/src/common/settings.h
index 59e96e74f..b0bc6519a 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -6,95 +6,21 @@
6#include <algorithm> 6#include <algorithm>
7#include <array> 7#include <array>
8#include <map> 8#include <map>
9#include <optional> 9#include <memory>
10#include <stdexcept>
10#include <string> 11#include <string>
11#include <utility> 12#include <utility>
12#include <vector> 13#include <vector>
13 14
14#include "common/common_types.h" 15#include "common/common_types.h"
16#include "common/settings_common.h"
17#include "common/settings_enums.h"
15#include "common/settings_input.h" 18#include "common/settings_input.h"
19#include "common/settings_setting.h"
16 20
17namespace Settings { 21namespace Settings {
18 22
19enum class VSyncMode : u32 { 23const char* TranslateCategory(Settings::Category category);
20 Immediate = 0,
21 Mailbox = 1,
22 FIFO = 2,
23 FIFORelaxed = 3,
24};
25
26enum class RendererBackend : u32 {
27 OpenGL = 0,
28 Vulkan = 1,
29 Null = 2,
30};
31
32enum class ShaderBackend : u32 {
33 GLSL = 0,
34 GLASM = 1,
35 SPIRV = 2,
36};
37
38enum class GPUAccuracy : u32 {
39 Normal = 0,
40 High = 1,
41 Extreme = 2,
42};
43
44enum class CPUAccuracy : u32 {
45 Auto = 0,
46 Accurate = 1,
47 Unsafe = 2,
48 Paranoid = 3,
49};
50
51enum class FullscreenMode : u32 {
52 Borderless = 0,
53 Exclusive = 1,
54};
55
56enum class NvdecEmulation : u32 {
57 Off = 0,
58 CPU = 1,
59 GPU = 2,
60};
61
62enum class ResolutionSetup : u32 {
63 Res1_2X = 0,
64 Res3_4X = 1,
65 Res1X = 2,
66 Res3_2X = 3,
67 Res2X = 4,
68 Res3X = 5,
69 Res4X = 6,
70 Res5X = 7,
71 Res6X = 8,
72 Res7X = 9,
73 Res8X = 10,
74};
75
76enum class ScalingFilter : u32 {
77 NearestNeighbor = 0,
78 Bilinear = 1,
79 Bicubic = 2,
80 Gaussian = 3,
81 ScaleForce = 4,
82 Fsr = 5,
83 LastFilter = Fsr,
84};
85
86enum class AntiAliasing : u32 {
87 None = 0,
88 Fxaa = 1,
89 Smaa = 2,
90 LastAA = Smaa,
91};
92
93enum class AstcRecompression : u32 {
94 Uncompressed = 0,
95 Bc1 = 1,
96 Bc3 = 2,
97};
98 24
99struct ResolutionScalingInfo { 25struct ResolutionScalingInfo {
100 u32 up_scale{1}; 26 u32 up_scale{1};
@@ -119,239 +45,47 @@ struct ResolutionScalingInfo {
119 } 45 }
120}; 46};
121 47
122/** The Setting class is a simple resource manager. It defines a label and default value alongside 48#ifndef CANNOT_EXPLICITLY_INSTANTIATE
123 * the actual value of the setting for simpler and less-error prone use with frontend 49// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
124 * configurations. Specifying a default value and label is required. A minimum and maximum range can 50#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
125 * be specified for sanitization. 51#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
126 */ 52
127template <typename Type, bool ranged = false> 53SETTING(AudioEngine, false);
128class Setting { 54SETTING(bool, false);
129protected: 55SETTING(int, false);
130 Setting() = default; 56SETTING(s32, false);
131 57SETTING(std::string, false);
132 /** 58SETTING(std::string, false);
133 * Only sets the setting to the given initializer, leaving the other members to their default 59SETTING(u16, false);
134 * initializers. 60SWITCHABLE(AnisotropyMode, true);
135 * 61SWITCHABLE(AntiAliasing, false);
136 * @param global_val Initial value of the setting 62SWITCHABLE(AspectRatio, true);
137 */ 63SWITCHABLE(AstcDecodeMode, true);
138 explicit Setting(const Type& val) : value{val} {} 64SWITCHABLE(AstcRecompression, true);
139 65SWITCHABLE(AudioMode, true);
140public: 66SWITCHABLE(CpuAccuracy, true);
141 /** 67SWITCHABLE(FullscreenMode, true);
142 * Sets a default value, label, and setting value. 68SWITCHABLE(GpuAccuracy, true);
143 * 69SWITCHABLE(Language, true);
144 * @param default_val Initial value of the setting, and default value of the setting 70SWITCHABLE(NvdecEmulation, false);
145 * @param name Label for the setting 71SWITCHABLE(Region, true);
146 */ 72SWITCHABLE(RendererBackend, true);
147 explicit Setting(const Type& default_val, const std::string& name) 73SWITCHABLE(ScalingFilter, false);
148 requires(!ranged) 74SWITCHABLE(ShaderBackend, true);
149 : value{default_val}, default_value{default_val}, label{name} {} 75SWITCHABLE(TimeZone, true);
150 virtual ~Setting() = default; 76SETTING(VSyncMode, true);
151 77SWITCHABLE(bool, false);
152 /** 78SWITCHABLE(int, false);
153 * Sets a default value, minimum value, maximum value, and label. 79SWITCHABLE(int, true);
154 * 80SWITCHABLE(s64, false);
155 * @param default_val Initial value of the setting, and default value of the setting 81SWITCHABLE(u16, true);
156 * @param min_val Sets the minimum allowed value of the setting 82SWITCHABLE(u32, false);
157 * @param max_val Sets the maximum allowed value of the setting 83SWITCHABLE(u8, false);
158 * @param name Label for the setting 84SWITCHABLE(u8, true);
159 */ 85
160 explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val, 86#undef SETTING
161 const std::string& name) 87#undef SWITCHABLE
162 requires(ranged) 88#endif
163 : value{default_val},
164 default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
165
166 /**
167 * Returns a reference to the setting's value.
168 *
169 * @returns A reference to the setting
170 */
171 [[nodiscard]] virtual const Type& GetValue() const {
172 return value;
173 }
174
175 /**
176 * Sets the setting to the given value.
177 *
178 * @param val The desired value
179 */
180 virtual void SetValue(const Type& val) {
181 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
182 std::swap(value, temp);
183 }
184
185 /**
186 * Returns the value that this setting was created with.
187 *
188 * @returns A reference to the default value
189 */
190 [[nodiscard]] const Type& GetDefault() const {
191 return default_value;
192 }
193
194 /**
195 * Returns the label this setting was created with.
196 *
197 * @returns A reference to the label
198 */
199 [[nodiscard]] const std::string& GetLabel() const {
200 return label;
201 }
202
203 /**
204 * Assigns a value to the setting.
205 *
206 * @param val The desired setting value
207 *
208 * @returns A reference to the setting
209 */
210 virtual const Type& operator=(const Type& val) {
211 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
212 std::swap(value, temp);
213 return value;
214 }
215
216 /**
217 * Returns a reference to the setting.
218 *
219 * @returns A reference to the setting
220 */
221 explicit virtual operator const Type&() const {
222 return value;
223 }
224
225protected:
226 Type value{}; ///< The setting
227 const Type default_value{}; ///< The default value
228 const Type maximum{}; ///< Maximum allowed value of the setting
229 const Type minimum{}; ///< Minimum allowed value of the setting
230 const std::string label{}; ///< The setting's label
231};
232
233/**
234 * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
235 * custom setting to switch to when a guest application specifically requires it. The effect is that
236 * other components of the emulator can access the setting's intended value without any need for the
237 * component to ask whether the custom or global setting is needed at the moment.
238 *
239 * By default, the global setting is used.
240 */
241template <typename Type, bool ranged = false>
242class SwitchableSetting : virtual public Setting<Type, ranged> {
243public:
244 /**
245 * Sets a default value, label, and setting value.
246 *
247 * @param default_val Initial value of the setting, and default value of the setting
248 * @param name Label for the setting
249 */
250 explicit SwitchableSetting(const Type& default_val, const std::string& name)
251 requires(!ranged)
252 : Setting<Type>{default_val, name} {}
253 virtual ~SwitchableSetting() = default;
254
255 /**
256 * Sets a default value, minimum value, maximum value, and label.
257 *
258 * @param default_val Initial value of the setting, and default value of the setting
259 * @param min_val Sets the minimum allowed value of the setting
260 * @param max_val Sets the maximum allowed value of the setting
261 * @param name Label for the setting
262 */
263 explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
264 const std::string& name)
265 requires(ranged)
266 : Setting<Type, true>{default_val, min_val, max_val, name} {}
267
268 /**
269 * Tells this setting to represent either the global or custom setting when other member
270 * functions are used.
271 *
272 * @param to_global Whether to use the global or custom setting.
273 */
274 void SetGlobal(bool to_global) {
275 use_global = to_global;
276 }
277
278 /**
279 * Returns whether this setting is using the global setting or not.
280 *
281 * @returns The global state
282 */
283 [[nodiscard]] bool UsingGlobal() const {
284 return use_global;
285 }
286
287 /**
288 * Returns either the global or custom setting depending on the values of this setting's global
289 * state or if the global value was specifically requested.
290 *
291 * @param need_global Request global value regardless of setting's state; defaults to false
292 *
293 * @returns The required value of the setting
294 */
295 [[nodiscard]] virtual const Type& GetValue() const override {
296 if (use_global) {
297 return this->value;
298 }
299 return custom;
300 }
301 [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
302 if (use_global || need_global) {
303 return this->value;
304 }
305 return custom;
306 }
307
308 /**
309 * Sets the current setting value depending on the global state.
310 *
311 * @param val The new value
312 */
313 void SetValue(const Type& val) override {
314 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
315 if (use_global) {
316 std::swap(this->value, temp);
317 } else {
318 std::swap(custom, temp);
319 }
320 }
321
322 /**
323 * Assigns the current setting value depending on the global state.
324 *
325 * @param val The new value
326 *
327 * @returns A reference to the current setting value
328 */
329 const Type& operator=(const Type& val) override {
330 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
331 if (use_global) {
332 std::swap(this->value, temp);
333 return this->value;
334 }
335 std::swap(custom, temp);
336 return custom;
337 }
338
339 /**
340 * Returns the current setting value depending on the global state.
341 *
342 * @returns A reference to the current setting value
343 */
344 virtual explicit operator const Type&() const override {
345 if (use_global) {
346 return this->value;
347 }
348 return custom;
349 }
350
351protected:
352 bool use_global{true}; ///< The setting's global state
353 Type custom{}; ///< The custom value of the setting
354};
355 89
356/** 90/**
357 * The InputSetting class allows for getting a reference to either the global or custom members. 91 * The InputSetting class allows for getting a reference to either the global or custom members.
@@ -391,208 +125,388 @@ struct TouchFromButtonMap {
391}; 125};
392 126
393struct Values { 127struct Values {
128 Linkage linkage{};
129
394 // Audio 130 // Audio
395 Setting<std::string> sink_id{"auto", "output_engine"}; 131 Setting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", Category::Audio,
396 Setting<std::string> audio_output_device_id{"auto", "output_device"}; 132 Specialization::RuntimeList};
397 Setting<std::string> audio_input_device_id{"auto", "input_device"}; 133 Setting<std::string> audio_output_device_id{linkage, "auto", "output_device", Category::Audio,
398 Setting<bool> audio_muted{false, "audio_muted"}; 134 Specialization::RuntimeList};
399 SwitchableSetting<u8, true> volume{100, 0, 200, "volume"}; 135 Setting<std::string> audio_input_device_id{linkage, "auto", "input_device", Category::Audio,
400 Setting<bool> dump_audio_commands{false, "dump_audio_commands"}; 136 Specialization::RuntimeList};
137 SwitchableSetting<AudioMode, true> sound_index{
138 linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
139 "sound_index", Category::SystemAudio, Specialization::Default, true,
140 true};
141 SwitchableSetting<u8, true> volume{linkage,
142 100,
143 0,
144 200,
145 "volume",
146 Category::Audio,
147 Specialization::Scalar | Specialization::Percentage,
148 true,
149 true};
150 Setting<bool, false> audio_muted{
151 linkage, false, "audio_muted", Category::Audio, Specialization::Default, false, true};
152 Setting<bool, false> dump_audio_commands{
153 linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
401 154
402 // Core 155 // Core
403 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"}; 156 SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
404 SwitchableSetting<bool> use_unsafe_extended_memory_layout{false, 157 SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
405 "use_unsafe_extended_memory_layout"}; 158 MemoryLayout::Memory_4Gb,
159 MemoryLayout::Memory_4Gb,
160 MemoryLayout::Memory_8Gb,
161 "memory_layout_mode",
162 Category::Core};
163 SwitchableSetting<bool> use_speed_limit{
164 linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, false, true};
165 SwitchableSetting<u16, true> speed_limit{linkage,
166 100,
167 0,
168 9999,
169 "speed_limit",
170 Category::Core,
171 Specialization::Countable | Specialization::Percentage,
172 true,
173 true,
174 &use_speed_limit};
406 175
407 // Cpu 176 // Cpu
408 SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, 177 SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
409 CPUAccuracy::Paranoid, "cpu_accuracy"}; 178 CpuAccuracy::Auto, CpuAccuracy::Paranoid,
410 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021 179 "cpu_accuracy", Category::Cpu};
411 Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"}; 180 Setting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
412 Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"}; 181
413 182 Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
414 Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"}; 183 Setting<bool> cpuopt_block_linking{linkage, true, "cpuopt_block_linking", Category::CpuDebug};
415 Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"}; 184 Setting<bool> cpuopt_return_stack_buffer{linkage, true, "cpuopt_return_stack_buffer",
416 Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"}; 185 Category::CpuDebug};
417 Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"}; 186 Setting<bool> cpuopt_fast_dispatcher{linkage, true, "cpuopt_fast_dispatcher",
418 Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"}; 187 Category::CpuDebug};
419 Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"}; 188 Setting<bool> cpuopt_context_elimination{linkage, true, "cpuopt_context_elimination",
420 Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"}; 189 Category::CpuDebug};
421 Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"}; 190 Setting<bool> cpuopt_const_prop{linkage, true, "cpuopt_const_prop", Category::CpuDebug};
422 Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"}; 191 Setting<bool> cpuopt_misc_ir{linkage, true, "cpuopt_misc_ir", Category::CpuDebug};
423 Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"}; 192 Setting<bool> cpuopt_reduce_misalign_checks{linkage, true, "cpuopt_reduce_misalign_checks",
424 Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"}; 193 Category::CpuDebug};
425 Setting<bool> cpuopt_ignore_memory_aborts{true, "cpuopt_ignore_memory_aborts"}; 194 Setting<bool> cpuopt_fastmem{linkage, true, "cpuopt_fastmem", Category::CpuDebug};
426 195 Setting<bool> cpuopt_fastmem_exclusives{linkage, true, "cpuopt_fastmem_exclusives",
427 SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"}; 196 Category::CpuDebug};
428 SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"}; 197 Setting<bool> cpuopt_recompile_exclusives{linkage, true, "cpuopt_recompile_exclusives",
198 Category::CpuDebug};
199 Setting<bool> cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts",
200 Category::CpuDebug};
201
202 SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma",
203 Category::CpuUnsafe};
204 SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{
205 linkage, true, "cpuopt_unsafe_reduce_fp_error", Category::CpuUnsafe};
429 SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{ 206 SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
430 true, "cpuopt_unsafe_ignore_standard_fpcr"}; 207 linkage, true, "cpuopt_unsafe_ignore_standard_fpcr", Category::CpuUnsafe};
431 SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"}; 208 SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{
432 SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"}; 209 linkage, true, "cpuopt_unsafe_inaccurate_nan", Category::CpuUnsafe};
210 SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{
211 linkage, true, "cpuopt_unsafe_fastmem_check", Category::CpuUnsafe};
433 SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{ 212 SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
434 true, "cpuopt_unsafe_ignore_global_monitor"}; 213 linkage, true, "cpuopt_unsafe_ignore_global_monitor", Category::CpuUnsafe};
435 214
436 // Renderer 215 // Renderer
437 SwitchableSetting<RendererBackend, true> renderer_backend{ 216 SwitchableSetting<RendererBackend, true> renderer_backend{
438 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"}; 217 linkage, RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null,
439 SwitchableSetting<bool> async_presentation{false, "async_presentation"}; 218 "backend", Category::Renderer};
440 SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"}; 219 SwitchableSetting<ShaderBackend, true> shader_backend{
441 Setting<bool> renderer_debug{false, "debug"}; 220 linkage, ShaderBackend::Glsl, ShaderBackend::Glsl, ShaderBackend::SpirV,
442 Setting<bool> renderer_shader_feedback{false, "shader_feedback"}; 221 "shader_backend", Category::Renderer, Specialization::RuntimeList};
443 Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; 222 SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
444 Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"}; 223 Specialization::RuntimeList};
445 SwitchableSetting<int> vulkan_device{0, "vulkan_device"}; 224
446 225 SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
447 ResolutionScalingInfo resolution_info{}; 226 Category::Renderer};
448 SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"}; 227 SwitchableSetting<bool> use_asynchronous_gpu_emulation{
449 SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"}; 228 linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
450 SwitchableSetting<int, true> fsr_sharpening_slider{25, 0, 200, "fsr_sharpening_slider"}; 229 SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
451 SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"}; 230 AstcDecodeMode::Gpu,
231 AstcDecodeMode::Cpu,
232 AstcDecodeMode::CpuAsynchronous,
233 "accelerate_astc",
234 Category::Renderer};
235 Setting<VSyncMode, true> vsync_mode{
236 linkage, VSyncMode::Fifo, VSyncMode::Immediate, VSyncMode::FifoRelaxed,
237 "use_vsync", Category::Renderer, Specialization::RuntimeList, true,
238 true};
239 SwitchableSetting<NvdecEmulation> nvdec_emulation{linkage, NvdecEmulation::Gpu,
240 "nvdec_emulation", Category::Renderer};
452 // *nix platforms may have issues with the borderless windowed fullscreen mode. 241 // *nix platforms may have issues with the borderless windowed fullscreen mode.
453 // Default to exclusive fullscreen on these platforms for now. 242 // Default to exclusive fullscreen on these platforms for now.
454 SwitchableSetting<FullscreenMode, true> fullscreen_mode{ 243 SwitchableSetting<FullscreenMode, true> fullscreen_mode{linkage,
455#ifdef _WIN32 244#ifdef _WIN32
456 FullscreenMode::Borderless, 245 FullscreenMode::Borderless,
457#else 246#else
458 FullscreenMode::Exclusive, 247 FullscreenMode::Exclusive,
459#endif 248#endif
460 FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"}; 249 FullscreenMode::Borderless,
461 SwitchableSetting<int, true> aspect_ratio{0, 0, 4, "aspect_ratio"}; 250 FullscreenMode::Exclusive,
462 SwitchableSetting<int, true> max_anisotropy{0, 0, 5, "max_anisotropy"}; 251 "fullscreen_mode",
463 SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"}; 252 Category::Renderer,
464 SwitchableSetting<u16, true> speed_limit{100, 0, 9999, "speed_limit"}; 253 Specialization::Default,
465 SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"}; 254 true,
466 SwitchableSetting<GPUAccuracy, true> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal, 255 true};
467 GPUAccuracy::Extreme, "gpu_accuracy"}; 256 SwitchableSetting<AspectRatio, true> aspect_ratio{linkage,
468 SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; 257 AspectRatio::R16_9,
469 SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; 258 AspectRatio::R16_9,
470 SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"}; 259 AspectRatio::Stretch,
471 SwitchableSetting<bool> async_astc{false, "async_astc"}; 260 "aspect_ratio",
472 Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate, 261 Category::Renderer,
473 VSyncMode::FIFORelaxed, "use_vsync"}; 262 Specialization::Default,
474 SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"}; 263 true,
475 SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL, 264 true};
476 ShaderBackend::SPIRV, "shader_backend"}; 265
477 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 266 ResolutionScalingInfo resolution_info{};
478 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 267 SwitchableSetting<ResolutionSetup> resolution_setup{linkage, ResolutionSetup::Res1X,
479 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true, 268 "resolution_setup", Category::Renderer};
480 "use_vulkan_driver_pipeline_cache"}; 269 SwitchableSetting<ScalingFilter> scaling_filter{linkage,
481 SwitchableSetting<bool> enable_compute_pipelines{false, "enable_compute_pipelines"}; 270 ScalingFilter::Bilinear,
482 SwitchableSetting<AstcRecompression, true> astc_recompression{ 271 "scaling_filter",
483 AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3, 272 Category::Renderer,
484 "astc_recompression"}; 273 Specialization::Default,
485 SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"}; 274 true,
486 SwitchableSetting<bool> barrier_feedback_loops{true, "barrier_feedback_loops"}; 275 true};
487 276 SwitchableSetting<AntiAliasing> anti_aliasing{linkage,
488 SwitchableSetting<u8> bg_red{0, "bg_red"}; 277 AntiAliasing::None,
489 SwitchableSetting<u8> bg_green{0, "bg_green"}; 278 "anti_aliasing",
490 SwitchableSetting<u8> bg_blue{0, "bg_blue"}; 279 Category::Renderer,
280 Specialization::Default,
281 true,
282 true};
283 SwitchableSetting<int, true> fsr_sharpening_slider{linkage,
284 25,
285 0,
286 200,
287 "fsr_sharpening_slider",
288 Category::Renderer,
289 Specialization::Scalar |
290 Specialization::Percentage,
291 true,
292 true};
293
294 SwitchableSetting<u8, false> bg_red{
295 linkage, 0, "bg_red", Category::Renderer, Specialization::Default, true, true};
296 SwitchableSetting<u8, false> bg_green{
297 linkage, 0, "bg_green", Category::Renderer, Specialization::Default, true, true};
298 SwitchableSetting<u8, false> bg_blue{
299 linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
300
301 SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
302 GpuAccuracy::High,
303 GpuAccuracy::Normal,
304 GpuAccuracy::Extreme,
305 "gpu_accuracy",
306 Category::RendererAdvanced,
307 Specialization::Default,
308 true,
309 true};
310 SwitchableSetting<AnisotropyMode, true> max_anisotropy{
311 linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16,
312 "max_anisotropy", Category::RendererAdvanced};
313 SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
314 AstcRecompression::Uncompressed,
315 AstcRecompression::Uncompressed,
316 AstcRecompression::Bc3,
317 "astc_recompression",
318 Category::RendererAdvanced};
319 SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation",
320 Category::RendererAdvanced};
321 SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
322 Category::RendererAdvanced};
323 SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing",
324 Category::RendererAdvanced};
325 SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
326 Category::RendererAdvanced};
327 SwitchableSetting<bool> use_fast_gpu_time{
328 linkage, true, "use_fast_gpu_time", Category::RendererAdvanced, Specialization::Default,
329 true, true};
330 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{linkage,
331 true,
332 "use_vulkan_driver_pipeline_cache",
333 Category::RendererAdvanced,
334 Specialization::Default,
335 true,
336 true};
337 SwitchableSetting<bool> enable_compute_pipelines{linkage, false, "enable_compute_pipelines",
338 Category::RendererAdvanced};
339 SwitchableSetting<bool> use_video_framerate{linkage, false, "use_video_framerate",
340 Category::RendererAdvanced};
341 SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
342 Category::RendererAdvanced};
343
344 Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
345 Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
346 Category::RendererDebug};
347 Setting<bool> enable_nsight_aftermath{linkage, false, "nsight_aftermath",
348 Category::RendererDebug};
349 Setting<bool> disable_shader_loop_safety_checks{
350 linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
491 351
492 // System 352 // System
493 SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; 353 SwitchableSetting<Language, true> language_index{linkage,
494 Setting<std::string> device_name{"Yuzu", "device_name"}; 354 Language::EnglishAmerican,
355 Language::Japanese,
356 Language::PortugueseBrazilian,
357 "language_index",
358 Category::System};
359 SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
360 Region::Taiwan, "region_index", Category::System};
361 SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
362 TimeZone::Auto, TimeZone::Zulu,
363 "time_zone_index", Category::System};
495 // Measured in seconds since epoch 364 // Measured in seconds since epoch
496 std::optional<s64> custom_rtc; 365 SwitchableSetting<bool> custom_rtc_enabled{
366 linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
367 SwitchableSetting<s64> custom_rtc{
368 linkage, 0, "custom_rtc", Category::System, Specialization::Time,
369 true, true, &custom_rtc_enabled};
497 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 370 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
498 s64 custom_rtc_differential; 371 s64 custom_rtc_differential;
372 SwitchableSetting<bool> rng_seed_enabled{
373 linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
374 SwitchableSetting<u32> rng_seed{
375 linkage, 0, "rng_seed", Category::System, Specialization::Hex,
376 true, true, &rng_seed_enabled};
377 Setting<std::string> device_name{
378 linkage, "yuzu", "device_name", Category::System, Specialization::Default, true, true};
499 379
500 Setting<s32> current_user{0, "current_user"}; 380 Setting<s32> current_user{linkage, 0, "current_user", Category::System};
501 SwitchableSetting<s32, true> language_index{1, 0, 17, "language_index"}; 381
502 SwitchableSetting<s32, true> region_index{1, 0, 6, "region_index"}; 382 SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System};
503 SwitchableSetting<s32, true> time_zone_index{0, 0, 45, "time_zone_index"};
504 SwitchableSetting<s32, true> sound_index{1, 0, 2, "sound_index"};
505 383
506 // Controls 384 // Controls
507 InputSetting<std::array<PlayerInput, 10>> players; 385 InputSetting<std::array<PlayerInput, 10>> players;
508 386
509 SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"}; 387 Setting<bool> enable_raw_input{
510 388 linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
511 Setting<bool> enable_raw_input{false, "enable_raw_input"}; 389// Only read/write enable_raw_input on Windows platforms
512 Setting<bool> controller_navigation{true, "controller_navigation"}; 390#ifdef _WIN32
513 Setting<bool> enable_joycon_driver{true, "enable_joycon_driver"}; 391 true
514 Setting<bool> enable_procon_driver{false, "enable_procon_driver"}; 392#else
515 393 false
516 SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"}; 394#endif
517 SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"}; 395 };
518 396 Setting<bool> controller_navigation{linkage, true, "controller_navigation", Category::Controls};
519 SwitchableSetting<bool> motion_enabled{true, "motion_enabled"}; 397 Setting<bool> enable_joycon_driver{linkage, true, "enable_joycon_driver", Category::Controls};
520 Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; 398 Setting<bool> enable_procon_driver{linkage, false, "enable_procon_driver", Category::Controls};
521 Setting<bool> enable_udp_controller{false, "enable_udp_controller"}; 399
522 400 SwitchableSetting<bool> vibration_enabled{linkage, true, "vibration_enabled",
523 Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"}; 401 Category::Controls};
524 Setting<bool> tas_enable{false, "tas_enable"}; 402 SwitchableSetting<bool> enable_accurate_vibrations{linkage, false, "enable_accurate_vibrations",
525 Setting<bool> tas_loop{false, "tas_loop"}; 403 Category::Controls};
526 404
527 Setting<bool> mouse_panning{false, "mouse_panning"}; 405 SwitchableSetting<bool> motion_enabled{linkage, true, "motion_enabled", Category::Controls};
528 Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; 406 Setting<std::string> udp_input_servers{linkage, "127.0.0.1:26760", "udp_input_servers",
529 Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; 407 Category::Controls};
530 Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100, 408 Setting<bool> enable_udp_controller{linkage, false, "enable_udp_controller",
531 "mouse_panning_deadzone_counterweight"}; 409 Category::Controls};
532 Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"}; 410
533 Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"}; 411 Setting<bool> pause_tas_on_load{linkage, true, "pause_tas_on_load", Category::Controls};
534 412 Setting<bool> tas_enable{linkage, false, "tas_enable", Category::Controls};
535 Setting<bool> mouse_enabled{false, "mouse_enabled"}; 413 Setting<bool> tas_loop{linkage, false, "tas_loop", Category::Controls};
536 Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; 414
537 Setting<bool> keyboard_enabled{false, "keyboard_enabled"}; 415 Setting<bool> mouse_panning{
538 416 linkage, false, "mouse_panning", Category::Controls, Specialization::Default, false};
539 Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"}; 417 Setting<u8, true> mouse_panning_sensitivity{
418 linkage, 50, 1, 100, "mouse_panning_sensitivity", Category::Controls};
419 Setting<bool> mouse_enabled{linkage, false, "mouse_enabled", Category::Controls};
420
421 Setting<u8, true> mouse_panning_x_sensitivity{
422 linkage, 50, 1, 100, "mouse_panning_x_sensitivity", Category::Controls};
423 Setting<u8, true> mouse_panning_y_sensitivity{
424 linkage, 50, 1, 100, "mouse_panning_y_sensitivity", Category::Controls};
425 Setting<u8, true> mouse_panning_deadzone_counterweight{
426 linkage, 20, 0, 100, "mouse_panning_deadzone_counterweight", Category::Controls};
427 Setting<u8, true> mouse_panning_decay_strength{
428 linkage, 18, 0, 100, "mouse_panning_decay_strength", Category::Controls};
429 Setting<u8, true> mouse_panning_min_decay{
430 linkage, 6, 0, 100, "mouse_panning_min_decay", Category::Controls};
431
432 Setting<bool> emulate_analog_keyboard{linkage, false, "emulate_analog_keyboard",
433 Category::Controls};
434 Setting<bool> keyboard_enabled{linkage, false, "keyboard_enabled", Category::Controls};
435
436 Setting<bool> debug_pad_enabled{linkage, false, "debug_pad_enabled", Category::Controls};
540 ButtonsRaw debug_pad_buttons; 437 ButtonsRaw debug_pad_buttons;
541 AnalogsRaw debug_pad_analogs; 438 AnalogsRaw debug_pad_analogs;
542 439
543 TouchscreenInput touchscreen; 440 TouchscreenInput touchscreen;
544 441
545 Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"}; 442 Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
546 Setting<int> touch_from_button_map_index{0, "touch_from_button_map"}; 443 "touch_device", Category::Controls};
444 Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
445 Category::Controls};
547 std::vector<TouchFromButtonMap> touch_from_button_maps; 446 std::vector<TouchFromButtonMap> touch_from_button_maps;
548 447
549 Setting<bool> enable_ring_controller{true, "enable_ring_controller"}; 448 Setting<bool> enable_ring_controller{linkage, true, "enable_ring_controller",
449 Category::Controls};
550 RingconRaw ringcon_analogs; 450 RingconRaw ringcon_analogs;
551 451
552 Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"}; 452 Setting<bool> enable_ir_sensor{linkage, false, "enable_ir_sensor", Category::Controls};
553 Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"}; 453 Setting<std::string> ir_sensor_device{linkage, "auto", "ir_sensor_device", Category::Controls};
554 454
555 Setting<bool> random_amiibo_id{false, "random_amiibo_id"}; 455 Setting<bool> random_amiibo_id{linkage, false, "random_amiibo_id", Category::Controls};
556 456
557 // Data Storage 457 // Data Storage
558 Setting<bool> use_virtual_sd{true, "use_virtual_sd"}; 458 Setting<bool> use_virtual_sd{linkage, true, "use_virtual_sd", Category::DataStorage};
559 Setting<bool> gamecard_inserted{false, "gamecard_inserted"}; 459 Setting<bool> gamecard_inserted{linkage, false, "gamecard_inserted", Category::DataStorage};
560 Setting<bool> gamecard_current_game{false, "gamecard_current_game"}; 460 Setting<bool> gamecard_current_game{linkage, false, "gamecard_current_game",
561 Setting<std::string> gamecard_path{std::string(), "gamecard_path"}; 461 Category::DataStorage};
462 Setting<std::string> gamecard_path{linkage, std::string(), "gamecard_path",
463 Category::DataStorage};
562 464
563 // Debugging 465 // Debugging
564 bool record_frame_times; 466 bool record_frame_times;
565 Setting<bool> use_gdbstub{false, "use_gdbstub"}; 467 Setting<bool> use_gdbstub{linkage, false, "use_gdbstub", Category::Debugging};
566 Setting<u16> gdbstub_port{6543, "gdbstub_port"}; 468 Setting<u16> gdbstub_port{linkage, 6543, "gdbstub_port", Category::Debugging};
567 Setting<std::string> program_args{std::string(), "program_args"}; 469 Setting<std::string> program_args{linkage, std::string(), "program_args", Category::Debugging};
568 Setting<bool> dump_exefs{false, "dump_exefs"}; 470 Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
569 Setting<bool> dump_nso{false, "dump_nso"}; 471 Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
570 Setting<bool> dump_shaders{false, "dump_shaders"}; 472 Setting<bool> dump_shaders{
571 Setting<bool> dump_macros{false, "dump_macros"}; 473 linkage, false, "dump_shaders", Category::DebuggingGraphics, Specialization::Default,
572 Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"}; 474 false};
573 Setting<bool> reporting_services{false, "reporting_services"}; 475 Setting<bool> dump_macros{
574 Setting<bool> quest_flag{false, "quest_flag"}; 476 linkage, false, "dump_macros", Category::DebuggingGraphics, Specialization::Default, false};
575 Setting<bool> disable_macro_jit{false, "disable_macro_jit"}; 477 Setting<bool> enable_fs_access_log{linkage, false, "enable_fs_access_log", Category::Debugging};
576 Setting<bool> disable_macro_hle{false, "disable_macro_hle"}; 478 Setting<bool> reporting_services{
577 Setting<bool> extended_logging{false, "extended_logging"}; 479 linkage, false, "reporting_services", Category::Debugging, Specialization::Default, false};
578 Setting<bool> use_debug_asserts{false, "use_debug_asserts"}; 480 Setting<bool> quest_flag{linkage, false, "quest_flag", Category::Debugging};
579 Setting<bool> use_auto_stub{false, "use_auto_stub"}; 481 Setting<bool> disable_macro_jit{linkage, false, "disable_macro_jit",
580 Setting<bool> enable_all_controllers{false, "enable_all_controllers"}; 482 Category::DebuggingGraphics};
581 Setting<bool> create_crash_dumps{false, "create_crash_dumps"}; 483 Setting<bool> disable_macro_hle{linkage, false, "disable_macro_hle",
582 Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"}; 484 Category::DebuggingGraphics};
485 Setting<bool> extended_logging{
486 linkage, false, "extended_logging", Category::Debugging, Specialization::Default, false};
487 Setting<bool> use_debug_asserts{linkage, false, "use_debug_asserts", Category::Debugging};
488 Setting<bool> use_auto_stub{
489 linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
490 Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
491 Category::Debugging};
492 Setting<bool> create_crash_dumps{linkage, false, "create_crash_dumps", Category::Debugging};
493 Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
583 494
584 // Miscellaneous 495 // Miscellaneous
585 Setting<std::string> log_filter{"*:Info", "log_filter"}; 496 Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
586 Setting<bool> use_dev_keys{false, "use_dev_keys"}; 497 Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
587 498
588 // Network 499 // Network
589 Setting<std::string> network_interface{std::string(), "network_interface"}; 500 Setting<std::string> network_interface{linkage, std::string(), "network_interface",
501 Category::Network};
590 502
591 // WebService 503 // WebService
592 Setting<bool> enable_telemetry{true, "enable_telemetry"}; 504 Setting<bool> enable_telemetry{linkage, true, "enable_telemetry", Category::WebService};
593 Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"}; 505 Setting<std::string> web_api_url{linkage, "https://api.yuzu-emu.org", "web_api_url",
594 Setting<std::string> yuzu_username{std::string(), "yuzu_username"}; 506 Category::WebService};
595 Setting<std::string> yuzu_token{std::string(), "yuzu_token"}; 507 Setting<std::string> yuzu_username{linkage, std::string(), "yuzu_username",
508 Category::WebService};
509 Setting<std::string> yuzu_token{linkage, std::string(), "yuzu_token", Category::WebService};
596 510
597 // Add-Ons 511 // Add-Ons
598 std::map<u64, std::vector<std::string>> disabled_addons; 512 std::map<u64, std::vector<std::string>> disabled_addons;
@@ -600,9 +514,6 @@ struct Values {
600 514
601extern Values values; 515extern Values values;
602 516
603bool IsConfiguringGlobal();
604void SetConfiguringGlobal(bool is_global);
605
606bool IsGPULevelExtreme(); 517bool IsGPULevelExtreme();
607bool IsGPULevelHigh(); 518bool IsGPULevelHigh();
608 519
@@ -610,7 +521,7 @@ bool IsFastmemEnabled();
610 521
611float Volume(); 522float Volume();
612 523
613std::string GetTimeZoneString(); 524std::string GetTimeZoneString(TimeZone time_zone);
614 525
615void LogSettings(); 526void LogSettings();
616 527
@@ -619,4 +530,7 @@ void UpdateRescalingInfo();
619// Restore the global state of all applicable settings in the Values struct 530// Restore the global state of all applicable settings in the Values struct
620void RestoreGlobalState(bool is_powered_on); 531void RestoreGlobalState(bool is_powered_on);
621 532
533bool IsConfiguringGlobal();
534void SetConfiguringGlobal(bool is_global);
535
622} // namespace Settings 536} // namespace Settings
diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp
new file mode 100644
index 000000000..dedf5ef90
--- /dev/null
+++ b/src/common/settings_common.cpp
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <string>
5#include "common/settings_common.h"
6
7namespace Settings {
8
9BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Category category_,
10 bool save_, bool runtime_modifiable_, u32 specialization_,
11 BasicSetting* other_setting_)
12 : label{name}, category{category_}, id{linkage.count}, save{save_},
13 runtime_modifiable{runtime_modifiable_}, specialization{specialization_},
14 other_setting{other_setting_} {
15 linkage.by_category[category].push_back(this);
16 linkage.count++;
17}
18
19BasicSetting::~BasicSetting() = default;
20
21std::string BasicSetting::ToStringGlobal() const {
22 return this->ToString();
23}
24
25bool BasicSetting::UsingGlobal() const {
26 return true;
27}
28
29void BasicSetting::SetGlobal(bool global) {}
30
31bool BasicSetting::Save() const {
32 return save;
33}
34
35bool BasicSetting::RuntimeModfiable() const {
36 return runtime_modifiable;
37}
38
39Category BasicSetting::GetCategory() const {
40 return category;
41}
42
43u32 BasicSetting::Specialization() const {
44 return specialization;
45}
46
47BasicSetting* BasicSetting::PairedSetting() const {
48 return other_setting;
49}
50
51const std::string& BasicSetting::GetLabel() const {
52 return label;
53}
54
55Linkage::Linkage(u32 initial_count) : count{initial_count} {}
56Linkage::~Linkage() = default;
57
58} // namespace Settings
diff --git a/src/common/settings_common.h b/src/common/settings_common.h
new file mode 100644
index 000000000..2efb329b0
--- /dev/null
+++ b/src/common/settings_common.h
@@ -0,0 +1,256 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <functional>
7#include <map>
8#include <string>
9#include <typeindex>
10#include "common/common_types.h"
11
12namespace Settings {
13
14enum class Category : u32 {
15 Audio,
16 Core,
17 Cpu,
18 CpuDebug,
19 CpuUnsafe,
20 Renderer,
21 RendererAdvanced,
22 RendererDebug,
23 System,
24 SystemAudio,
25 DataStorage,
26 Debugging,
27 DebuggingGraphics,
28 Miscellaneous,
29 Network,
30 WebService,
31 AddOns,
32 Controls,
33 Ui,
34 UiGeneral,
35 UiLayout,
36 UiGameList,
37 Screenshots,
38 Shortcuts,
39 Multiplayer,
40 Services,
41 Paths,
42 MaxEnum,
43};
44
45constexpr u8 SpecializationTypeMask = 0xf;
46constexpr u8 SpecializationAttributeMask = 0xf0;
47constexpr u8 SpecializationAttributeOffset = 4;
48
49// Scalar and countable could have better names
50enum Specialization : u8 {
51 Default = 0,
52 Time = 1, // Duration or specific moment in time
53 Hex = 2, // Hexadecimal number
54 List = 3, // Setting has specific members
55 RuntimeList = 4, // Members of the list are determined during runtime
56 Scalar = 5, // Values are continuous
57 Countable = 6, // Can be stepped through
58 Paired = 7, // Another setting is associated with this setting
59
60 Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
61};
62
63class BasicSetting;
64
65class Linkage {
66public:
67 explicit Linkage(u32 initial_count = 0);
68 ~Linkage();
69 std::map<Category, std::vector<BasicSetting*>> by_category{};
70 std::vector<std::function<void()>> restore_functions{};
71 u32 count;
72};
73
74/**
75 * BasicSetting is an abstract class that only keeps track of metadata. The string methods are
76 * available to get data values out.
77 */
78class BasicSetting {
79protected:
80 explicit BasicSetting(Linkage& linkage, const std::string& name, Category category_, bool save_,
81 bool runtime_modifiable_, u32 specialization,
82 BasicSetting* other_setting);
83
84public:
85 virtual ~BasicSetting();
86
87 /*
88 * Data retrieval
89 */
90
91 /**
92 * Returns a string representation of the internal data. If the Setting is Switchable, it
93 * respects the internal global state: it is based on GetValue().
94 *
95 * @returns A string representation of the internal data.
96 */
97 [[nodiscard]] virtual std::string ToString() const = 0;
98
99 /**
100 * Returns a string representation of the global version of internal data. If the Setting is
101 * not Switchable, it behaves like ToString.
102 *
103 * @returns A string representation of the global version of internal data.
104 */
105 [[nodiscard]] virtual std::string ToStringGlobal() const;
106
107 /**
108 * @returns A string representation of the Setting's default value.
109 */
110 [[nodiscard]] virtual std::string DefaultToString() const = 0;
111
112 /**
113 * Returns a string representation of the minimum value of the setting. If the Setting is not
114 * ranged, the string represents the default initialization of the data type.
115 *
116 * @returns A string representation of the minimum value of the setting.
117 */
118 [[nodiscard]] virtual std::string MinVal() const = 0;
119
120 /**
121 * Returns a string representation of the maximum value of the setting. If the Setting is not
122 * ranged, the string represents the default initialization of the data type.
123 *
124 * @returns A string representation of the maximum value of the setting.
125 */
126 [[nodiscard]] virtual std::string MaxVal() const = 0;
127
128 /**
129 * Takes a string input, converts it to the internal data type if necessary, and then runs
130 * SetValue with it.
131 *
132 * @param load String of the input data.
133 */
134 virtual void LoadString(const std::string& load) = 0;
135
136 /**
137 * Returns a string representation of the data. If the data is an enum, it returns a string of
138 * the enum value. If the internal data type is not an enum, this is equivalent to ToString.
139 *
140 * e.g. renderer_backend.Canonicalize() == "OpenGL"
141 *
142 * @returns Canonicalized string representation of the internal data
143 */
144 [[nodiscard]] virtual std::string Canonicalize() const = 0;
145
146 /*
147 * Metadata
148 */
149
150 /**
151 * @returns A unique identifier for the Setting's internal data type.
152 */
153 [[nodiscard]] virtual std::type_index TypeId() const = 0;
154
155 /**
156 * Returns true if the Setting's internal data type is an enum.
157 *
158 * @returns True if the Setting's internal data type is an enum
159 */
160 [[nodiscard]] virtual constexpr bool IsEnum() const = 0;
161
162 /**
163 * Returns true if the current setting is Switchable.
164 *
165 * @returns If the setting is a SwitchableSetting
166 */
167 [[nodiscard]] virtual constexpr bool Switchable() const {
168 return false;
169 }
170
171 /**
172 * Returns true to suggest that a frontend can read or write the setting to a configuration
173 * file.
174 *
175 * @returns The save preference
176 */
177 [[nodiscard]] bool Save() const;
178
179 /**
180 * @returns true if the current setting can be changed while the guest is running.
181 */
182 [[nodiscard]] bool RuntimeModfiable() const;
183
184 /**
185 * @returns A unique number corresponding to the setting.
186 */
187 [[nodiscard]] constexpr u32 Id() const {
188 return id;
189 }
190
191 /**
192 * Returns the setting's category AKA INI group.
193 *
194 * @returns The setting's category
195 */
196 [[nodiscard]] Category GetCategory() const;
197
198 /**
199 * @returns Extra metadata for data representation in frontend implementations.
200 */
201 [[nodiscard]] u32 Specialization() const;
202
203 /**
204 * @returns Another BasicSetting if one is paired, or nullptr otherwise.
205 */
206 [[nodiscard]] BasicSetting* PairedSetting() const;
207
208 /**
209 * Returns the label this setting was created with.
210 *
211 * @returns A reference to the label
212 */
213 [[nodiscard]] const std::string& GetLabel() const;
214
215 /**
216 * @returns If the Setting checks input values for valid ranges.
217 */
218 [[nodiscard]] virtual constexpr bool Ranged() const = 0;
219
220 /**
221 * @returns The index of the enum if the underlying setting type is an enum, else max of u32.
222 */
223 [[nodiscard]] virtual constexpr u32 EnumIndex() const = 0;
224
225 /*
226 * Switchable settings
227 */
228
229 /**
230 * Sets a setting's global state. True means use the normal setting, false to use a custom
231 * value. Has no effect if the Setting is not Switchable.
232 *
233 * @param global The desired state
234 */
235 virtual void SetGlobal(bool global);
236
237 /**
238 * Returns true if the setting is using the normal setting value. Always true if the setting is
239 * not Switchable.
240 *
241 * @returns The Setting's global state
242 */
243 [[nodiscard]] virtual bool UsingGlobal() const;
244
245private:
246 const std::string label; ///< The setting's label
247 const Category category; ///< The setting's category AKA INI group
248 const u32 id; ///< Unique integer for the setting
249 const bool save; ///< Suggests if the setting should be saved and read to a frontend config
250 const bool
251 runtime_modifiable; ///< Suggests if the setting can be modified while a guest is running
252 const u32 specialization; ///< Extra data to identify representation of a setting
253 BasicSetting* const other_setting; ///< A paired setting
254};
255
256} // namespace Settings
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
new file mode 100644
index 000000000..a1a29ebf6
--- /dev/null
+++ b/src/common/settings_enums.h
@@ -0,0 +1,214 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <string>
7#include <utility>
8#include <vector>
9#include "common/common_types.h"
10
11namespace Settings {
12
13template <typename T>
14struct EnumMetadata {
15 static constexpr std::vector<std::pair<std::string, T>> Canonicalizations();
16 static constexpr u32 Index();
17};
18
19#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
20#define PAIR_44(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_45(N, __VA_ARGS__))
21#define PAIR_43(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_44(N, __VA_ARGS__))
22#define PAIR_42(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_43(N, __VA_ARGS__))
23#define PAIR_41(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_42(N, __VA_ARGS__))
24#define PAIR_40(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_41(N, __VA_ARGS__))
25#define PAIR_39(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_40(N, __VA_ARGS__))
26#define PAIR_38(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_39(N, __VA_ARGS__))
27#define PAIR_37(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_38(N, __VA_ARGS__))
28#define PAIR_36(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_37(N, __VA_ARGS__))
29#define PAIR_35(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_36(N, __VA_ARGS__))
30#define PAIR_34(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_35(N, __VA_ARGS__))
31#define PAIR_33(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_34(N, __VA_ARGS__))
32#define PAIR_32(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_33(N, __VA_ARGS__))
33#define PAIR_31(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_32(N, __VA_ARGS__))
34#define PAIR_30(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_31(N, __VA_ARGS__))
35#define PAIR_29(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_30(N, __VA_ARGS__))
36#define PAIR_28(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_29(N, __VA_ARGS__))
37#define PAIR_27(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_28(N, __VA_ARGS__))
38#define PAIR_26(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_27(N, __VA_ARGS__))
39#define PAIR_25(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_26(N, __VA_ARGS__))
40#define PAIR_24(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_25(N, __VA_ARGS__))
41#define PAIR_23(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_24(N, __VA_ARGS__))
42#define PAIR_22(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_23(N, __VA_ARGS__))
43#define PAIR_21(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_22(N, __VA_ARGS__))
44#define PAIR_20(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_21(N, __VA_ARGS__))
45#define PAIR_19(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_20(N, __VA_ARGS__))
46#define PAIR_18(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_19(N, __VA_ARGS__))
47#define PAIR_17(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_18(N, __VA_ARGS__))
48#define PAIR_16(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_17(N, __VA_ARGS__))
49#define PAIR_15(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_16(N, __VA_ARGS__))
50#define PAIR_14(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_15(N, __VA_ARGS__))
51#define PAIR_13(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_14(N, __VA_ARGS__))
52#define PAIR_12(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_13(N, __VA_ARGS__))
53#define PAIR_11(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_12(N, __VA_ARGS__))
54#define PAIR_10(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_11(N, __VA_ARGS__))
55#define PAIR_9(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_10(N, __VA_ARGS__))
56#define PAIR_8(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_9(N, __VA_ARGS__))
57#define PAIR_7(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_8(N, __VA_ARGS__))
58#define PAIR_6(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_7(N, __VA_ARGS__))
59#define PAIR_5(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_6(N, __VA_ARGS__))
60#define PAIR_4(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_5(N, __VA_ARGS__))
61#define PAIR_3(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_4(N, __VA_ARGS__))
62#define PAIR_2(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_3(N, __VA_ARGS__))
63#define PAIR_1(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_2(N, __VA_ARGS__))
64#define PAIR(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_1(N, __VA_ARGS__))
65
66#define ENUM(NAME, ...) \
67 enum class NAME : u32 { __VA_ARGS__ }; \
68 template <> \
69 constexpr std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
70 return {PAIR(NAME, __VA_ARGS__)}; \
71 } \
72 template <> \
73 constexpr u32 EnumMetadata<NAME>::Index() { \
74 return __COUNTER__; \
75 }
76
77// AudioEngine must be specified discretely due to having existing but slightly different
78// canonicalizations
79// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
80enum class AudioEngine : u32 {
81 Auto,
82 Cubeb,
83 Sdl2,
84 Null,
85};
86
87template <>
88constexpr std::vector<std::pair<std::string, AudioEngine>>
89EnumMetadata<AudioEngine>::Canonicalizations() {
90 return {
91 {"auto", AudioEngine::Auto},
92 {"cubeb", AudioEngine::Cubeb},
93 {"sdl2", AudioEngine::Sdl2},
94 {"null", AudioEngine::Null},
95 };
96}
97
98template <>
99constexpr u32 EnumMetadata<AudioEngine>::Index() {
100 // This is just a sufficiently large number that is more than the number of other enums declared
101 // here
102 return 100;
103}
104
105ENUM(AudioMode, Mono, Stereo, Surround);
106
107ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
108 Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
109 ChineseSimplified, ChineseTraditional, PortugueseBrazilian);
110
111ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
112
113ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt,
114 GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
115 Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
116 Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
117
118ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
119
120ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
121
122ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
123
124ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
125
126ENUM(RendererBackend, OpenGL, Vulkan, Null);
127
128ENUM(ShaderBackend, Glsl, Glasm, SpirV);
129
130ENUM(GpuAccuracy, Normal, High, Extreme);
131
132ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
133
134ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
135
136ENUM(FullscreenMode, Borderless, Exclusive);
137
138ENUM(NvdecEmulation, Off, Cpu, Gpu);
139
140ENUM(ResolutionSetup, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X,
141 Res8X);
142
143ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, MaxEnum);
144
145ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
146
147ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
148
149template <typename Type>
150constexpr std::string CanonicalizeEnum(Type id) {
151 const auto group = EnumMetadata<Type>::Canonicalizations();
152 for (auto& [name, value] : group) {
153 if (value == id) {
154 return name;
155 }
156 }
157 return "unknown";
158}
159
160template <typename Type>
161constexpr Type ToEnum(const std::string& canonicalization) {
162 const auto group = EnumMetadata<Type>::Canonicalizations();
163 for (auto& [name, value] : group) {
164 if (name == canonicalization) {
165 return value;
166 }
167 }
168 return {};
169}
170} // namespace Settings
171
172#undef ENUM
173#undef PAIR
174#undef PAIR_1
175#undef PAIR_2
176#undef PAIR_3
177#undef PAIR_4
178#undef PAIR_5
179#undef PAIR_6
180#undef PAIR_7
181#undef PAIR_8
182#undef PAIR_9
183#undef PAIR_10
184#undef PAIR_12
185#undef PAIR_13
186#undef PAIR_14
187#undef PAIR_15
188#undef PAIR_16
189#undef PAIR_17
190#undef PAIR_18
191#undef PAIR_19
192#undef PAIR_20
193#undef PAIR_22
194#undef PAIR_23
195#undef PAIR_24
196#undef PAIR_25
197#undef PAIR_26
198#undef PAIR_27
199#undef PAIR_28
200#undef PAIR_29
201#undef PAIR_30
202#undef PAIR_32
203#undef PAIR_33
204#undef PAIR_34
205#undef PAIR_35
206#undef PAIR_36
207#undef PAIR_37
208#undef PAIR_38
209#undef PAIR_39
210#undef PAIR_40
211#undef PAIR_42
212#undef PAIR_43
213#undef PAIR_44
214#undef PAIR_45
diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h
new file mode 100644
index 000000000..a8beb06e9
--- /dev/null
+++ b/src/common/settings_setting.h
@@ -0,0 +1,394 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <limits>
7#include <map>
8#include <optional>
9#include <stdexcept>
10#include <string>
11#include <typeindex>
12#include <typeinfo>
13#include "common/common_types.h"
14#include "common/settings_common.h"
15#include "common/settings_enums.h"
16
17namespace Settings {
18
19/** The Setting class is a simple resource manager. It defines a label and default value
20 * alongside the actual value of the setting for simpler and less-error prone use with frontend
21 * configurations. Specifying a default value and label is required. A minimum and maximum range
22 * can be specified for sanitization.
23 */
24template <typename Type, bool ranged = false>
25class Setting : public BasicSetting {
26protected:
27 Setting() = default;
28
29public:
30 /**
31 * Sets a default value, label, and setting value.
32 *
33 * @param linkage Setting registry
34 * @param default_val Initial value of the setting, and default value of the setting
35 * @param name Label for the setting
36 * @param category_ Category of the setting AKA INI group
37 * @param specialization_ Suggestion for how frontend implementations represent this in a config
38 * @param save_ Suggests that this should or should not be saved to a frontend config file
39 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
40 * @param other_setting_ A second Setting to associate to this one in metadata
41 */
42 explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
43 Category category_, u32 specialization_ = Specialization::Default,
44 bool save_ = true, bool runtime_modifiable_ = false,
45 BasicSetting* other_setting_ = nullptr)
46 requires(!ranged)
47 : BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
48 other_setting_),
49 value{default_val}, default_value{default_val} {}
50 virtual ~Setting() = default;
51
52 /**
53 * Sets a default value, minimum value, maximum value, and label.
54 *
55 * @param linkage Setting registry
56 * @param default_val Initial value of the setting, and default value of the setting
57 * @param min_val Sets the minimum allowed value of the setting
58 * @param max_val Sets the maximum allowed value of the setting
59 * @param name Label for the setting
60 * @param category_ Category of the setting AKA INI group
61 * @param specialization_ Suggestion for how frontend implementations represent this in a config
62 * @param save_ Suggests that this should or should not be saved to a frontend config file
63 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
64 * @param other_setting_ A second Setting to associate to this one in metadata
65 */
66 explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
67 const Type& max_val, const std::string& name, Category category_,
68 u32 specialization_ = Specialization::Default, bool save_ = true,
69 bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
70 requires(ranged)
71 : BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
72 other_setting_),
73 value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val} {}
74
75 /**
76 * Returns a reference to the setting's value.
77 *
78 * @returns A reference to the setting
79 */
80 [[nodiscard]] virtual const Type& GetValue() const {
81 return value;
82 }
83
84 /**
85 * Sets the setting to the given value.
86 *
87 * @param val The desired value
88 */
89 virtual void SetValue(const Type& val) {
90 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
91 std::swap(value, temp);
92 }
93
94 /**
95 * Returns the value that this setting was created with.
96 *
97 * @returns A reference to the default value
98 */
99 [[nodiscard]] const Type& GetDefault() const {
100 return default_value;
101 }
102
103 [[nodiscard]] constexpr bool IsEnum() const override {
104 return std::is_enum_v<Type>;
105 }
106
107protected:
108 [[nodiscard]] std::string ToString(const Type& value_) const {
109 if constexpr (std::is_same_v<Type, std::string>) {
110 return value_;
111 } else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
112 return value_.has_value() ? std::to_string(*value_) : "none";
113 } else if constexpr (std::is_same_v<Type, bool>) {
114 return value_ ? "true" : "false";
115 } else if constexpr (std::is_same_v<Type, AudioEngine>) {
116 // Compatibility with old AudioEngine setting being a string
117 return CanonicalizeEnum(value_);
118 } else {
119 return std::to_string(static_cast<u64>(value_));
120 }
121 }
122
123public:
124 /**
125 * Converts the value of the setting to a std::string. Respects the global state if the setting
126 * has one.
127 *
128 * @returns The current setting as a std::string
129 */
130 [[nodiscard]] std::string ToString() const override {
131 return ToString(this->GetValue());
132 }
133
134 /**
135 * Returns the default value of the setting as a std::string.
136 *
137 * @returns The default value as a string.
138 */
139 [[nodiscard]] std::string DefaultToString() const override {
140 return ToString(default_value);
141 }
142
143 /**
144 * Assigns a value to the setting.
145 *
146 * @param val The desired setting value
147 *
148 * @returns A reference to the setting
149 */
150 virtual const Type& operator=(const Type& val) {
151 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
152 std::swap(value, temp);
153 return value;
154 }
155
156 /**
157 * Returns a reference to the setting.
158 *
159 * @returns A reference to the setting
160 */
161 explicit virtual operator const Type&() const {
162 return value;
163 }
164
165 /**
166 * Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
167 * thus respecting its constraints.
168 *
169 * @param input The desired value
170 */
171 void LoadString(const std::string& input) override final {
172 if (input.empty()) {
173 this->SetValue(this->GetDefault());
174 return;
175 }
176 try {
177 if constexpr (std::is_same_v<Type, std::string>) {
178 this->SetValue(input);
179 } else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
180 this->SetValue(static_cast<u32>(std::stoul(input)));
181 } else if constexpr (std::is_same_v<Type, bool>) {
182 this->SetValue(input == "true");
183 } else if constexpr (std::is_same_v<Type, AudioEngine>) {
184 this->SetValue(ToEnum<Type>(input));
185 } else {
186 this->SetValue(static_cast<Type>(std::stoll(input)));
187 }
188 } catch (std::invalid_argument&) {
189 this->SetValue(this->GetDefault());
190 }
191 }
192
193 [[nodiscard]] std::string constexpr Canonicalize() const override final {
194 if constexpr (std::is_enum_v<Type>) {
195 return CanonicalizeEnum(this->GetValue());
196 } else {
197 return ToString(this->GetValue());
198 }
199 }
200
201 /**
202 * Gives us another way to identify the setting without having to go through a string.
203 *
204 * @returns the type_index of the setting's type
205 */
206 [[nodiscard]] std::type_index TypeId() const override final {
207 return std::type_index(typeid(Type));
208 }
209
210 [[nodiscard]] constexpr u32 EnumIndex() const override final {
211 if constexpr (std::is_enum_v<Type>) {
212 return EnumMetadata<Type>::Index();
213 } else {
214 return std::numeric_limits<u32>::max();
215 }
216 }
217
218 [[nodiscard]] std::string MinVal() const override final {
219 return this->ToString(minimum);
220 }
221 [[nodiscard]] std::string MaxVal() const override final {
222 return this->ToString(maximum);
223 }
224
225 [[nodiscard]] constexpr bool Ranged() const override {
226 return ranged;
227 }
228
229protected:
230 Type value{}; ///< The setting
231 const Type default_value{}; ///< The default value
232 const Type maximum{}; ///< Maximum allowed value of the setting
233 const Type minimum{}; ///< Minimum allowed value of the setting
234};
235
236/**
237 * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
238 * custom setting to switch to when a guest application specifically requires it. The effect is that
239 * other components of the emulator can access the setting's intended value without any need for the
240 * component to ask whether the custom or global setting is needed at the moment.
241 *
242 * By default, the global setting is used.
243 */
244template <typename Type, bool ranged = false>
245class SwitchableSetting : virtual public Setting<Type, ranged> {
246public:
247 /**
248 * Sets a default value, label, and setting value.
249 *
250 * @param linkage Setting registry
251 * @param default_val Initial value of the setting, and default value of the setting
252 * @param name Label for the setting
253 * @param category_ Category of the setting AKA INI group
254 * @param specialization_ Suggestion for how frontend implementations represent this in a config
255 * @param save_ Suggests that this should or should not be saved to a frontend config file
256 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
257 * @param other_setting_ A second Setting to associate to this one in metadata
258 */
259 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
260 Category category_, u32 specialization_ = Specialization::Default,
261 bool save_ = true, bool runtime_modifiable_ = false,
262 BasicSetting* other_setting_ = nullptr)
263 requires(!ranged)
264 : Setting<Type, false>{
265 linkage, default_val, name, category_, specialization_,
266 save_, runtime_modifiable_, other_setting_} {
267 linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
268 }
269 virtual ~SwitchableSetting() = default;
270
271 /**
272 * Sets a default value, minimum value, maximum value, and label.
273 *
274 * @param linkage Setting registry
275 * @param default_val Initial value of the setting, and default value of the setting
276 * @param min_val Sets the minimum allowed value of the setting
277 * @param max_val Sets the maximum allowed value of the setting
278 * @param name Label for the setting
279 * @param category_ Category of the setting AKA INI group
280 * @param specialization_ Suggestion for how frontend implementations represent this in a config
281 * @param save_ Suggests that this should or should not be saved to a frontend config file
282 * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
283 * @param other_setting_ A second Setting to associate to this one in metadata
284 */
285 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
286 const Type& max_val, const std::string& name, Category category_,
287 u32 specialization_ = Specialization::Default, bool save_ = true,
288 bool runtime_modifiable_ = false,
289 BasicSetting* other_setting_ = nullptr)
290 requires(ranged)
291 : Setting<Type, true>{linkage, default_val, min_val,
292 max_val, name, category_,
293 specialization_, save_, runtime_modifiable_,
294 other_setting_} {
295 linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
296 }
297
298 /**
299 * Tells this setting to represent either the global or custom setting when other member
300 * functions are used.
301 *
302 * @param to_global Whether to use the global or custom setting.
303 */
304 void SetGlobal(bool to_global) override final {
305 use_global = to_global;
306 }
307
308 /**
309 * Returns whether this setting is using the global setting or not.
310 *
311 * @returns The global state
312 */
313 [[nodiscard]] bool UsingGlobal() const override final {
314 return use_global;
315 }
316
317 /**
318 * Returns either the global or custom setting depending on the values of this setting's global
319 * state or if the global value was specifically requested.
320 *
321 * @param need_global Request global value regardless of setting's state; defaults to false
322 *
323 * @returns The required value of the setting
324 */
325 [[nodiscard]] const Type& GetValue() const override final {
326 if (use_global) {
327 return this->value;
328 }
329 return custom;
330 }
331 [[nodiscard]] const Type& GetValue(bool need_global) const {
332 if (use_global || need_global) {
333 return this->value;
334 }
335 return custom;
336 }
337
338 /**
339 * Sets the current setting value depending on the global state.
340 *
341 * @param val The new value
342 */
343 void SetValue(const Type& val) override final {
344 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
345 if (use_global) {
346 std::swap(this->value, temp);
347 } else {
348 std::swap(custom, temp);
349 }
350 }
351
352 [[nodiscard]] constexpr bool Switchable() const override final {
353 return true;
354 }
355
356 [[nodiscard]] std::string ToStringGlobal() const override final {
357 return this->ToString(this->value);
358 }
359
360 /**
361 * Assigns the current setting value depending on the global state.
362 *
363 * @param val The new value
364 *
365 * @returns A reference to the current setting value
366 */
367 const Type& operator=(const Type& val) override final {
368 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
369 if (use_global) {
370 std::swap(this->value, temp);
371 return this->value;
372 }
373 std::swap(custom, temp);
374 return custom;
375 }
376
377 /**
378 * Returns the current setting value depending on the global state.
379 *
380 * @returns A reference to the current setting value
381 */
382 explicit operator const Type&() const override final {
383 if (use_global) {
384 return this->value;
385 }
386 return custom;
387 }
388
389protected:
390 bool use_global{true}; ///< The setting's global state
391 Type custom{}; ///< The custom value of the setting
392};
393
394} // namespace Settings