summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_out.cpp3
-rw-r--r--src/audio_core/command_generator.cpp64
-rw-r--r--src/audio_core/command_generator.h5
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/settings.cpp18
-rw-r--r--src/common/settings.h419
-rw-r--r--src/common/thread_worker.cpp58
-rw-r--r--src/common/thread_worker.h102
-rw-r--r--src/common/unique_function.h62
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp18
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp18
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/core/frontend/applets/profile_select.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp3
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/bcat/module.cpp2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp6
-rw-r--r--src/core/hle/service/set/set.cpp2
-rw-r--r--src/core/loader/nro.cpp4
-rw-r--r--src/core/loader/nso.cpp4
-rw-r--r--src/core/reporter.cpp2
-rw-r--r--src/core/telemetry_session.cpp10
-rw-r--r--src/input_common/mouse/mouse_poller.cpp3
-rw-r--r--src/input_common/touch_from_button.cpp2
-rw-r--r--src/input_common/udp/client.cpp4
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/common/unique_function.cpp108
-rw-r--r--src/tests/video_core/buffer_base.cpp2
-rw-r--r--src/video_core/buffer_cache/buffer_base.h19
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h292
-rw-r--r--src/video_core/dma_pusher.cpp10
-rw-r--r--src/video_core/engines/fermi_2d.cpp22
-rw-r--r--src/video_core/engines/maxwell_dma.cpp36
-rw-r--r--src/video_core/engines/maxwell_dma.h17
-rw-r--r--src/video_core/fence_manager.h7
-rw-r--r--src/video_core/gpu.cpp5
-rw-r--r--src/video_core/rasterizer_interface.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp21
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h14
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp21
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h14
-rw-r--r--src/video_core/texture_cache/texture_cache.h71
-rw-r--r--src/video_core/texture_cache/types.h4
-rw-r--r--src/yuzu/CMakeLists.txt3
-rw-r--r--src/yuzu/configuration/config.cpp734
-rw-r--r--src/yuzu/configuration/config.h75
-rw-r--r--src/yuzu/configuration/configure.ui50
-rw-r--r--src/yuzu/configuration/configure_audio.cpp8
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp18
-rw-r--r--src/yuzu/configuration/configure_cpu.h1
-rw-r--r--src/yuzu/configuration/configure_cpu.ui14
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.cpp21
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.h1
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.ui94
-rw-r--r--src/yuzu/configuration/configure_debug.cpp28
-rw-r--r--src/yuzu/configuration/configure_debug.ui63
-rw-r--r--src/yuzu/configuration/configure_debug_tab.cpp38
-rw-r--r--src/yuzu/configuration/configure_debug_tab.h32
-rw-r--r--src/yuzu/configuration/configure_debug_tab.ui52
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp6
-rw-r--r--src/yuzu/configuration/configure_filesystem.cpp13
-rw-r--r--src/yuzu/configuration/configure_general.cpp8
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp6
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h1
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui18
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp12
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp11
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp11
-rw-r--r--src/yuzu/configuration/configure_service.cpp2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp11
-rw-r--r--src/yuzu/configuration/configure_web.cpp12
-rw-r--r--src/yuzu/debugger/console.cpp4
-rw-r--r--src/yuzu/game_list.cpp3
-rw-r--r--src/yuzu/game_list_p.h15
-rw-r--r--src/yuzu/main.cpp52
-rw-r--r--src/yuzu/uisettings.h43
-rw-r--r--src/yuzu_cmd/config.cpp196
-rw-r--r--src/yuzu_cmd/config.h12
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
80 files changed, 1970 insertions, 1195 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index 20a756dce..44a899d08 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
30 u32 num_channels, std::string&& name, 30 u32 num_channels, std::string&& name,
31 Stream::ReleaseCallback&& release_callback) { 31 Stream::ReleaseCallback&& release_callback) {
32 if (!sink) { 32 if (!sink) {
33 sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id); 33 sink = CreateSinkFromID(Settings::values.sink_id.GetValue(),
34 Settings::values.audio_device_id.GetValue());
34 } 35 }
35 36
36 return std::make_shared<Stream>( 37 return std::make_shared<Stream>(
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index 02c6e6f6a..45b2eef52 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -412,7 +412,10 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
412 } 412 }
413 } else { 413 } else {
414 switch (in_params.sample_format) { 414 switch (in_params.sample_format) {
415 case SampleFormat::Pcm8:
415 case SampleFormat::Pcm16: 416 case SampleFormat::Pcm16:
417 case SampleFormat::Pcm32:
418 case SampleFormat::PcmFloat:
416 DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel, 419 DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel,
417 worker_params.sample_rate, worker_params.sample_count, 420 worker_params.sample_rate, worker_params.sample_count,
418 in_params.node_id); 421 in_params.node_id);
@@ -1018,9 +1021,10 @@ void CommandGenerator::GenerateFinalMixCommand() {
1018 } 1021 }
1019} 1022}
1020 1023
1021s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, 1024template <typename T>
1022 s32 sample_start_offset, s32 sample_end_offset, s32 sample_count, 1025s32 CommandGenerator::DecodePcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
1023 s32 channel, std::size_t mix_offset) { 1026 s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
1027 s32 channel, std::size_t mix_offset) {
1024 const auto& in_params = voice_info.GetInParams(); 1028 const auto& in_params = voice_info.GetInParams();
1025 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; 1029 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
1026 if (wave_buffer.buffer_address == 0) { 1030 if (wave_buffer.buffer_address == 0) {
@@ -1034,24 +1038,37 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
1034 } 1038 }
1035 const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset; 1039 const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset;
1036 const auto start_offset = 1040 const auto start_offset =
1037 ((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(s16); 1041 ((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(T);
1038 const auto buffer_pos = wave_buffer.buffer_address + start_offset; 1042 const auto buffer_pos = wave_buffer.buffer_address + start_offset;
1039 const auto samples_processed = std::min(sample_count, samples_remaining); 1043 const auto samples_processed = std::min(sample_count, samples_remaining);
1040 1044
1041 if (in_params.channel_count == 1) { 1045 const auto channel_count = in_params.channel_count;
1042 std::vector<s16> buffer(samples_processed); 1046 std::vector<T> buffer(samples_processed * channel_count);
1043 memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16)); 1047 memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(T));
1044 for (std::size_t i = 0; i < buffer.size(); i++) {
1045 sample_buffer[mix_offset + i] = buffer[i];
1046 }
1047 } else {
1048 const auto channel_count = in_params.channel_count;
1049 std::vector<s16> buffer(samples_processed * channel_count);
1050 memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
1051 1048
1049 if constexpr (std::is_floating_point_v<T>) {
1050 for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
1051 sample_buffer[mix_offset + i] = static_cast<s32>(buffer[i * channel_count + channel] *
1052 std::numeric_limits<s16>::max());
1053 }
1054 } else if constexpr (sizeof(T) == 1) {
1055 for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
1056 sample_buffer[mix_offset + i] =
1057 static_cast<s32>(static_cast<f32>(buffer[i * channel_count + channel] /
1058 std::numeric_limits<s8>::max()) *
1059 std::numeric_limits<s16>::max());
1060 }
1061 } else if constexpr (sizeof(T) == 2) {
1052 for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) { 1062 for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
1053 sample_buffer[mix_offset + i] = buffer[i * channel_count + channel]; 1063 sample_buffer[mix_offset + i] = buffer[i * channel_count + channel];
1054 } 1064 }
1065 } else {
1066 for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
1067 sample_buffer[mix_offset + i] =
1068 static_cast<s32>(static_cast<f32>(buffer[i * channel_count + channel] /
1069 std::numeric_limits<s32>::max()) *
1070 std::numeric_limits<s16>::max());
1071 }
1055 } 1072 }
1056 1073
1057 return samples_processed; 1074 return samples_processed;
@@ -1267,10 +1284,25 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::s
1267 1284
1268 s32 samples_decoded{0}; 1285 s32 samples_decoded{0};
1269 switch (in_params.sample_format) { 1286 switch (in_params.sample_format) {
1287 case SampleFormat::Pcm8:
1288 samples_decoded =
1289 DecodePcm<s8>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
1290 samples_to_read - samples_read, channel, temp_mix_offset);
1291 break;
1270 case SampleFormat::Pcm16: 1292 case SampleFormat::Pcm16:
1271 samples_decoded = 1293 samples_decoded =
1272 DecodePcm16(voice_info, dsp_state, samples_offset_start, samples_offset_end, 1294 DecodePcm<s16>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
1273 samples_to_read - samples_read, channel, temp_mix_offset); 1295 samples_to_read - samples_read, channel, temp_mix_offset);
1296 break;
1297 case SampleFormat::Pcm32:
1298 samples_decoded =
1299 DecodePcm<s32>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
1300 samples_to_read - samples_read, channel, temp_mix_offset);
1301 break;
1302 case SampleFormat::PcmFloat:
1303 samples_decoded =
1304 DecodePcm<f32>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
1305 samples_to_read - samples_read, channel, temp_mix_offset);
1274 break; 1306 break;
1275 case SampleFormat::Adpcm: 1307 case SampleFormat::Adpcm:
1276 samples_decoded = 1308 samples_decoded =
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index ac034b0a5..59a33ba76 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -88,8 +88,9 @@ private:
88 std::vector<u8>& work_buffer); 88 std::vector<u8>& work_buffer);
89 void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear); 89 void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear);
90 // DSP Code 90 // DSP Code
91 s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset, 91 template <typename T>
92 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset); 92 s32 DecodePcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
93 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
93 s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset, 94 s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
94 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset); 95 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
95 void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::span<s32> output, 96 void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::span<s32> output,
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index a6fa9a85d..e03fffd8d 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -180,7 +180,6 @@ add_library(common STATIC
180 thread.cpp 180 thread.cpp
181 thread.h 181 thread.h
182 thread_queue_list.h 182 thread_queue_list.h
183 thread_worker.cpp
184 thread_worker.h 183 thread_worker.h
185 threadsafe_queue.h 184 threadsafe_queue.h
186 time_zone.cpp 185 time_zone.cpp
@@ -188,6 +187,7 @@ add_library(common STATIC
188 tiny_mt.h 187 tiny_mt.h
189 tree.h 188 tree.h
190 uint128.h 189 uint128.h
190 unique_function.h
191 uuid.cpp 191 uuid.cpp
192 uuid.h 192 uuid.h
193 vector_math.h 193 vector_math.h
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index e1bb4b7ff..e1973af85 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -41,7 +41,7 @@ void LogSettings() {
41 LOG_INFO(Config, "yuzu Configuration:"); 41 LOG_INFO(Config, "yuzu Configuration:");
42 log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue()); 42 log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
43 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); 43 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
44 log_setting("System_CurrentUser", values.current_user); 44 log_setting("System_CurrentUser", values.current_user.GetValue());
45 log_setting("System_LanguageIndex", values.language_index.GetValue()); 45 log_setting("System_LanguageIndex", values.language_index.GetValue());
46 log_setting("System_RegionIndex", values.region_index.GetValue()); 46 log_setting("System_RegionIndex", values.region_index.GetValue());
47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
@@ -61,18 +61,18 @@ void LogSettings() {
61 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 61 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
62 log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue()); 62 log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
63 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); 63 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
64 log_setting("Audio_OutputEngine", values.sink_id); 64 log_setting("Audio_OutputEngine", values.sink_id.GetValue());
65 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); 65 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
66 log_setting("Audio_OutputDevice", values.audio_device_id); 66 log_setting("Audio_OutputDevice", values.audio_device_id.GetValue());
67 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); 67 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
68 log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir)); 68 log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
69 log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir)); 69 log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
70 log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir)); 70 log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
71 log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir)); 71 log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
72 log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); 72 log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
73 log_setting("Debugging_ProgramArgs", values.program_args); 73 log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
74 log_setting("Services_BCATBackend", values.bcat_backend); 74 log_setting("Services_BCATBackend", values.bcat_backend.GetValue());
75 log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); 75 log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue());
76} 76}
77 77
78bool IsConfiguringGlobal() { 78bool IsConfiguringGlobal() {
@@ -93,8 +93,8 @@ bool IsGPULevelHigh() {
93} 93}
94 94
95bool IsFastmemEnabled() { 95bool IsFastmemEnabled() {
96 if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) { 96 if (values.cpu_debug_mode) {
97 return values.cpuopt_fastmem; 97 return static_cast<bool>(values.cpuopt_fastmem);
98 } 98 }
99 return true; 99 return true;
100} 100}
diff --git a/src/common/settings.h b/src/common/settings.h
index 82ec18e27..71d0f864f 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -10,10 +10,12 @@
10#include <map> 10#include <map>
11#include <optional> 11#include <optional>
12#include <string> 12#include <string>
13#include <utility>
13#include <vector> 14#include <vector>
14 15
15#include "common/common_types.h" 16#include "common/common_types.h"
16#include "common/settings_input.h" 17#include "common/settings_input.h"
18#include "input_common/udp/client.h"
17 19
18namespace Settings { 20namespace Settings {
19 21
@@ -29,73 +31,240 @@ enum class GPUAccuracy : u32 {
29}; 31};
30 32
31enum class CPUAccuracy : u32 { 33enum class CPUAccuracy : u32 {
32 Accurate = 0, 34 Auto = 0,
33 Unsafe = 1, 35 Accurate = 1,
34 DebugMode = 2, 36 Unsafe = 2,
35}; 37};
36 38
39/** The BasicSetting class is a simple resource manager. It defines a label and default value
40 * alongside the actual value of the setting for simpler and less-error prone use with frontend
41 * configurations. Setting a default value and label is required, though subclasses may deviate from
42 * this requirement.
43 */
44template <typename Type>
45class BasicSetting {
46protected:
47 BasicSetting() = default;
48
49 /**
50 * Only sets the setting to the given initializer, leaving the other members to their default
51 * initializers.
52 *
53 * @param global_val Initial value of the setting
54 */
55 explicit BasicSetting(const Type& global_val) : global{global_val} {}
56
57public:
58 /**
59 * Sets a default value, label, and setting value.
60 *
61 * @param default_val Intial value of the setting, and default value of the setting
62 * @param name Label for the setting
63 */
64 explicit BasicSetting(const Type& default_val, const std::string& name)
65 : default_value{default_val}, global{default_val}, label{name} {}
66 ~BasicSetting() = default;
67
68 /**
69 * Returns a reference to the setting's value.
70 *
71 * @returns A reference to the setting
72 */
73 [[nodiscard]] const Type& GetValue() const {
74 return global;
75 }
76
77 /**
78 * Sets the setting to the given value.
79 *
80 * @param value The desired value
81 */
82 void SetValue(const Type& value) {
83 Type temp{value};
84 std::swap(global, temp);
85 }
86
87 /**
88 * Returns the value that this setting was created with.
89 *
90 * @returns A reference to the default value
91 */
92 [[nodiscard]] const Type& GetDefault() const {
93 return default_value;
94 }
95
96 /**
97 * Returns the label this setting was created with.
98 *
99 * @returns A reference to the label
100 */
101 [[nodiscard]] const std::string& GetLabel() const {
102 return label;
103 }
104
105 /**
106 * Assigns a value to the setting.
107 *
108 * @param value The desired setting value
109 *
110 * @returns A reference to the setting
111 */
112 const Type& operator=(const Type& value) {
113 Type temp{value};
114 std::swap(global, temp);
115 return global;
116 }
117
118 /**
119 * Returns a reference to the setting.
120 *
121 * @returns A reference to the setting
122 */
123 explicit operator const Type&() const {
124 return global;
125 }
126
127protected:
128 const Type default_value{}; ///< The default value
129 Type global{}; ///< The setting
130 const std::string label{}; ///< The setting's label
131};
132
133/**
134 * The Setting class is a slightly more complex version of the BasicSetting class. This adds a
135 * custom setting to switch to when a guest application specifically requires it. The effect is that
136 * other components of the emulator can access the setting's intended value without any need for the
137 * component to ask whether the custom or global setting is needed at the moment.
138 *
139 * By default, the global setting is used.
140 *
141 * Like the BasicSetting, this requires setting a default value and label to use.
142 */
37template <typename Type> 143template <typename Type>
38class Setting final { 144class Setting final : public BasicSetting<Type> {
39public: 145public:
40 Setting() = default; 146 /**
41 explicit Setting(Type val) : global{val} {} 147 * Sets a default value, label, and setting value.
148 *
149 * @param default_val Intial value of the setting, and default value of the setting
150 * @param name Label for the setting
151 */
152 explicit Setting(const Type& default_val, const std::string& name)
153 : BasicSetting<Type>(default_val, name) {}
42 ~Setting() = default; 154 ~Setting() = default;
155
156 /**
157 * Tells this setting to represent either the global or custom setting when other member
158 * functions are used.
159 *
160 * @param to_global Whether to use the global or custom setting.
161 */
43 void SetGlobal(bool to_global) { 162 void SetGlobal(bool to_global) {
44 use_global = to_global; 163 use_global = to_global;
45 } 164 }
46 bool UsingGlobal() const { 165
166 /**
167 * Returns whether this setting is using the global setting or not.
168 *
169 * @returns The global state
170 */
171 [[nodiscard]] bool UsingGlobal() const {
47 return use_global; 172 return use_global;
48 } 173 }
49 Type GetValue(bool need_global = false) const { 174
175 /**
176 * Returns either the global or custom setting depending on the values of this setting's global
177 * state or if the global value was specifically requested.
178 *
179 * @param need_global Request global value regardless of setting's state; defaults to false
180 *
181 * @returns The required value of the setting
182 */
183 [[nodiscard]] const Type& GetValue(bool need_global = false) const {
50 if (use_global || need_global) { 184 if (use_global || need_global) {
51 return global; 185 return this->global;
52 } 186 }
53 return local; 187 return custom;
54 } 188 }
189
190 /**
191 * Sets the current setting value depending on the global state.
192 *
193 * @param value The new value
194 */
55 void SetValue(const Type& value) { 195 void SetValue(const Type& value) {
196 Type temp{value};
56 if (use_global) { 197 if (use_global) {
57 global = value; 198 std::swap(this->global, temp);
58 } else { 199 } else {
59 local = value; 200 std::swap(custom, temp);
201 }
202 }
203
204 /**
205 * Assigns the current setting value depending on the global state.
206 *
207 * @param value The new value
208 *
209 * @returns A reference to the current setting value
210 */
211 const Type& operator=(const Type& value) {
212 Type temp{value};
213 if (use_global) {
214 std::swap(this->global, temp);
215 return this->global;
216 }
217 std::swap(custom, temp);
218 return custom;
219 }
220
221 /**
222 * Returns the current setting value depending on the global state.
223 *
224 * @returns A reference to the current setting value
225 */
226 explicit operator const Type&() const {
227 if (use_global) {
228 return this->global;
60 } 229 }
230 return custom;
61 } 231 }
62 232
63private: 233private:
64 bool use_global = true; 234 bool use_global{true}; ///< The setting's global state
65 Type global{}; 235 Type custom{}; ///< The custom value of the setting
66 Type local{};
67}; 236};
68 237
69/** 238/**
70 * The InputSetting class allows for getting a reference to either the global or local members. 239 * The InputSetting class allows for getting a reference to either the global or custom members.
71 * This is required as we cannot easily modify the values of user-defined types within containers 240 * This is required as we cannot easily modify the values of user-defined types within containers
72 * using the SetValue() member function found in the Setting class. The primary purpose of this 241 * using the SetValue() member function found in the Setting class. The primary purpose of this
73 * class is to store an array of 10 PlayerInput structs for both the global and local (per-game) 242 * class is to store an array of 10 PlayerInput structs for both the global and custom setting and
74 * setting and allows for easily accessing and modifying both settings. 243 * allows for easily accessing and modifying both settings.
75 */ 244 */
76template <typename Type> 245template <typename Type>
77class InputSetting final { 246class InputSetting final {
78public: 247public:
79 InputSetting() = default; 248 InputSetting() = default;
80 explicit InputSetting(Type val) : global{val} {} 249 explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
81 ~InputSetting() = default; 250 ~InputSetting() = default;
82 void SetGlobal(bool to_global) { 251 void SetGlobal(bool to_global) {
83 use_global = to_global; 252 use_global = to_global;
84 } 253 }
85 bool UsingGlobal() const { 254 [[nodiscard]] bool UsingGlobal() const {
86 return use_global; 255 return use_global;
87 } 256 }
88 Type& GetValue(bool need_global = false) { 257 [[nodiscard]] Type& GetValue(bool need_global = false) {
89 if (use_global || need_global) { 258 if (use_global || need_global) {
90 return global; 259 return global;
91 } 260 }
92 return local; 261 return custom;
93 } 262 }
94 263
95private: 264private:
96 bool use_global = true; 265 bool use_global{true}; ///< The setting's global state
97 Type global{}; 266 Type global{}; ///< The setting
98 Type local{}; 267 Type custom{}; ///< The custom setting value
99}; 268};
100 269
101struct TouchFromButtonMap { 270struct TouchFromButtonMap {
@@ -105,144 +274,158 @@ struct TouchFromButtonMap {
105 274
106struct Values { 275struct Values {
107 // Audio 276 // Audio
108 std::string audio_device_id; 277 BasicSetting<std::string> audio_device_id{"auto", "output_device"};
109 std::string sink_id; 278 BasicSetting<std::string> sink_id{"auto", "output_engine"};
110 bool audio_muted; 279 BasicSetting<bool> audio_muted{false, "audio_muted"};
111 Setting<bool> enable_audio_stretching; 280 Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
112 Setting<float> volume; 281 Setting<float> volume{1.0f, "volume"};
113 282
114 // Core 283 // Core
115 Setting<bool> use_multi_core; 284 Setting<bool> use_multi_core{true, "use_multi_core"};
116 285
117 // Cpu 286 // Cpu
118 Setting<CPUAccuracy> cpu_accuracy; 287 Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, "cpu_accuracy"};
119 288 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
120 bool cpuopt_page_tables; 289 BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
121 bool cpuopt_block_linking; 290 BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
122 bool cpuopt_return_stack_buffer; 291
123 bool cpuopt_fast_dispatcher; 292 BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
124 bool cpuopt_context_elimination; 293 BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
125 bool cpuopt_const_prop; 294 BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
126 bool cpuopt_misc_ir; 295 BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
127 bool cpuopt_reduce_misalign_checks; 296 BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
128 bool cpuopt_fastmem; 297 BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
129 298 BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
130 Setting<bool> cpuopt_unsafe_unfuse_fma; 299 BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
131 Setting<bool> cpuopt_unsafe_reduce_fp_error; 300 BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
132 Setting<bool> cpuopt_unsafe_ignore_standard_fpcr; 301
133 Setting<bool> cpuopt_unsafe_inaccurate_nan; 302 Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
134 Setting<bool> cpuopt_unsafe_fastmem_check; 303 Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
304 Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
305 Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
306 Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
135 307
136 // Renderer 308 // Renderer
137 Setting<RendererBackend> renderer_backend; 309 Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
138 bool renderer_debug; 310 BasicSetting<bool> renderer_debug{false, "debug"};
139 Setting<int> vulkan_device; 311 Setting<int> vulkan_device{0, "vulkan_device"};
140 312
141 Setting<u16> resolution_factor{1}; 313 Setting<u16> resolution_factor{1, "resolution_factor"};
142 Setting<int> fullscreen_mode; 314 // *nix platforms may have issues with the borderless windowed fullscreen mode.
143 Setting<int> aspect_ratio; 315 // Default to exclusive fullscreen on these platforms for now.
144 Setting<int> max_anisotropy; 316 Setting<int> fullscreen_mode{
145 Setting<bool> use_frame_limit; 317#ifdef _WIN32
146 Setting<u16> frame_limit; 318 0,
147 Setting<bool> use_disk_shader_cache; 319#else
148 Setting<GPUAccuracy> gpu_accuracy; 320 1,
149 Setting<bool> use_asynchronous_gpu_emulation; 321#endif
150 Setting<bool> use_nvdec_emulation; 322 "fullscreen_mode"};
151 Setting<bool> accelerate_astc; 323 Setting<int> aspect_ratio{0, "aspect_ratio"};
152 Setting<bool> use_vsync; 324 Setting<int> max_anisotropy{0, "max_anisotropy"};
153 Setting<bool> disable_fps_limit; 325 Setting<bool> use_frame_limit{true, "use_frame_limit"};
154 Setting<bool> use_assembly_shaders; 326 Setting<u16> frame_limit{100, "frame_limit"};
155 Setting<bool> use_asynchronous_shaders; 327 Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
156 Setting<bool> use_fast_gpu_time; 328 Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
157 Setting<bool> use_caches_gc; 329 Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
158 330 Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
159 Setting<float> bg_red; 331 Setting<bool> accelerate_astc{true, "accelerate_astc"};
160 Setting<float> bg_green; 332 Setting<bool> use_vsync{true, "use_vsync"};
161 Setting<float> bg_blue; 333 BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
334 Setting<bool> use_assembly_shaders{false, "use_assembly_shaders"};
335 Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
336 Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
337 Setting<bool> use_caches_gc{false, "use_caches_gc"};
338
339 Setting<float> bg_red{0.0f, "bg_red"};
340 Setting<float> bg_green{0.0f, "bg_green"};
341 Setting<float> bg_blue{0.0f, "bg_blue"};
162 342
163 // System 343 // System
164 Setting<std::optional<u32>> rng_seed; 344 Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
165 // Measured in seconds since epoch 345 // Measured in seconds since epoch
166 std::optional<std::chrono::seconds> custom_rtc; 346 std::optional<std::chrono::seconds> custom_rtc;
167 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 347 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
168 std::chrono::seconds custom_rtc_differential; 348 std::chrono::seconds custom_rtc_differential;
169 349
170 s32 current_user; 350 BasicSetting<s32> current_user{0, "current_user"};
171 Setting<s32> language_index; 351 Setting<s32> language_index{1, "language_index"};
172 Setting<s32> region_index; 352 Setting<s32> region_index{1, "region_index"};
173 Setting<s32> time_zone_index; 353 Setting<s32> time_zone_index{0, "time_zone_index"};
174 Setting<s32> sound_index; 354 Setting<s32> sound_index{1, "sound_index"};
175 355
176 // Controls 356 // Controls
177 InputSetting<std::array<PlayerInput, 10>> players; 357 InputSetting<std::array<PlayerInput, 10>> players;
178 358
179 Setting<bool> use_docked_mode; 359 Setting<bool> use_docked_mode{true, "use_docked_mode"};
180 360
181 Setting<bool> vibration_enabled; 361 Setting<bool> vibration_enabled{true, "vibration_enabled"};
182 Setting<bool> enable_accurate_vibrations; 362 Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
183 363
184 Setting<bool> motion_enabled; 364 Setting<bool> motion_enabled{true, "motion_enabled"};
185 std::string motion_device; 365 BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
186 std::string udp_input_servers; 366 "motion_device"};
367 BasicSetting<std::string> udp_input_servers{InputCommon::CemuhookUDP::DEFAULT_SRV,
368 "udp_input_servers"};
187 369
188 bool mouse_panning; 370 BasicSetting<bool> mouse_panning{false, "mouse_panning"};
189 float mouse_panning_sensitivity; 371 BasicSetting<float> mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"};
190 bool mouse_enabled; 372 BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
191 std::string mouse_device; 373 std::string mouse_device;
192 MouseButtonsRaw mouse_buttons; 374 MouseButtonsRaw mouse_buttons;
193 375
194 bool emulate_analog_keyboard; 376 BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
195 bool keyboard_enabled; 377 BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
196 KeyboardKeysRaw keyboard_keys; 378 KeyboardKeysRaw keyboard_keys;
197 KeyboardModsRaw keyboard_mods; 379 KeyboardModsRaw keyboard_mods;
198 380
199 bool debug_pad_enabled; 381 BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
200 ButtonsRaw debug_pad_buttons; 382 ButtonsRaw debug_pad_buttons;
201 AnalogsRaw debug_pad_analogs; 383 AnalogsRaw debug_pad_analogs;
202 384
203 TouchscreenInput touchscreen; 385 TouchscreenInput touchscreen;
204 386
205 bool use_touch_from_button; 387 BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
206 std::string touch_device; 388 BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
207 int touch_from_button_map_index; 389 "touch_device"};
390 BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
208 std::vector<TouchFromButtonMap> touch_from_button_maps; 391 std::vector<TouchFromButtonMap> touch_from_button_maps;
209 392
210 std::atomic_bool is_device_reload_pending{true}; 393 std::atomic_bool is_device_reload_pending{true};
211 394
212 // Data Storage 395 // Data Storage
213 bool use_virtual_sd; 396 BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
214 bool gamecard_inserted; 397 BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
215 bool gamecard_current_game; 398 BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"};
216 std::string gamecard_path; 399 BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"};
217 400
218 // Debugging 401 // Debugging
219 bool record_frame_times; 402 bool record_frame_times;
220 bool use_gdbstub; 403 BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
221 u16 gdbstub_port; 404 BasicSetting<u16> gdbstub_port{0, "gdbstub_port"};
222 std::string program_args; 405 BasicSetting<std::string> program_args{std::string(), "program_args"};
223 bool dump_exefs; 406 BasicSetting<bool> dump_exefs{false, "dump_exefs"};
224 bool dump_nso; 407 BasicSetting<bool> dump_nso{false, "dump_nso"};
225 bool enable_fs_access_log; 408 BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
226 bool reporting_services; 409 BasicSetting<bool> reporting_services{false, "reporting_services"};
227 bool quest_flag; 410 BasicSetting<bool> quest_flag{false, "quest_flag"};
228 bool disable_macro_jit; 411 BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"};
229 bool extended_logging; 412 BasicSetting<bool> extended_logging{false, "extended_logging"};
230 bool use_debug_asserts; 413 BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
231 bool use_auto_stub; 414 BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
232 415
233 // Miscellaneous 416 // Miscellaneous
234 std::string log_filter; 417 BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
235 bool use_dev_keys; 418 BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
236 419
237 // Services 420 // Services
238 std::string bcat_backend; 421 BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
239 bool bcat_boxcat_local; 422 BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
240 423
241 // WebService 424 // WebService
242 bool enable_telemetry; 425 BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
243 std::string web_api_url; 426 BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
244 std::string yuzu_username; 427 BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"};
245 std::string yuzu_token; 428 BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"};
246 429
247 // Add-Ons 430 // Add-Ons
248 std::map<u64, std::vector<std::string>> disabled_addons; 431 std::map<u64, std::vector<std::string>> disabled_addons;
diff --git a/src/common/thread_worker.cpp b/src/common/thread_worker.cpp
deleted file mode 100644
index 8f9bf447a..000000000
--- a/src/common/thread_worker.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/thread.h"
6#include "common/thread_worker.h"
7
8namespace Common {
9
10ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
11 for (std::size_t i = 0; i < num_workers; ++i)
12 threads.emplace_back([this, thread_name{std::string{name}}] {
13 Common::SetCurrentThreadName(thread_name.c_str());
14
15 // Wait for first request
16 {
17 std::unique_lock lock{queue_mutex};
18 condition.wait(lock, [this] { return stop || !requests.empty(); });
19 }
20
21 while (true) {
22 std::function<void()> task;
23
24 {
25 std::unique_lock lock{queue_mutex};
26 condition.wait(lock, [this] { return stop || !requests.empty(); });
27 if (stop || requests.empty()) {
28 return;
29 }
30 task = std::move(requests.front());
31 requests.pop();
32 }
33
34 task();
35 }
36 });
37}
38
39ThreadWorker::~ThreadWorker() {
40 {
41 std::unique_lock lock{queue_mutex};
42 stop = true;
43 }
44 condition.notify_all();
45 for (std::thread& thread : threads) {
46 thread.join();
47 }
48}
49
50void ThreadWorker::QueueWork(std::function<void()>&& work) {
51 {
52 std::unique_lock lock{queue_mutex};
53 requests.emplace(work);
54 }
55 condition.notify_one();
56}
57
58} // namespace Common
diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h
index f1859971f..8272985ff 100644
--- a/src/common/thread_worker.h
+++ b/src/common/thread_worker.h
@@ -7,24 +7,110 @@
7#include <atomic> 7#include <atomic>
8#include <functional> 8#include <functional>
9#include <mutex> 9#include <mutex>
10#include <stop_token>
10#include <string> 11#include <string>
12#include <thread>
13#include <type_traits>
11#include <vector> 14#include <vector>
12#include <queue> 15#include <queue>
13 16
17#include "common/thread.h"
18#include "common/unique_function.h"
19
14namespace Common { 20namespace Common {
15 21
16class ThreadWorker final { 22template <class StateType = void>
23class StatefulThreadWorker {
24 static constexpr bool with_state = !std::is_same_v<StateType, void>;
25
26 struct DummyCallable {
27 int operator()() const noexcept {
28 return 0;
29 }
30 };
31
32 using Task =
33 std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
34 using StateMaker = std::conditional_t<with_state, std::function<StateType()>, DummyCallable>;
35
17public: 36public:
18 explicit ThreadWorker(std::size_t num_workers, const std::string& name); 37 explicit StatefulThreadWorker(size_t num_workers, std::string name, StateMaker func = {})
19 ~ThreadWorker(); 38 : workers_queued{num_workers}, thread_name{std::move(name)} {
20 void QueueWork(std::function<void()>&& work); 39 const auto lambda = [this, func](std::stop_token stop_token) {
40 Common::SetCurrentThreadName(thread_name.c_str());
41 {
42 std::conditional_t<with_state, StateType, int> state{func()};
43 while (!stop_token.stop_requested()) {
44 Task task;
45 {
46 std::unique_lock lock{queue_mutex};
47 if (requests.empty()) {
48 wait_condition.notify_all();
49 }
50 condition.wait(lock, stop_token, [this] { return !requests.empty(); });
51 if (stop_token.stop_requested()) {
52 break;
53 }
54 task = std::move(requests.front());
55 requests.pop();
56 }
57 if constexpr (with_state) {
58 task(&state);
59 } else {
60 task();
61 }
62 ++work_done;
63 }
64 }
65 ++workers_stopped;
66 wait_condition.notify_all();
67 };
68 threads.reserve(num_workers);
69 for (size_t i = 0; i < num_workers; ++i) {
70 threads.emplace_back(lambda);
71 }
72 }
73
74 StatefulThreadWorker& operator=(const StatefulThreadWorker&) = delete;
75 StatefulThreadWorker(const StatefulThreadWorker&) = delete;
76
77 StatefulThreadWorker& operator=(StatefulThreadWorker&&) = delete;
78 StatefulThreadWorker(StatefulThreadWorker&&) = delete;
79
80 void QueueWork(Task work) {
81 {
82 std::unique_lock lock{queue_mutex};
83 requests.emplace(std::move(work));
84 ++work_scheduled;
85 }
86 condition.notify_one();
87 }
88
89 void WaitForRequests(std::stop_token stop_token = {}) {
90 std::stop_callback callback(stop_token, [this] {
91 for (auto& thread : threads) {
92 thread.request_stop();
93 }
94 });
95 std::unique_lock lock{queue_mutex};
96 wait_condition.wait(lock, [this] {
97 return workers_stopped >= workers_queued || work_done >= work_scheduled;
98 });
99 }
21 100
22private: 101private:
23 std::vector<std::thread> threads; 102 std::queue<Task> requests;
24 std::queue<std::function<void()>> requests;
25 std::mutex queue_mutex; 103 std::mutex queue_mutex;
26 std::condition_variable condition; 104 std::condition_variable_any condition;
27 std::atomic_bool stop{}; 105 std::condition_variable wait_condition;
106 std::atomic<size_t> work_scheduled{};
107 std::atomic<size_t> work_done{};
108 std::atomic<size_t> workers_stopped{};
109 std::atomic<size_t> workers_queued{};
110 std::string thread_name;
111 std::vector<std::jthread> threads;
28}; 112};
29 113
114using ThreadWorker = StatefulThreadWorker<>;
115
30} // namespace Common 116} // namespace Common
diff --git a/src/common/unique_function.h b/src/common/unique_function.h
new file mode 100644
index 000000000..ca0559071
--- /dev/null
+++ b/src/common/unique_function.h
@@ -0,0 +1,62 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <utility>
9
10namespace Common {
11
12/// General purpose function wrapper similar to std::function.
13/// Unlike std::function, the captured values don't have to be copyable.
14/// This class can be moved but not copied.
15template <typename ResultType, typename... Args>
16class UniqueFunction {
17 class CallableBase {
18 public:
19 virtual ~CallableBase() = default;
20 virtual ResultType operator()(Args&&...) = 0;
21 };
22
23 template <typename Functor>
24 class Callable final : public CallableBase {
25 public:
26 Callable(Functor&& functor_) : functor{std::move(functor_)} {}
27 ~Callable() override = default;
28
29 ResultType operator()(Args&&... args) override {
30 return functor(std::forward<Args>(args)...);
31 }
32
33 private:
34 Functor functor;
35 };
36
37public:
38 UniqueFunction() = default;
39
40 template <typename Functor>
41 UniqueFunction(Functor&& functor)
42 : callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
43
44 UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
45 UniqueFunction(UniqueFunction&& rhs) noexcept = default;
46
47 UniqueFunction& operator=(const UniqueFunction&) = delete;
48 UniqueFunction(const UniqueFunction&) = delete;
49
50 ResultType operator()(Args&&... args) const {
51 return (*callable)(std::forward<Args>(args)...);
52 }
53
54 explicit operator bool() const noexcept {
55 return static_cast<bool>(callable);
56 }
57
58private:
59 std::unique_ptr<CallableBase> callable;
60};
61
62} // namespace Common
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 77a44f862..b0d89c539 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -150,7 +150,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
150 config.far_code_offset = 400_MiB; 150 config.far_code_offset = 400_MiB;
151 151
152 // Safe optimizations 152 // Safe optimizations
153 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) { 153 if (Settings::values.cpu_debug_mode) {
154 if (!Settings::values.cpuopt_page_tables) { 154 if (!Settings::values.cpuopt_page_tables) {
155 config.page_table = nullptr; 155 config.page_table = nullptr;
156 } 156 }
@@ -183,20 +183,28 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
183 // Unsafe optimizations 183 // Unsafe optimizations
184 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { 184 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
185 config.unsafe_optimizations = true; 185 config.unsafe_optimizations = true;
186 if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) { 186 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
187 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 187 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
188 } 188 }
189 if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) { 189 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
190 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 190 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
191 } 191 }
192 if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue()) { 192 if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) {
193 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; 193 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
194 } 194 }
195 if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) { 195 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
196 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 196 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
197 } 197 }
198 } 198 }
199 199
200 // Curated optimizations
201 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
202 config.unsafe_optimizations = true;
203 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
204 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
205 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
206 }
207
200 return std::make_unique<Dynarmic::A32::Jit>(config); 208 return std::make_unique<Dynarmic::A32::Jit>(config);
201} 209}
202 210
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 75332e348..bf27ffe71 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -190,7 +190,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
190 config.far_code_offset = 400_MiB; 190 config.far_code_offset = 400_MiB;
191 191
192 // Safe optimizations 192 // Safe optimizations
193 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) { 193 if (Settings::values.cpu_debug_mode) {
194 if (!Settings::values.cpuopt_page_tables) { 194 if (!Settings::values.cpuopt_page_tables) {
195 config.page_table = nullptr; 195 config.page_table = nullptr;
196 } 196 }
@@ -223,20 +223,28 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
223 // Unsafe optimizations 223 // Unsafe optimizations
224 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) { 224 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
225 config.unsafe_optimizations = true; 225 config.unsafe_optimizations = true;
226 if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) { 226 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
227 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 227 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
228 } 228 }
229 if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) { 229 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
230 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 230 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
231 } 231 }
232 if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) { 232 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
233 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 233 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
234 } 234 }
235 if (Settings::values.cpuopt_unsafe_fastmem_check.GetValue()) { 235 if (Settings::values.cpuopt_unsafe_fastmem_check) {
236 config.fastmem_address_space_bits = 64; 236 config.fastmem_address_space_bits = 64;
237 } 237 }
238 } 238 }
239 239
240 // Curated optimizations
241 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
242 config.unsafe_optimizations = true;
243 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
244 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
245 config.fastmem_address_space_bits = 64;
246 }
247
240 return std::make_shared<Dynarmic::A64::Jit>(config); 248 return std::make_shared<Dynarmic::A64::Jit>(config);
241} 249}
242 250
diff --git a/src/core/core.cpp b/src/core/core.cpp
index e6f1aa0e7..891f1cb49 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -263,9 +263,9 @@ struct System::Impl {
263 if (Settings::values.gamecard_inserted) { 263 if (Settings::values.gamecard_inserted) {
264 if (Settings::values.gamecard_current_game) { 264 if (Settings::values.gamecard_current_game) {
265 fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath)); 265 fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
266 } else if (!Settings::values.gamecard_path.empty()) { 266 } else if (!Settings::values.gamecard_path.GetValue().empty()) {
267 fs_controller.SetGameCard( 267 const auto gamecard_path = Settings::values.gamecard_path.GetValue();
268 GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path)); 268 fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, gamecard_path));
269 } 269 }
270 } 270 }
271 271
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp
index 8d960d1ca..4c58c310f 100644
--- a/src/core/frontend/applets/profile_select.cpp
+++ b/src/core/frontend/applets/profile_select.cpp
@@ -13,7 +13,7 @@ ProfileSelectApplet::~ProfileSelectApplet() = default;
13void DefaultProfileSelectApplet::SelectProfile( 13void DefaultProfileSelectApplet::SelectProfile(
14 std::function<void(std::optional<Common::UUID>)> callback) const { 14 std::function<void(std::optional<Common::UUID>)> callback) const {
15 Service::Account::ProfileManager manager; 15 Service::Account::ProfileManager manager;
16 callback(manager.GetUser(Settings::values.current_user).value_or(Common::UUID{})); 16 callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
17 LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); 17 LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
18} 18}
19 19
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index f72d5d561..24a1c9157 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() {
48 CreateNewUser(UUID::Generate(), "yuzu"); 48 CreateNewUser(UUID::Generate(), "yuzu");
49 } 49 }
50 50
51 auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1); 51 auto current =
52 std::clamp<int>(static_cast<s32>(Settings::values.current_user), 0, MAX_USERS - 1);
52 53
53 // If user index don't exist. Load the first user and change the active user 54 // If user index don't exist. Load the first user and change the active user
54 if (!UserExistsIndex(current)) { 55 if (!UserExistsIndex(current)) {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index b578153d3..23ebc1138 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) {
1443 params.is_account_selected = 1; 1443 params.is_account_selected = 1;
1444 1444
1445 Account::ProfileManager profile_manager{}; 1445 Account::ProfileManager profile_manager{};
1446 const auto uuid = profile_manager.GetUser(Settings::values.current_user); 1446 const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
1447 ASSERT(uuid); 1447 ASSERT(uuid);
1448 params.current_user = uuid->uuid; 1448 params.current_user = uuid->uuid;
1449 1449
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 44e4d0509..f85444da8 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(
579std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system, 579std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
580 DirectoryGetter getter) { 580 DirectoryGetter getter) {
581#ifdef YUZU_ENABLE_BOXCAT 581#ifdef YUZU_ENABLE_BOXCAT
582 if (Settings::values.bcat_backend == "boxcat") { 582 if (Settings::values.bcat_backend.GetValue() == "boxcat") {
583 return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter)); 583 return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
584 } 584 }
585#endif 585#endif
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index f03b2666a..e742db48f 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -179,7 +179,7 @@ private:
179 IPC::ResponseBuilder rb{ctx, 3}; 179 IPC::ResponseBuilder rb{ctx, 3};
180 rb.Push(ResultSuccess); 180 rb.Push(ResultSuccess);
181 181
182 if (Settings::values.bcat_backend == "none") { 182 if (Settings::values.bcat_backend.GetValue() == "none") {
183 rb.PushEnum(RequestState::NotSubmitted); 183 rb.PushEnum(RequestState::NotSubmitted);
184 } else { 184 } else {
185 rb.PushEnum(RequestState::Connected); 185 rb.PushEnum(RequestState::Connected);
@@ -384,7 +384,7 @@ private:
384 384
385 IPC::ResponseBuilder rb{ctx, 3}; 385 IPC::ResponseBuilder rb{ctx, 3};
386 rb.Push(ResultSuccess); 386 rb.Push(ResultSuccess);
387 if (Settings::values.bcat_backend == "none") { 387 if (Settings::values.bcat_backend.GetValue() == "none") {
388 rb.Push<u8>(0); 388 rb.Push<u8>(0);
389 } else { 389 } else {
390 rb.Push<u8>(1); 390 rb.Push<u8>(1);
@@ -395,7 +395,7 @@ private:
395 395
396 IPC::ResponseBuilder rb{ctx, 3}; 396 IPC::ResponseBuilder rb{ctx, 3};
397 rb.Push(ResultSuccess); 397 rb.Push(ResultSuccess);
398 if (Settings::values.bcat_backend == "none") { 398 if (Settings::values.bcat_backend.GetValue() == "none") {
399 rb.Push<u8>(0); 399 rb.Push<u8>(0);
400 } else { 400 } else {
401 rb.Push<u8>(1); 401 rb.Push<u8>(1);
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index ece2a74c6..522a604a5 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) {
160 160
161 IPC::ResponseBuilder rb{ctx, 3}; 161 IPC::ResponseBuilder rb{ctx, 3};
162 rb.Push(ResultSuccess); 162 rb.Push(ResultSuccess);
163 rb.Push(static_cast<u32>(Settings::values.quest_flag)); 163 rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
164} 164}
165 165
166void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { 166void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 618555202..951ea966e 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)
155 codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size); 155 codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
156 } 156 }
157 157
158 if (!Settings::values.program_args.empty()) { 158 if (!Settings::values.program_args.GetValue().empty()) {
159 const auto arg_data = Settings::values.program_args; 159 const auto arg_data = Settings::values.program_args.GetValue();
160 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE; 160 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
161 NSOArgumentHeader args_header{ 161 NSOArgumentHeader args_header{
162 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}}; 162 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 0f5cfda68..4a2224c02 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::
104 codeset.segments[i].size = nso_header.segments[i].size; 104 codeset.segments[i].size = nso_header.segments[i].size;
105 } 105 }
106 106
107 if (should_pass_arguments && !Settings::values.program_args.empty()) { 107 if (should_pass_arguments && !Settings::values.program_args.GetValue().empty()) {
108 const auto arg_data{Settings::values.program_args}; 108 const auto arg_data{Settings::values.program_args.GetValue()};
109 109
110 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE; 110 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
111 NSOArgumentHeader args_header{ 111 NSOArgumentHeader args_header{
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 82b0f535a..cfaf50105 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -397,7 +397,7 @@ void Reporter::ClearFSAccessLog() const {
397} 397}
398 398
399bool Reporter::IsReportingEnabled() const { 399bool Reporter::IsReportingEnabled() const {
400 return Settings::values.reporting_services; 400 return Settings::values.reporting_services.GetValue();
401} 401}
402 402
403} // namespace Core 403} // namespace Core
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index d4c23ced2..066cb23e4 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -135,7 +135,7 @@ u64 RegenerateTelemetryId() {
135 135
136bool VerifyLogin(const std::string& username, const std::string& token) { 136bool VerifyLogin(const std::string& username, const std::string& token) {
137#ifdef ENABLE_WEB_SERVICE 137#ifdef ENABLE_WEB_SERVICE
138 return WebService::VerifyLogin(Settings::values.web_api_url, username, token); 138 return WebService::VerifyLogin(Settings::values.web_api_url.GetValue(), username, token);
139#else 139#else
140 return false; 140 return false;
141#endif 141#endif
@@ -152,7 +152,8 @@ TelemetrySession::~TelemetrySession() {
152 152
153#ifdef ENABLE_WEB_SERVICE 153#ifdef ENABLE_WEB_SERVICE
154 auto backend = std::make_unique<WebService::TelemetryJson>( 154 auto backend = std::make_unique<WebService::TelemetryJson>(
155 Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token); 155 Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
156 Settings::values.yuzu_token.GetValue());
156#else 157#else
157 auto backend = std::make_unique<Telemetry::NullVisitor>(); 158 auto backend = std::make_unique<Telemetry::NullVisitor>();
158#endif 159#endif
@@ -212,7 +213,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
212 213
213 // Log user configuration information 214 // Log user configuration information
214 constexpr auto field_type = Telemetry::FieldType::UserConfig; 215 constexpr auto field_type = Telemetry::FieldType::UserConfig;
215 AddField(field_type, "Audio_SinkId", Settings::values.sink_id); 216 AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
216 AddField(field_type, "Audio_EnableAudioStretching", 217 AddField(field_type, "Audio_EnableAudioStretching",
217 Settings::values.enable_audio_stretching.GetValue()); 218 Settings::values.enable_audio_stretching.GetValue());
218 AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue()); 219 AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
@@ -242,7 +243,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
242bool TelemetrySession::SubmitTestcase() { 243bool TelemetrySession::SubmitTestcase() {
243#ifdef ENABLE_WEB_SERVICE 244#ifdef ENABLE_WEB_SERVICE
244 auto backend = std::make_unique<WebService::TelemetryJson>( 245 auto backend = std::make_unique<WebService::TelemetryJson>(
245 Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token); 246 Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
247 Settings::values.yuzu_token.GetValue());
246 field_collection.Accept(*backend); 248 field_collection.Accept(*backend);
247 return backend->SubmitTestcase(); 249 return backend->SubmitTestcase();
248#else 250#else
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 758f7af1f..45b3d7340 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -84,7 +84,8 @@ public:
84 std::lock_guard lock{mutex}; 84 std::lock_guard lock{mutex};
85 const auto axis_value = 85 const auto axis_value =
86 static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis)); 86 static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
87 return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range); 87 const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue();
88 return axis_value * sensitivity / (100.0f * range);
88 } 89 }
89 90
90 std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { 91 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 5b24fd8bf..7878a56d7 100644
--- a/src/input_common/touch_from_button.cpp
+++ b/src/input_common/touch_from_button.cpp
@@ -13,7 +13,7 @@ class TouchFromButtonDevice final : public Input::TouchDevice {
13public: 13public:
14 TouchFromButtonDevice() { 14 TouchFromButtonDevice() {
15 const auto button_index = 15 const auto button_index =
16 static_cast<std::size_t>(Settings::values.touch_from_button_map_index); 16 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
17 const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons; 17 const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
18 18
19 for (const auto& config_entry : buttons) { 19 for (const auto& config_entry : buttons) {
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index bc1dfab3d..9b0aec797 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 {
201void Client::ReloadSockets() { 201void Client::ReloadSockets() {
202 Reset(); 202 Reset();
203 203
204 std::stringstream servers_ss(Settings::values.udp_input_servers); 204 std::stringstream servers_ss(static_cast<std::string>(Settings::values.udp_input_servers));
205 std::string server_token; 205 std::string server_token;
206 std::size_t client = 0; 206 std::size_t client = 0;
207 while (std::getline(servers_ss, server_token, ',')) { 207 while (std::getline(servers_ss, server_token, ',')) {
@@ -370,7 +370,7 @@ std::optional<std::size_t> Client::GetUnusedFingerID() const {
370 370
371void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { 371void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
372 // TODO: Use custom calibration per device 372 // TODO: Use custom calibration per device
373 const Common::ParamPackage touch_param(Settings::values.touch_device); 373 const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
374 const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100)); 374 const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
375 const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50)); 375 const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
376 const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800)); 376 const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 96bc30cac..c4c012f3d 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -5,6 +5,7 @@ add_executable(tests
5 common/host_memory.cpp 5 common/host_memory.cpp
6 common/param_package.cpp 6 common/param_package.cpp
7 common/ring_buffer.cpp 7 common/ring_buffer.cpp
8 common/unique_function.cpp
8 core/core_timing.cpp 9 core/core_timing.cpp
9 core/network/network.cpp 10 core/network/network.cpp
10 tests.cpp 11 tests.cpp
diff --git a/src/tests/common/unique_function.cpp b/src/tests/common/unique_function.cpp
new file mode 100644
index 000000000..ac9912738
--- /dev/null
+++ b/src/tests/common/unique_function.cpp
@@ -0,0 +1,108 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6
7#include <catch2/catch.hpp>
8
9#include "common/unique_function.h"
10
11namespace {
12struct Noisy {
13 Noisy() : state{"Default constructed"} {}
14 Noisy(Noisy&& rhs) noexcept : state{"Move constructed"} {
15 rhs.state = "Moved away";
16 }
17 Noisy& operator=(Noisy&& rhs) noexcept {
18 state = "Move assigned";
19 rhs.state = "Moved away";
20 }
21 Noisy(const Noisy&) : state{"Copied constructed"} {}
22 Noisy& operator=(const Noisy&) {
23 state = "Copied assigned";
24 }
25
26 std::string state;
27};
28} // Anonymous namespace
29
30TEST_CASE("UniqueFunction", "[common]") {
31 SECTION("Capture reference") {
32 int value = 0;
33 Common::UniqueFunction<void> func = [&value] { value = 5; };
34 func();
35 REQUIRE(value == 5);
36 }
37 SECTION("Capture pointer") {
38 int value = 0;
39 int* pointer = &value;
40 Common::UniqueFunction<void> func = [pointer] { *pointer = 5; };
41 func();
42 REQUIRE(value == 5);
43 }
44 SECTION("Move object") {
45 Noisy noisy;
46 REQUIRE(noisy.state == "Default constructed");
47
48 Common::UniqueFunction<void> func = [noisy = std::move(noisy)] {
49 REQUIRE(noisy.state == "Move constructed");
50 };
51 REQUIRE(noisy.state == "Moved away");
52 func();
53 }
54 SECTION("Move construct function") {
55 int value = 0;
56 Common::UniqueFunction<void> func = [&value] { value = 5; };
57 Common::UniqueFunction<void> new_func = std::move(func);
58 new_func();
59 REQUIRE(value == 5);
60 }
61 SECTION("Move assign function") {
62 int value = 0;
63 Common::UniqueFunction<void> func = [&value] { value = 5; };
64 Common::UniqueFunction<void> new_func;
65 new_func = std::move(func);
66 new_func();
67 REQUIRE(value == 5);
68 }
69 SECTION("Default construct then assign function") {
70 int value = 0;
71 Common::UniqueFunction<void> func;
72 func = [&value] { value = 5; };
73 func();
74 REQUIRE(value == 5);
75 }
76 SECTION("Pass arguments") {
77 int result = 0;
78 Common::UniqueFunction<void, int, int> func = [&result](int a, int b) { result = a + b; };
79 func(5, 4);
80 REQUIRE(result == 9);
81 }
82 SECTION("Pass arguments and return value") {
83 Common::UniqueFunction<int, int, int> func = [](int a, int b) { return a + b; };
84 REQUIRE(func(5, 4) == 9);
85 }
86 SECTION("Destructor") {
87 int num_destroyed = 0;
88 struct Foo {
89 Foo(int* num_) : num{num_} {}
90 Foo(Foo&& rhs) : num{std::exchange(rhs.num, nullptr)} {}
91 Foo(const Foo&) = delete;
92
93 ~Foo() {
94 if (num) {
95 ++*num;
96 }
97 }
98
99 int* num = nullptr;
100 };
101 Foo object{&num_destroyed};
102 {
103 Common::UniqueFunction<void> func = [object = std::move(object)] {};
104 REQUIRE(num_destroyed == 0);
105 }
106 REQUIRE(num_destroyed == 1);
107 }
108}
diff --git a/src/tests/video_core/buffer_base.cpp b/src/tests/video_core/buffer_base.cpp
index edced69bb..9f5a54de4 100644
--- a/src/tests/video_core/buffer_base.cpp
+++ b/src/tests/video_core/buffer_base.cpp
@@ -536,7 +536,7 @@ TEST_CASE("BufferBase: Cached write downloads") {
536 REQUIRE(rasterizer.Count() == 63); 536 REQUIRE(rasterizer.Count() == 63);
537 buffer.MarkRegionAsGpuModified(c + PAGE, PAGE); 537 buffer.MarkRegionAsGpuModified(c + PAGE, PAGE);
538 int num = 0; 538 int num = 0;
539 buffer.ForEachDownloadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); 539 buffer.ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; });
540 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); 540 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
541 REQUIRE(num == 0); 541 REQUIRE(num == 0);
542 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); 542 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index b121d36a3..c3318095c 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -226,19 +226,24 @@ public:
226 /// Call 'func' for each CPU modified range and unmark those pages as CPU modified 226 /// Call 'func' for each CPU modified range and unmark those pages as CPU modified
227 template <typename Func> 227 template <typename Func>
228 void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) { 228 void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) {
229 ForEachModifiedRange<Type::CPU>(query_cpu_range, size, func); 229 ForEachModifiedRange<Type::CPU>(query_cpu_range, size, true, func);
230 } 230 }
231 231
232 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified 232 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified
233 template <typename Func> 233 template <typename Func>
234 void ForEachDownloadRange(VAddr query_cpu_range, u64 size, Func&& func) { 234 void ForEachDownloadRange(VAddr query_cpu_range, u64 size, bool clear, Func&& func) {
235 ForEachModifiedRange<Type::GPU>(query_cpu_range, size, func); 235 ForEachModifiedRange<Type::GPU>(query_cpu_range, size, clear, func);
236 }
237
238 template <typename Func>
239 void ForEachDownloadRangeAndClear(VAddr query_cpu_range, u64 size, Func&& func) {
240 ForEachModifiedRange<Type::GPU>(query_cpu_range, size, true, func);
236 } 241 }
237 242
238 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified 243 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified
239 template <typename Func> 244 template <typename Func>
240 void ForEachDownloadRange(Func&& func) { 245 void ForEachDownloadRange(Func&& func) {
241 ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), func); 246 ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), true, func);
242 } 247 }
243 248
244 /// Mark buffer as picked 249 /// Mark buffer as picked
@@ -415,7 +420,7 @@ private:
415 * @param func Function to call for each turned off region 420 * @param func Function to call for each turned off region
416 */ 421 */
417 template <Type type, typename Func> 422 template <Type type, typename Func>
418 void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) { 423 void ForEachModifiedRange(VAddr query_cpu_range, s64 size, bool clear, Func&& func) {
419 static_assert(type != Type::Untracked); 424 static_assert(type != Type::Untracked);
420 425
421 const s64 difference = query_cpu_range - cpu_addr; 426 const s64 difference = query_cpu_range - cpu_addr;
@@ -467,7 +472,9 @@ private:
467 bits = (bits << left_offset) >> left_offset; 472 bits = (bits << left_offset) >> left_offset;
468 473
469 const u64 current_word = state_words[word_index] & bits; 474 const u64 current_word = state_words[word_index] & bits;
470 state_words[word_index] &= ~bits; 475 if (clear) {
476 state_words[word_index] &= ~bits;
477 }
471 478
472 if constexpr (type == Type::CPU) { 479 if constexpr (type == Type::CPU) {
473 const u64 current_bits = untracked_words[word_index] & bits; 480 const u64 current_bits = untracked_words[word_index] & bits;
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index cad7f902d..2871682f6 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -15,6 +15,7 @@
15#include <vector> 15#include <vector>
16 16
17#include <boost/container/small_vector.hpp> 17#include <boost/container/small_vector.hpp>
18#include <boost/icl/interval_set.hpp>
18 19
19#include "common/common_types.h" 20#include "common/common_types.h"
20#include "common/div_ceil.h" 21#include "common/div_ceil.h"
@@ -77,6 +78,9 @@ class BufferCache {
77 using Runtime = typename P::Runtime; 78 using Runtime = typename P::Runtime;
78 using Buffer = typename P::Buffer; 79 using Buffer = typename P::Buffer;
79 80
81 using IntervalSet = boost::icl::interval_set<VAddr>;
82 using IntervalType = typename IntervalSet::interval_type;
83
80 struct Empty {}; 84 struct Empty {};
81 85
82 struct OverlapResult { 86 struct OverlapResult {
@@ -148,18 +152,26 @@ public:
148 /// Return true when there are uncommitted buffers to be downloaded 152 /// Return true when there are uncommitted buffers to be downloaded
149 [[nodiscard]] bool HasUncommittedFlushes() const noexcept; 153 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
150 154
155 void AccumulateFlushes();
156
151 /// Return true when the caller should wait for async downloads 157 /// Return true when the caller should wait for async downloads
152 [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept; 158 [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
153 159
154 /// Commit asynchronous downloads 160 /// Commit asynchronous downloads
155 void CommitAsyncFlushes(); 161 void CommitAsyncFlushes();
162 void CommitAsyncFlushesHigh();
156 163
157 /// Pop asynchronous downloads 164 /// Pop asynchronous downloads
158 void PopAsyncFlushes(); 165 void PopAsyncFlushes();
159 166
167 [[nodiscard]] bool DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount);
168
160 /// Return true when a CPU region is modified from the GPU 169 /// Return true when a CPU region is modified from the GPU
161 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); 170 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
162 171
172 /// Return true when a CPU region is modified from the CPU
173 [[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size);
174
163 std::mutex mutex; 175 std::mutex mutex;
164 176
165private: 177private:
@@ -190,6 +202,36 @@ private:
190 } 202 }
191 } 203 }
192 204
205 template <typename Func>
206 void ForEachWrittenRange(VAddr cpu_addr, u64 size, Func&& func) {
207 const VAddr start_address = cpu_addr;
208 const VAddr end_address = start_address + size;
209 const VAddr search_base =
210 static_cast<VAddr>(std::min<s64>(0LL, static_cast<s64>(start_address - size)));
211 const IntervalType search_interval{search_base, search_base + 1};
212 auto it = common_ranges.lower_bound(search_interval);
213 if (it == common_ranges.end()) {
214 it = common_ranges.begin();
215 }
216 for (; it != common_ranges.end(); it++) {
217 VAddr inter_addr_end = it->upper();
218 VAddr inter_addr = it->lower();
219 if (inter_addr >= end_address) {
220 break;
221 }
222 if (inter_addr_end <= start_address) {
223 continue;
224 }
225 if (inter_addr_end > end_address) {
226 inter_addr_end = end_address;
227 }
228 if (inter_addr < start_address) {
229 inter_addr = start_address;
230 }
231 func(inter_addr, inter_addr_end);
232 }
233 }
234
193 static bool IsRangeGranular(VAddr cpu_addr, size_t size) { 235 static bool IsRangeGranular(VAddr cpu_addr, size_t size) {
194 return (cpu_addr & ~Core::Memory::PAGE_MASK) == 236 return (cpu_addr & ~Core::Memory::PAGE_MASK) ==
195 ((cpu_addr + size) & ~Core::Memory::PAGE_MASK); 237 ((cpu_addr + size) & ~Core::Memory::PAGE_MASK);
@@ -272,8 +314,6 @@ private:
272 314
273 void DeleteBuffer(BufferId buffer_id); 315 void DeleteBuffer(BufferId buffer_id);
274 316
275 void ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id);
276
277 void NotifyBufferDeletion(); 317 void NotifyBufferDeletion();
278 318
279 [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const; 319 [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const;
@@ -327,9 +367,9 @@ private:
327 367
328 std::vector<BufferId> cached_write_buffer_ids; 368 std::vector<BufferId> cached_write_buffer_ids;
329 369
330 // TODO: This data structure is not optimal and it should be reworked 370 IntervalSet uncommitted_ranges;
331 std::vector<BufferId> uncommitted_downloads; 371 IntervalSet common_ranges;
332 std::deque<std::vector<BufferId>> committed_downloads; 372 std::deque<IntervalSet> committed_ranges;
333 373
334 size_t immediate_buffer_capacity = 0; 374 size_t immediate_buffer_capacity = 0;
335 std::unique_ptr<u8[]> immediate_buffer_alloc; 375 std::unique_ptr<u8[]> immediate_buffer_alloc;
@@ -352,6 +392,7 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
352 // Ensure the first slot is used for the null buffer 392 // Ensure the first slot is used for the null buffer
353 void(slot_buffers.insert(runtime, NullBufferParams{})); 393 void(slot_buffers.insert(runtime, NullBufferParams{}));
354 deletion_iterator = slot_buffers.end(); 394 deletion_iterator = slot_buffers.end();
395 common_ranges.clear();
355} 396}
356 397
357template <class P> 398template <class P>
@@ -422,6 +463,68 @@ void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
422} 463}
423 464
424template <class P> 465template <class P>
466bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
467 const std::optional<VAddr> cpu_src_address = gpu_memory.GpuToCpuAddress(src_address);
468 const std::optional<VAddr> cpu_dest_address = gpu_memory.GpuToCpuAddress(dest_address);
469 if (!cpu_src_address || !cpu_dest_address) {
470 return false;
471 }
472 const bool source_dirty = IsRegionGpuModified(*cpu_src_address, amount);
473 const bool dest_dirty = IsRegionGpuModified(*cpu_dest_address, amount);
474 if (!source_dirty && !dest_dirty) {
475 return false;
476 }
477
478 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
479 uncommitted_ranges.subtract(subtract_interval);
480 for (auto& interval_set : committed_ranges) {
481 interval_set.subtract(subtract_interval);
482 }
483
484 BufferId buffer_a;
485 BufferId buffer_b;
486 do {
487 has_deleted_buffers = false;
488 buffer_a = FindBuffer(*cpu_src_address, static_cast<u32>(amount));
489 buffer_b = FindBuffer(*cpu_dest_address, static_cast<u32>(amount));
490 } while (has_deleted_buffers);
491 auto& src_buffer = slot_buffers[buffer_a];
492 auto& dest_buffer = slot_buffers[buffer_b];
493 SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
494 SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount));
495 std::array copies{BufferCopy{
496 .src_offset = src_buffer.Offset(*cpu_src_address),
497 .dst_offset = dest_buffer.Offset(*cpu_dest_address),
498 .size = amount,
499 }};
500
501 boost::container::small_vector<IntervalType, 4> tmp_intervals;
502 auto mirror = [&](VAddr base_address, VAddr base_address_end) {
503 const u64 size = base_address_end - base_address;
504 const VAddr diff = base_address - *cpu_src_address;
505 const VAddr new_base_address = *cpu_dest_address + diff;
506 const IntervalType add_interval{new_base_address, new_base_address + size};
507 uncommitted_ranges.add(add_interval);
508 tmp_intervals.push_back(add_interval);
509 };
510 ForEachWrittenRange(*cpu_src_address, amount, mirror);
511 // This subtraction in this order is important for overlapping copies.
512 common_ranges.subtract(subtract_interval);
513 for (const IntervalType add_interval : tmp_intervals) {
514 common_ranges.add(add_interval);
515 }
516
517 runtime.CopyBuffer(dest_buffer, src_buffer, copies);
518 if (source_dirty) {
519 dest_buffer.MarkRegionAsGpuModified(*cpu_dest_address, amount);
520 }
521 std::vector<u8> tmp_buffer(amount);
522 cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount);
523 cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount);
524 return true;
525}
526
527template <class P>
425void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, 528void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
426 u32 size) { 529 u32 size) {
427 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr); 530 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
@@ -547,29 +650,30 @@ void BufferCache<P>::FlushCachedWrites() {
547 650
548template <class P> 651template <class P>
549bool BufferCache<P>::HasUncommittedFlushes() const noexcept { 652bool BufferCache<P>::HasUncommittedFlushes() const noexcept {
550 return !uncommitted_downloads.empty(); 653 return !uncommitted_ranges.empty() || !committed_ranges.empty();
551} 654}
552 655
553template <class P> 656template <class P>
554bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept { 657void BufferCache<P>::AccumulateFlushes() {
555 return !committed_downloads.empty() && !committed_downloads.front().empty(); 658 if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) {
659 uncommitted_ranges.clear();
660 return;
661 }
662 if (uncommitted_ranges.empty()) {
663 return;
664 }
665 committed_ranges.emplace_back(std::move(uncommitted_ranges));
556} 666}
557 667
558template <class P> 668template <class P>
559void BufferCache<P>::CommitAsyncFlushes() { 669bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
560 // This is intentionally passing the value by copy 670 return false;
561 committed_downloads.push_front(uncommitted_downloads);
562 uncommitted_downloads.clear();
563} 671}
564 672
565template <class P> 673template <class P>
566void BufferCache<P>::PopAsyncFlushes() { 674void BufferCache<P>::CommitAsyncFlushesHigh() {
567 if (committed_downloads.empty()) { 675 AccumulateFlushes();
568 return; 676 if (committed_ranges.empty()) {
569 }
570 auto scope_exit_pop_download = detail::ScopeExit([this] { committed_downloads.pop_back(); });
571 const std::span<const BufferId> download_ids = committed_downloads.back();
572 if (download_ids.empty()) {
573 return; 677 return;
574 } 678 }
575 MICROPROFILE_SCOPE(GPU_DownloadMemory); 679 MICROPROFILE_SCOPE(GPU_DownloadMemory);
@@ -577,20 +681,43 @@ void BufferCache<P>::PopAsyncFlushes() {
577 boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads; 681 boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
578 u64 total_size_bytes = 0; 682 u64 total_size_bytes = 0;
579 u64 largest_copy = 0; 683 u64 largest_copy = 0;
580 for (const BufferId buffer_id : download_ids) { 684 for (const IntervalSet& intervals : committed_ranges) {
581 slot_buffers[buffer_id].ForEachDownloadRange([&](u64 range_offset, u64 range_size) { 685 for (auto& interval : intervals) {
582 downloads.push_back({ 686 const std::size_t size = interval.upper() - interval.lower();
583 BufferCopy{ 687 const VAddr cpu_addr = interval.lower();
584 .src_offset = range_offset, 688 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
585 .dst_offset = total_size_bytes, 689 boost::container::small_vector<BufferCopy, 1> copies;
586 .size = range_size, 690 buffer.ForEachDownloadRangeAndClear(
587 }, 691 cpu_addr, size, [&](u64 range_offset, u64 range_size) {
588 buffer_id, 692 const VAddr buffer_addr = buffer.CpuAddr();
693 const auto add_download = [&](VAddr start, VAddr end) {
694 const u64 new_offset = start - buffer_addr;
695 const u64 new_size = end - start;
696 downloads.push_back({
697 BufferCopy{
698 .src_offset = new_offset,
699 .dst_offset = total_size_bytes,
700 .size = new_size,
701 },
702 buffer_id,
703 });
704 // Align up to avoid cache conflicts
705 constexpr u64 align = 256ULL;
706 constexpr u64 mask = ~(align - 1ULL);
707 total_size_bytes += (new_size + align - 1) & mask;
708 largest_copy = std::max(largest_copy, new_size);
709 };
710
711 const VAddr start_address = buffer_addr + range_offset;
712 const VAddr end_address = start_address + range_size;
713 ForEachWrittenRange(start_address, range_size, add_download);
714 const IntervalType subtract_interval{start_address, end_address};
715 common_ranges.subtract(subtract_interval);
716 });
589 }); 717 });
590 total_size_bytes += range_size; 718 }
591 largest_copy = std::max(largest_copy, range_size);
592 });
593 } 719 }
720 committed_ranges.clear();
594 if (downloads.empty()) { 721 if (downloads.empty()) {
595 return; 722 return;
596 } 723 }
@@ -623,6 +750,19 @@ void BufferCache<P>::PopAsyncFlushes() {
623} 750}
624 751
625template <class P> 752template <class P>
753void BufferCache<P>::CommitAsyncFlushes() {
754 if (Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High) {
755 CommitAsyncFlushesHigh();
756 } else {
757 uncommitted_ranges.clear();
758 committed_ranges.clear();
759 }
760}
761
762template <class P>
763void BufferCache<P>::PopAsyncFlushes() {}
764
765template <class P>
626bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { 766bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
627 const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE); 767 const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
628 for (u64 page = addr >> PAGE_BITS; page < page_end;) { 768 for (u64 page = addr >> PAGE_BITS; page < page_end;) {
@@ -642,6 +782,25 @@ bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
642} 782}
643 783
644template <class P> 784template <class P>
785bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) {
786 const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
787 for (u64 page = addr >> PAGE_BITS; page < page_end;) {
788 const BufferId image_id = page_table[page];
789 if (!image_id) {
790 ++page;
791 continue;
792 }
793 Buffer& buffer = slot_buffers[image_id];
794 if (buffer.IsRegionCpuModified(addr, size)) {
795 return true;
796 }
797 const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
798 page = Common::DivCeil(end_addr, PAGE_SIZE);
799 }
800 return false;
801}
802
803template <class P>
645void BufferCache<P>::BindHostIndexBuffer() { 804void BufferCache<P>::BindHostIndexBuffer() {
646 Buffer& buffer = slot_buffers[index_buffer.buffer_id]; 805 Buffer& buffer = slot_buffers[index_buffer.buffer_id];
647 TouchBuffer(buffer); 806 TouchBuffer(buffer);
@@ -649,7 +808,9 @@ void BufferCache<P>::BindHostIndexBuffer() {
649 const u32 size = index_buffer.size; 808 const u32 size = index_buffer.size;
650 SynchronizeBuffer(buffer, index_buffer.cpu_addr, size); 809 SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
651 if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { 810 if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
652 runtime.BindIndexBuffer(buffer, offset, size); 811 const u32 new_offset = offset + maxwell3d.regs.index_array.first *
812 maxwell3d.regs.index_array.FormatSizeInBytes();
813 runtime.BindIndexBuffer(buffer, new_offset, size);
653 } else { 814 } else {
654 runtime.BindIndexBuffer(maxwell3d.regs.draw.topology, maxwell3d.regs.index_array.format, 815 runtime.BindIndexBuffer(maxwell3d.regs.draw.topology, maxwell3d.regs.index_array.format,
655 maxwell3d.regs.index_array.first, maxwell3d.regs.index_array.count, 816 maxwell3d.regs.index_array.first, maxwell3d.regs.index_array.count,
@@ -863,7 +1024,7 @@ void BufferCache<P>::UpdateIndexBuffer() {
863 const GPUVAddr gpu_addr_end = index_array.EndAddress(); 1024 const GPUVAddr gpu_addr_end = index_array.EndAddress();
864 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr_begin); 1025 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr_begin);
865 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin); 1026 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
866 const u32 draw_size = index_array.count * index_array.FormatSizeInBytes(); 1027 const u32 draw_size = (index_array.count + index_array.first) * index_array.FormatSizeInBytes();
867 const u32 size = std::min(address_size, draw_size); 1028 const u32 size = std::min(address_size, draw_size);
868 if (size == 0 || !cpu_addr) { 1029 if (size == 0 || !cpu_addr) {
869 index_buffer = NULL_BINDING; 1030 index_buffer = NULL_BINDING;
@@ -1010,16 +1171,16 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 s
1010 Buffer& buffer = slot_buffers[buffer_id]; 1171 Buffer& buffer = slot_buffers[buffer_id];
1011 buffer.MarkRegionAsGpuModified(cpu_addr, size); 1172 buffer.MarkRegionAsGpuModified(cpu_addr, size);
1012 1173
1013 const bool is_accuracy_high = Settings::IsGPULevelHigh(); 1174 const IntervalType base_interval{cpu_addr, cpu_addr + size};
1175 common_ranges.add(base_interval);
1176
1177 const bool is_accuracy_high =
1178 Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High;
1014 const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); 1179 const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
1015 if (!is_accuracy_high || !is_async) { 1180 if (!is_async && !is_accuracy_high) {
1016 return;
1017 }
1018 if (std::ranges::find(uncommitted_downloads, buffer_id) != uncommitted_downloads.end()) {
1019 // Already inserted
1020 return; 1181 return;
1021 } 1182 }
1022 uncommitted_downloads.push_back(buffer_id); 1183 uncommitted_ranges.add(base_interval);
1023} 1184}
1024 1185
1025template <class P> 1186template <class P>
@@ -1103,7 +1264,6 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
1103 if (!copies.empty()) { 1264 if (!copies.empty()) {
1104 runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies); 1265 runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies);
1105 } 1266 }
1106 ReplaceBufferDownloads(overlap_id, new_buffer_id);
1107 DeleteBuffer(overlap_id); 1267 DeleteBuffer(overlap_id);
1108} 1268}
1109 1269
@@ -1244,14 +1404,28 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
1244 boost::container::small_vector<BufferCopy, 1> copies; 1404 boost::container::small_vector<BufferCopy, 1> copies;
1245 u64 total_size_bytes = 0; 1405 u64 total_size_bytes = 0;
1246 u64 largest_copy = 0; 1406 u64 largest_copy = 0;
1247 buffer.ForEachDownloadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) { 1407 buffer.ForEachDownloadRangeAndClear(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
1248 copies.push_back(BufferCopy{ 1408 const VAddr buffer_addr = buffer.CpuAddr();
1249 .src_offset = range_offset, 1409 const auto add_download = [&](VAddr start, VAddr end) {
1250 .dst_offset = total_size_bytes, 1410 const u64 new_offset = start - buffer_addr;
1251 .size = range_size, 1411 const u64 new_size = end - start;
1252 }); 1412 copies.push_back(BufferCopy{
1253 total_size_bytes += range_size; 1413 .src_offset = new_offset,
1254 largest_copy = std::max(largest_copy, range_size); 1414 .dst_offset = total_size_bytes,
1415 .size = new_size,
1416 });
1417 // Align up to avoid cache conflicts
1418 constexpr u64 align = 256ULL;
1419 constexpr u64 mask = ~(align - 1ULL);
1420 total_size_bytes += (new_size + align - 1) & mask;
1421 largest_copy = std::max(largest_copy, new_size);
1422 };
1423
1424 const VAddr start_address = buffer_addr + range_offset;
1425 const VAddr end_address = start_address + range_size;
1426 ForEachWrittenRange(start_address, range_size, add_download);
1427 const IntervalType subtract_interval{start_address, end_address};
1428 common_ranges.subtract(subtract_interval);
1255 }); 1429 });
1256 if (total_size_bytes == 0) { 1430 if (total_size_bytes == 0) {
1257 return; 1431 return;
@@ -1316,18 +1490,6 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id) {
1316} 1490}
1317 1491
1318template <class P> 1492template <class P>
1319void BufferCache<P>::ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id) {
1320 const auto replace = [old_buffer_id, new_buffer_id](std::vector<BufferId>& buffers) {
1321 std::ranges::replace(buffers, old_buffer_id, new_buffer_id);
1322 if (auto it = std::ranges::find(buffers, new_buffer_id); it != buffers.end()) {
1323 buffers.erase(std::remove(it + 1, buffers.end(), new_buffer_id), buffers.end());
1324 }
1325 };
1326 replace(uncommitted_downloads);
1327 std::ranges::for_each(committed_downloads, replace);
1328}
1329
1330template <class P>
1331void BufferCache<P>::NotifyBufferDeletion() { 1493void BufferCache<P>::NotifyBufferDeletion() {
1332 if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { 1494 if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
1333 dirty_uniform_buffers.fill(~u32{0}); 1495 dirty_uniform_buffers.fill(~u32{0});
@@ -1349,15 +1511,9 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
1349 if (!cpu_addr || size == 0) { 1511 if (!cpu_addr || size == 0) {
1350 return NULL_BINDING; 1512 return NULL_BINDING;
1351 } 1513 }
1352 // HACK(Rodrigo): This is the number of bytes bound in host beyond the guest API's range.
1353 // It exists due to some games like Astral Chain operate out of bounds.
1354 // Binding the whole map range would be technically correct, but games have large maps that make
1355 // this approach unaffordable for now.
1356 static constexpr u32 arbitrary_extra_bytes = 0xc000;
1357 const u32 bytes_to_map_end = static_cast<u32>(gpu_memory.BytesToMapEnd(gpu_addr));
1358 const Binding binding{ 1514 const Binding binding{
1359 .cpu_addr = *cpu_addr, 1515 .cpu_addr = *cpu_addr,
1360 .size = std::min(size + arbitrary_extra_bytes, bytes_to_map_end), 1516 .size = size,
1361 .buffer_id = BufferId{}, 1517 .buffer_id = BufferId{},
1362 }; 1518 };
1363 return binding; 1519 return binding;
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 8b33c04ab..8d28bd884 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/cityhash.h" 5#include "common/cityhash.h"
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "common/settings.h"
7#include "core/core.h" 8#include "core/core.h"
8#include "core/memory.h" 9#include "core/memory.h"
9#include "video_core/dma_pusher.h" 10#include "video_core/dma_pusher.h"
@@ -76,8 +77,13 @@ bool DmaPusher::Step() {
76 77
77 // Push buffer non-empty, read a word 78 // Push buffer non-empty, read a word
78 command_headers.resize(command_list_header.size); 79 command_headers.resize(command_list_header.size);
79 gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(), 80 if (Settings::IsGPULevelHigh()) {
80 command_list_header.size * sizeof(u32)); 81 gpu.MemoryManager().ReadBlock(dma_get, command_headers.data(),
82 command_list_header.size * sizeof(u32));
83 } else {
84 gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(),
85 command_list_header.size * sizeof(u32));
86 }
81 } 87 }
82 for (std::size_t index = 0; index < command_headers.size();) { 88 for (std::size_t index = 0; index < command_headers.size();) {
83 const CommandHeader& command_header = command_headers[index]; 89 const CommandHeader& command_header = command_headers[index];
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 0f640fdae..f26530ede 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -7,6 +7,10 @@
7#include "video_core/engines/fermi_2d.h" 7#include "video_core/engines/fermi_2d.h"
8#include "video_core/memory_manager.h" 8#include "video_core/memory_manager.h"
9#include "video_core/rasterizer_interface.h" 9#include "video_core/rasterizer_interface.h"
10#include "video_core/surface.h"
11
12using VideoCore::Surface::BytesPerBlock;
13using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
10 14
11namespace Tegra::Engines { 15namespace Tegra::Engines {
12 16
@@ -49,7 +53,7 @@ void Fermi2D::Blit() {
49 UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled"); 53 UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
50 54
51 const auto& args = regs.pixels_from_memory; 55 const auto& args = regs.pixels_from_memory;
52 const Config config{ 56 Config config{
53 .operation = regs.operation, 57 .operation = regs.operation,
54 .filter = args.sample_mode.filter, 58 .filter = args.sample_mode.filter,
55 .dst_x0 = args.dst_x0, 59 .dst_x0 = args.dst_x0,
@@ -61,7 +65,21 @@ void Fermi2D::Blit() {
61 .src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32), 65 .src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32),
62 .src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32), 66 .src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32),
63 }; 67 };
64 if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, config)) { 68 Surface src = regs.src;
69 const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
70 const auto need_align_to_pitch =
71 src.linear == Tegra::Engines::Fermi2D::MemoryLayout::Pitch &&
72 static_cast<s32>(src.width) == config.src_x1 &&
73 config.src_x1 > static_cast<s32>(src.pitch / bytes_per_pixel) && config.src_x0 > 0;
74 if (need_align_to_pitch) {
75 auto address = src.Address() + config.src_x0 * bytes_per_pixel;
76 src.addr_upper = static_cast<u32>(address >> 32);
77 src.addr_lower = static_cast<u32>(address);
78 src.width -= config.src_x0;
79 config.src_x1 -= config.src_x0;
80 config.src_x0 = 0;
81 }
82 if (!rasterizer->AccelerateSurfaceCopy(src, regs.dst, config)) {
65 UNIMPLEMENTED(); 83 UNIMPLEMENTED();
66 } 84 }
67} 85}
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 2ee980bab..24481952b 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -21,6 +21,10 @@ MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
21 21
22MaxwellDMA::~MaxwellDMA() = default; 22MaxwellDMA::~MaxwellDMA() = default;
23 23
24void MaxwellDMA::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
25 rasterizer = rasterizer_;
26}
27
24void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) { 28void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
25 ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register"); 29 ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register");
26 30
@@ -44,7 +48,6 @@ void MaxwellDMA::Launch() {
44 48
45 // TODO(Subv): Perform more research and implement all features of this engine. 49 // TODO(Subv): Perform more research and implement all features of this engine.
46 const LaunchDMA& launch = regs.launch_dma; 50 const LaunchDMA& launch = regs.launch_dma;
47 ASSERT(launch.remap_enable == 0);
48 ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE); 51 ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE);
49 ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE); 52 ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE);
50 ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED); 53 ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED);
@@ -77,11 +80,29 @@ void MaxwellDMA::CopyPitchToPitch() {
77 // When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D 80 // When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D
78 // buffer of length `line_length_in`. 81 // buffer of length `line_length_in`.
79 // Otherwise we copy a 2D image of dimensions (line_length_in, line_count). 82 // Otherwise we copy a 2D image of dimensions (line_length_in, line_count).
83 auto& accelerate = rasterizer->AccessAccelerateDMA();
80 if (!regs.launch_dma.multi_line_enable) { 84 if (!regs.launch_dma.multi_line_enable) {
81 memory_manager.CopyBlock(regs.offset_out, regs.offset_in, regs.line_length_in); 85 const bool is_buffer_clear = regs.launch_dma.remap_enable != 0 &&
86 regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A;
87 // TODO: allow multisized components.
88 if (is_buffer_clear) {
89 ASSERT(regs.remap_const.component_size_minus_one == 3);
90 std::vector<u32> tmp_buffer(regs.line_length_in, regs.remap_consta_value);
91 memory_manager.WriteBlock(regs.offset_out, reinterpret_cast<u8*>(tmp_buffer.data()),
92 regs.line_length_in * sizeof(u32));
93 return;
94 }
95 UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
96 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
97 std::vector<u8> tmp_buffer(regs.line_length_in);
98 memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), regs.line_length_in);
99 memory_manager.WriteBlock(regs.offset_out, tmp_buffer.data(), regs.line_length_in);
100 }
82 return; 101 return;
83 } 102 }
84 103
104 UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
105
85 // Perform a line-by-line copy. 106 // Perform a line-by-line copy.
86 // We're going to take a subrect of size (line_length_in, line_count) from the source rectangle. 107 // We're going to take a subrect of size (line_length_in, line_count) from the source rectangle.
87 // There is no need to manually flush/invalidate the regions because CopyBlock does that for us. 108 // There is no need to manually flush/invalidate the regions because CopyBlock does that for us.
@@ -105,6 +126,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
105 } 126 }
106 127
107 // Deswizzle the input and copy it over. 128 // Deswizzle the input and copy it over.
129 UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
108 const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; 130 const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in;
109 const Parameters& src_params = regs.src_params; 131 const Parameters& src_params = regs.src_params;
110 const u32 width = src_params.width; 132 const u32 width = src_params.width;
@@ -134,6 +156,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
134 156
135void MaxwellDMA::CopyPitchToBlockLinear() { 157void MaxwellDMA::CopyPitchToBlockLinear() {
136 UNIMPLEMENTED_IF_MSG(regs.dst_params.block_size.width != 0, "Block width is not one"); 158 UNIMPLEMENTED_IF_MSG(regs.dst_params.block_size.width != 0, "Block width is not one");
159 UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
137 160
138 const auto& dst_params = regs.dst_params; 161 const auto& dst_params = regs.dst_params;
139 const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in; 162 const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in;
@@ -156,13 +179,8 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
156 write_buffer.resize(dst_size); 179 write_buffer.resize(dst_size);
157 } 180 }
158 181
159 if (Settings::IsGPULevelExtreme()) { 182 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
160 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); 183 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
161 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
162 } else {
163 memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
164 memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
165 }
166 184
167 // If the input is linear and the output is tiled, swizzle the input and copy it over. 185 // If the input is linear and the output is tiled, swizzle the input and copy it over.
168 if (regs.dst_params.block_size.depth > 0) { 186 if (regs.dst_params.block_size.depth > 0) {
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index c77f02a22..4ed0d0996 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -21,8 +21,18 @@ namespace Tegra {
21class MemoryManager; 21class MemoryManager;
22} 22}
23 23
24namespace VideoCore {
25class RasterizerInterface;
26}
27
24namespace Tegra::Engines { 28namespace Tegra::Engines {
25 29
30class AccelerateDMAInterface {
31public:
32 /// Write the value to the register identified by method.
33 virtual bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) = 0;
34};
35
26/** 36/**
27 * This engine is known as gk104_copy. Documentation can be found in: 37 * This engine is known as gk104_copy. Documentation can be found in:
28 * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h 38 * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h
@@ -187,6 +197,8 @@ public:
187 }; 197 };
188 static_assert(sizeof(RemapConst) == 12); 198 static_assert(sizeof(RemapConst) == 12);
189 199
200 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
201
190 explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_); 202 explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
191 ~MaxwellDMA() override; 203 ~MaxwellDMA() override;
192 204
@@ -213,6 +225,7 @@ private:
213 Core::System& system; 225 Core::System& system;
214 226
215 MemoryManager& memory_manager; 227 MemoryManager& memory_manager;
228 VideoCore::RasterizerInterface* rasterizer;
216 229
217 std::vector<u8> read_buffer; 230 std::vector<u8> read_buffer;
218 std::vector<u8> write_buffer; 231 std::vector<u8> write_buffer;
@@ -240,7 +253,9 @@ private:
240 u32 pitch_out; 253 u32 pitch_out;
241 u32 line_length_in; 254 u32 line_length_in;
242 u32 line_count; 255 u32 line_count;
243 u32 reserved06[0xb8]; 256 u32 reserved06[0xb6];
257 u32 remap_consta_value;
258 u32 remap_constb_value;
244 RemapConst remap_const; 259 RemapConst remap_const;
245 Parameters dst_params; 260 Parameters dst_params;
246 u32 reserved07[0x1]; 261 u32 reserved07[0x1];
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index f055b61e9..34dc6c596 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -8,6 +8,7 @@
8#include <queue> 8#include <queue>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/settings.h"
11#include "core/core.h" 12#include "core/core.h"
12#include "video_core/delayed_destruction_ring.h" 13#include "video_core/delayed_destruction_ring.h"
13#include "video_core/gpu.h" 14#include "video_core/gpu.h"
@@ -53,6 +54,12 @@ public:
53 delayed_destruction_ring.Tick(); 54 delayed_destruction_ring.Tick();
54 } 55 }
55 56
57 // Unlike other fences, this one doesn't
58 void SignalOrdering() {
59 std::scoped_lock lock{buffer_cache.mutex};
60 buffer_cache.AccumulateFlushes();
61 }
62
56 void SignalSemaphore(GPUVAddr addr, u32 value) { 63 void SignalSemaphore(GPUVAddr addr, u32 value) {
57 TryReleasePendingFences(); 64 TryReleasePendingFences();
58 const bool should_flush = ShouldFlush(); 65 const bool should_flush = ShouldFlush();
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 35cc561be..ff024f530 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -50,6 +50,7 @@ void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
50 maxwell_3d->BindRasterizer(rasterizer); 50 maxwell_3d->BindRasterizer(rasterizer);
51 fermi_2d->BindRasterizer(rasterizer); 51 fermi_2d->BindRasterizer(rasterizer);
52 kepler_compute->BindRasterizer(rasterizer); 52 kepler_compute->BindRasterizer(rasterizer);
53 maxwell_dma->BindRasterizer(rasterizer);
53} 54}
54 55
55Engines::Maxwell3D& GPU::Maxwell3D() { 56Engines::Maxwell3D& GPU::Maxwell3D() {
@@ -268,11 +269,13 @@ void GPU::CallPullerMethod(const MethodCall& method_call) {
268 case BufferMethods::SemaphoreAddressHigh: 269 case BufferMethods::SemaphoreAddressHigh:
269 case BufferMethods::SemaphoreAddressLow: 270 case BufferMethods::SemaphoreAddressLow:
270 case BufferMethods::SemaphoreSequence: 271 case BufferMethods::SemaphoreSequence:
271 case BufferMethods::RefCnt:
272 case BufferMethods::UnkCacheFlush: 272 case BufferMethods::UnkCacheFlush:
273 case BufferMethods::WrcacheFlush: 273 case BufferMethods::WrcacheFlush:
274 case BufferMethods::FenceValue: 274 case BufferMethods::FenceValue:
275 break; 275 break;
276 case BufferMethods::RefCnt:
277 rasterizer->SignalReference();
278 break;
276 case BufferMethods::FenceAction: 279 case BufferMethods::FenceAction:
277 ProcessFenceActionMethod(); 280 ProcessFenceActionMethod();
278 break; 281 break;
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 0cec4225b..58014c1c3 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -15,7 +15,10 @@
15 15
16namespace Tegra { 16namespace Tegra {
17class MemoryManager; 17class MemoryManager;
18namespace Engines {
19class AccelerateDMAInterface;
18} 20}
21} // namespace Tegra
19 22
20namespace VideoCore { 23namespace VideoCore {
21 24
@@ -63,6 +66,9 @@ public:
63 /// Signal a GPU based syncpoint as a fence 66 /// Signal a GPU based syncpoint as a fence
64 virtual void SignalSyncPoint(u32 value) = 0; 67 virtual void SignalSyncPoint(u32 value) = 0;
65 68
69 /// Signal a GPU based reference as point
70 virtual void SignalReference() = 0;
71
66 /// Release all pending fences. 72 /// Release all pending fences.
67 virtual void ReleaseFences() = 0; 73 virtual void ReleaseFences() = 0;
68 74
@@ -116,6 +122,8 @@ public:
116 return false; 122 return false;
117 } 123 }
118 124
125 [[nodiscard]] virtual Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() = 0;
126
119 /// Attempt to use a faster method to display the framebuffer to screen 127 /// Attempt to use a faster method to display the framebuffer to screen
120 [[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, 128 [[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config,
121 VAddr framebuffer_addr, u32 pixel_stride) { 129 VAddr framebuffer_addr, u32 pixel_stride) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 07ad0e205..82c84127a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -171,7 +171,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra
171 buffer_cache_runtime(device), 171 buffer_cache_runtime(device),
172 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime), 172 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
173 shader_cache(*this, emu_window_, gpu, maxwell3d, kepler_compute, gpu_memory, device), 173 shader_cache(*this, emu_window_, gpu, maxwell3d, kepler_compute, gpu_memory, device),
174 query_cache(*this, maxwell3d, gpu_memory), 174 query_cache(*this, maxwell3d, gpu_memory), accelerate_dma(buffer_cache),
175 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), 175 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
176 async_shaders(emu_window_) { 176 async_shaders(emu_window_) {
177 if (device.UseAsynchronousShaders()) { 177 if (device.UseAsynchronousShaders()) {
@@ -634,6 +634,13 @@ void RasterizerOpenGL::SignalSyncPoint(u32 value) {
634 fence_manager.SignalSyncPoint(value); 634 fence_manager.SignalSyncPoint(value);
635} 635}
636 636
637void RasterizerOpenGL::SignalReference() {
638 if (!gpu.IsAsync()) {
639 return;
640 }
641 fence_manager.SignalOrdering();
642}
643
637void RasterizerOpenGL::ReleaseFences() { 644void RasterizerOpenGL::ReleaseFences() {
638 if (!gpu.IsAsync()) { 645 if (!gpu.IsAsync()) {
639 return; 646 return;
@@ -650,6 +657,7 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
650 657
651void RasterizerOpenGL::WaitForIdle() { 658void RasterizerOpenGL::WaitForIdle() {
652 glMemoryBarrier(GL_ALL_BARRIER_BITS); 659 glMemoryBarrier(GL_ALL_BARRIER_BITS);
660 SignalReference();
653} 661}
654 662
655void RasterizerOpenGL::FragmentBarrier() { 663void RasterizerOpenGL::FragmentBarrier() {
@@ -693,6 +701,10 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surf
693 return true; 701 return true;
694} 702}
695 703
704Tegra::Engines::AccelerateDMAInterface& RasterizerOpenGL::AccessAccelerateDMA() {
705 return accelerate_dma;
706}
707
696bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, 708bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
697 VAddr framebuffer_addr, u32 pixel_stride) { 709 VAddr framebuffer_addr, u32 pixel_stride) {
698 if (framebuffer_addr == 0) { 710 if (framebuffer_addr == 0) {
@@ -1388,4 +1400,11 @@ void RasterizerOpenGL::EndTransformFeedback() {
1388 glEndTransformFeedback(); 1400 glEndTransformFeedback();
1389} 1401}
1390 1402
1403AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
1404
1405bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
1406 std::scoped_lock lock{buffer_cache.mutex};
1407 return buffer_cache.DMACopy(src_address, dest_address, amount);
1408}
1409
1391} // namespace OpenGL 1410} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 482efed7a..ccee9ba33 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -19,6 +19,7 @@
19#include "common/common_types.h" 19#include "common/common_types.h"
20#include "video_core/engines/const_buffer_info.h" 20#include "video_core/engines/const_buffer_info.h"
21#include "video_core/engines/maxwell_3d.h" 21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/engines/maxwell_dma.h"
22#include "video_core/rasterizer_accelerated.h" 23#include "video_core/rasterizer_accelerated.h"
23#include "video_core/rasterizer_interface.h" 24#include "video_core/rasterizer_interface.h"
24#include "video_core/renderer_opengl/gl_buffer_cache.h" 25#include "video_core/renderer_opengl/gl_buffer_cache.h"
@@ -58,6 +59,16 @@ struct BindlessSSBO {
58}; 59};
59static_assert(sizeof(BindlessSSBO) * CHAR_BIT == 128); 60static_assert(sizeof(BindlessSSBO) * CHAR_BIT == 128);
60 61
62class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface {
63public:
64 explicit AccelerateDMA(BufferCache& buffer_cache);
65
66 bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) override;
67
68private:
69 BufferCache& buffer_cache;
70};
71
61class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { 72class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
62public: 73public:
63 explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 74 explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -83,6 +94,7 @@ public:
83 void ModifyGPUMemory(GPUVAddr addr, u64 size) override; 94 void ModifyGPUMemory(GPUVAddr addr, u64 size) override;
84 void SignalSemaphore(GPUVAddr addr, u32 value) override; 95 void SignalSemaphore(GPUVAddr addr, u32 value) override;
85 void SignalSyncPoint(u32 value) override; 96 void SignalSyncPoint(u32 value) override;
97 void SignalReference() override;
86 void ReleaseFences() override; 98 void ReleaseFences() override;
87 void FlushAndInvalidateRegion(VAddr addr, u64 size) override; 99 void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
88 void WaitForIdle() override; 100 void WaitForIdle() override;
@@ -93,6 +105,7 @@ public:
93 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, 105 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
94 const Tegra::Engines::Fermi2D::Surface& dst, 106 const Tegra::Engines::Fermi2D::Surface& dst,
95 const Tegra::Engines::Fermi2D::Config& copy_config) override; 107 const Tegra::Engines::Fermi2D::Config& copy_config) override;
108 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
96 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 109 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
97 u32 pixel_stride) override; 110 u32 pixel_stride) override;
98 void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 111 void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
@@ -233,6 +246,7 @@ private:
233 BufferCache buffer_cache; 246 BufferCache buffer_cache;
234 ShaderCacheOpenGL shader_cache; 247 ShaderCacheOpenGL shader_cache;
235 QueryCache query_cache; 248 QueryCache query_cache;
249 AccelerateDMA accelerate_dma;
236 FenceManagerOpenGL fence_manager; 250 FenceManagerOpenGL fence_manager;
237 251
238 VideoCommon::Shader::AsyncShaders async_shaders; 252 VideoCommon::Shader::AsyncShaders async_shaders;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 3986eb172..bec3a81d9 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -103,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
103 gpu(gpu_), 103 gpu(gpu_),
104 library(OpenLibrary()), 104 library(OpenLibrary()),
105 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 105 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
106 true, Settings::values.renderer_debug)), 106 true, Settings::values.renderer_debug.GetValue())),
107 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 107 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
108 surface(CreateSurface(instance, render_window)), 108 surface(CreateSurface(instance, render_window)),
109 device(CreateDevice(instance, dld, *surface)), 109 device(CreateDevice(instance, dld, *surface)),
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index bd4d649cc..e378a5679 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -251,7 +251,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
251 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime), 251 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
252 pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, 252 pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
253 descriptor_pool, update_descriptor_queue), 253 descriptor_pool, update_descriptor_queue),
254 query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, 254 query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{buffer_cache},
255 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), 255 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
256 wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { 256 wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) {
257 scheduler.SetQueryCache(query_cache); 257 scheduler.SetQueryCache(query_cache);
@@ -580,6 +580,13 @@ void RasterizerVulkan::SignalSyncPoint(u32 value) {
580 fence_manager.SignalSyncPoint(value); 580 fence_manager.SignalSyncPoint(value);
581} 581}
582 582
583void RasterizerVulkan::SignalReference() {
584 if (!gpu.IsAsync()) {
585 return;
586 }
587 fence_manager.SignalOrdering();
588}
589
583void RasterizerVulkan::ReleaseFences() { 590void RasterizerVulkan::ReleaseFences() {
584 if (!gpu.IsAsync()) { 591 if (!gpu.IsAsync()) {
585 return; 592 return;
@@ -612,6 +619,7 @@ void RasterizerVulkan::WaitForIdle() {
612 cmdbuf.SetEvent(event, flags); 619 cmdbuf.SetEvent(event, flags);
613 cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {}); 620 cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {});
614 }); 621 });
622 SignalReference();
615} 623}
616 624
617void RasterizerVulkan::FragmentBarrier() { 625void RasterizerVulkan::FragmentBarrier() {
@@ -652,6 +660,10 @@ bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surf
652 return true; 660 return true;
653} 661}
654 662
663Tegra::Engines::AccelerateDMAInterface& RasterizerVulkan::AccessAccelerateDMA() {
664 return accelerate_dma;
665}
666
655bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, 667bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
656 VAddr framebuffer_addr, u32 pixel_stride) { 668 VAddr framebuffer_addr, u32 pixel_stride) {
657 if (!framebuffer_addr) { 669 if (!framebuffer_addr) {
@@ -690,6 +702,13 @@ void RasterizerVulkan::FlushWork() {
690 draw_counter = 0; 702 draw_counter = 0;
691} 703}
692 704
705AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
706
707bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
708 std::scoped_lock lock{buffer_cache.mutex};
709 return buffer_cache.DMACopy(src_address, dest_address, amount);
710}
711
693void RasterizerVulkan::SetupShaderDescriptors( 712void RasterizerVulkan::SetupShaderDescriptors(
694 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders, bool is_indexed) { 713 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders, bool is_indexed) {
695 image_view_indices.clear(); 714 image_view_indices.clear();
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 41459c5c5..3a78de258 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -13,6 +13,7 @@
13#include <boost/container/static_vector.hpp> 13#include <boost/container/static_vector.hpp>
14 14
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "video_core/engines/maxwell_dma.h"
16#include "video_core/rasterizer_accelerated.h" 17#include "video_core/rasterizer_accelerated.h"
17#include "video_core/rasterizer_interface.h" 18#include "video_core/rasterizer_interface.h"
18#include "video_core/renderer_vulkan/blit_image.h" 19#include "video_core/renderer_vulkan/blit_image.h"
@@ -49,6 +50,16 @@ struct VKScreenInfo;
49 50
50class StateTracker; 51class StateTracker;
51 52
53class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface {
54public:
55 explicit AccelerateDMA(BufferCache& buffer_cache);
56
57 bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override;
58
59private:
60 BufferCache& buffer_cache;
61};
62
52class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { 63class RasterizerVulkan final : public VideoCore::RasterizerAccelerated {
53public: 64public:
54 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 65 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -75,6 +86,7 @@ public:
75 void ModifyGPUMemory(GPUVAddr addr, u64 size) override; 86 void ModifyGPUMemory(GPUVAddr addr, u64 size) override;
76 void SignalSemaphore(GPUVAddr addr, u32 value) override; 87 void SignalSemaphore(GPUVAddr addr, u32 value) override;
77 void SignalSyncPoint(u32 value) override; 88 void SignalSyncPoint(u32 value) override;
89 void SignalReference() override;
78 void ReleaseFences() override; 90 void ReleaseFences() override;
79 void FlushAndInvalidateRegion(VAddr addr, u64 size) override; 91 void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
80 void WaitForIdle() override; 92 void WaitForIdle() override;
@@ -85,6 +97,7 @@ public:
85 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, 97 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
86 const Tegra::Engines::Fermi2D::Surface& dst, 98 const Tegra::Engines::Fermi2D::Surface& dst,
87 const Tegra::Engines::Fermi2D::Config& copy_config) override; 99 const Tegra::Engines::Fermi2D::Config& copy_config) override;
100 Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
88 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 101 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
89 u32 pixel_stride) override; 102 u32 pixel_stride) override;
90 103
@@ -185,6 +198,7 @@ private:
185 BufferCache buffer_cache; 198 BufferCache buffer_cache;
186 VKPipelineCache pipeline_cache; 199 VKPipelineCache pipeline_cache;
187 VKQueryCache query_cache; 200 VKQueryCache query_cache;
201 AccelerateDMA accelerate_dma;
188 VKFenceManager fence_manager; 202 VKFenceManager fence_manager;
189 203
190 vk::Event wfi_event; 204 vk::Event wfi_event;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index e3542301e..01de2d498 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -159,9 +159,7 @@ public:
159 /// Blit an image with the given parameters 159 /// Blit an image with the given parameters
160 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, 160 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
161 const Tegra::Engines::Fermi2D::Surface& src, 161 const Tegra::Engines::Fermi2D::Surface& src,
162 const Tegra::Engines::Fermi2D::Config& copy, 162 const Tegra::Engines::Fermi2D::Config& copy);
163 std::optional<Region2D> src_region_override = {},
164 std::optional<Region2D> dst_region_override = {});
165 163
166 /// Invalidate the contents of the color buffer index 164 /// Invalidate the contents of the color buffer index
167 /// These contents become unspecified, the cache can assume aggressive optimizations. 165 /// These contents become unspecified, the cache can assume aggressive optimizations.
@@ -760,9 +758,7 @@ void TextureCache<P>::UnmapGPUMemory(GPUVAddr gpu_addr, size_t size) {
760template <class P> 758template <class P>
761void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, 759void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
762 const Tegra::Engines::Fermi2D::Surface& src, 760 const Tegra::Engines::Fermi2D::Surface& src,
763 const Tegra::Engines::Fermi2D::Config& copy, 761 const Tegra::Engines::Fermi2D::Config& copy) {
764 std::optional<Region2D> src_override,
765 std::optional<Region2D> dst_override) {
766 const BlitImages images = GetBlitImages(dst, src); 762 const BlitImages images = GetBlitImages(dst, src);
767 const ImageId dst_id = images.dst_id; 763 const ImageId dst_id = images.dst_id;
768 const ImageId src_id = images.src_id; 764 const ImageId src_id = images.src_id;
@@ -773,47 +769,25 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
773 const ImageBase& src_image = slot_images[src_id]; 769 const ImageBase& src_image = slot_images[src_id];
774 770
775 // TODO: Deduplicate 771 // TODO: Deduplicate
776 const std::optional dst_base = dst_image.TryFindBase(dst.Address());
777 const SubresourceRange dst_range{.base = dst_base.value(), .extent = {1, 1}};
778 const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
779 const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
780 const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
781
782 // out of bounds texture blit checking
783 const bool use_override = src_override.has_value();
784 const s32 src_x0 = copy.src_x0 >> src_samples_x;
785 s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x;
786 const s32 src_y0 = copy.src_y0 >> src_samples_y;
787 const s32 src_y1 = copy.src_y1 >> src_samples_y;
788
789 const auto src_width = static_cast<s32>(src_image.info.size.width);
790 const bool width_oob = src_x1 > src_width;
791 const auto width_diff = width_oob ? src_x1 - src_width : 0;
792 if (width_oob) {
793 src_x1 = src_width;
794 }
795
796 const Region2D src_dimensions{
797 Offset2D{.x = src_x0, .y = src_y0},
798 Offset2D{.x = src_x1, .y = src_y1},
799 };
800 const auto src_region = use_override ? *src_override : src_dimensions;
801
802 const std::optional src_base = src_image.TryFindBase(src.Address()); 772 const std::optional src_base = src_image.TryFindBase(src.Address());
803 const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}}; 773 const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}};
804 const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range); 774 const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range);
805 const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info); 775 const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info);
806 const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples); 776 const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
777 const Region2D src_region{
778 Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y},
779 Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y},
780 };
807 781
808 const s32 dst_x0 = copy.dst_x0 >> dst_samples_x; 782 const std::optional dst_base = dst_image.TryFindBase(dst.Address());
809 const s32 dst_x1 = copy.dst_x1 >> dst_samples_x; 783 const SubresourceRange dst_range{.base = dst_base.value(), .extent = {1, 1}};
810 const s32 dst_y0 = copy.dst_y0 >> dst_samples_y; 784 const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
811 const s32 dst_y1 = copy.dst_y1 >> dst_samples_y; 785 const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
812 const Region2D dst_dimensions{ 786 const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
813 Offset2D{.x = dst_x0, .y = dst_y0}, 787 const Region2D dst_region{
814 Offset2D{.x = dst_x1 - width_diff, .y = dst_y1}, 788 Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y},
789 Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y},
815 }; 790 };
816 const auto dst_region = use_override ? *dst_override : dst_dimensions;
817 791
818 // Always call this after src_framebuffer_id was queried, as the address might be invalidated. 792 // Always call this after src_framebuffer_id was queried, as the address might be invalidated.
819 Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id]; 793 Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id];
@@ -830,21 +804,6 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
830 runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter, 804 runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter,
831 copy.operation); 805 copy.operation);
832 } 806 }
833
834 if (width_oob) {
835 // Continue copy of the oob region of the texture on the next row
836 auto oob_src = src;
837 oob_src.height++;
838 const Region2D src_region_override{
839 Offset2D{.x = 0, .y = src_y0 + 1},
840 Offset2D{.x = width_diff, .y = src_y1 + 1},
841 };
842 const Region2D dst_region_override{
843 Offset2D{.x = dst_x1 - width_diff, .y = dst_y0},
844 Offset2D{.x = dst_x1, .y = dst_y1},
845 };
846 BlitImage(dst, oob_src, copy, src_region_override, dst_region_override);
847 }
848} 807}
849 808
850template <class P> 809template <class P>
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h
index 9fbdc1ac6..47a11cb2f 100644
--- a/src/video_core/texture_cache/types.h
+++ b/src/video_core/texture_cache/types.h
@@ -133,8 +133,8 @@ struct BufferImageCopy {
133}; 133};
134 134
135struct BufferCopy { 135struct BufferCopy {
136 size_t src_offset; 136 u64 src_offset;
137 size_t dst_offset; 137 u64 dst_offset;
138 size_t size; 138 size_t size;
139}; 139};
140 140
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 634fe66a5..f870b33b1 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -52,6 +52,9 @@ add_executable(yuzu
52 configuration/configure_debug_controller.cpp 52 configuration/configure_debug_controller.cpp
53 configuration/configure_debug_controller.h 53 configuration/configure_debug_controller.h
54 configuration/configure_debug_controller.ui 54 configuration/configure_debug_controller.ui
55 configuration/configure_debug_tab.cpp
56 configuration/configure_debug_tab.h
57 configuration/configure_debug_tab.ui
55 configuration/configure_dialog.cpp 58 configuration/configure_dialog.cpp
56 configuration/configure_dialog.h 59 configuration/configure_dialog.h
57 configuration/configure_filesystem.cpp 60 configuration/configure_filesystem.cpp
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 62bafc453..8c71ad5c1 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -272,6 +272,91 @@ void Config::Initialize(const std::string& config_name) {
272 } 272 }
273} 273}
274 274
275/* {Read,Write}BasicSetting and WriteGlobalSetting templates must be defined here before their
276 * usages later in this file. This allows explicit definition of some types that don't work
277 * nicely with the general version.
278 */
279
280// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
281// can it implicitly convert a QVariant back to a {std::,Q}string
282template <>
283void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
284 const QString name = QString::fromStdString(setting.GetLabel());
285 const auto default_value = QString::fromStdString(setting.GetDefault());
286 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
287 setting.SetValue(default_value.toStdString());
288 } else {
289 setting.SetValue(qt_config->value(name, default_value).toString().toStdString());
290 }
291}
292
293template <typename Type>
294void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
295 const QString name = QString::fromStdString(setting.GetLabel());
296 const Type default_value = setting.GetDefault();
297 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
298 setting.SetValue(default_value);
299 } else {
300 setting.SetValue(
301 static_cast<QVariant>(qt_config->value(name, default_value)).value<Type>());
302 }
303}
304
305// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant
306template <>
307void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& setting) {
308 const QString name = QString::fromStdString(setting.GetLabel());
309 const std::string& value = setting.GetValue();
310 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
311 qt_config->setValue(name, QString::fromStdString(value));
312}
313
314// Explicit float definition: use a double as Qt doesn't write legible floats to config files
315template <>
316void Config::WriteBasicSetting(const Settings::BasicSetting<float>& setting) {
317 const QString name = QString::fromStdString(setting.GetLabel());
318 const double value = setting.GetValue();
319 qt_config->setValue(name + QStringLiteral("/default"),
320 setting.GetValue() == setting.GetDefault());
321 qt_config->setValue(name, value);
322}
323
324template <typename Type>
325void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
326 const QString name = QString::fromStdString(setting.GetLabel());
327 const Type value = setting.GetValue();
328 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
329 qt_config->setValue(name, value);
330}
331
332// Explicit float definition: use a double as Qt doesn't write legible floats to config files
333template <>
334void Config::WriteGlobalSetting(const Settings::Setting<float>& setting) {
335 const QString name = QString::fromStdString(setting.GetLabel());
336 const double value = setting.GetValue(global);
337 if (!global) {
338 qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
339 }
340 if (global || !setting.UsingGlobal()) {
341 qt_config->setValue(name + QStringLiteral("/default"),
342 setting.GetValue(global) == setting.GetDefault());
343 qt_config->setValue(name, value);
344 }
345}
346
347template <typename Type>
348void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) {
349 const QString name = QString::fromStdString(setting.GetLabel());
350 const Type& value = setting.GetValue(global);
351 if (!global) {
352 qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
353 }
354 if (global || !setting.UsingGlobal()) {
355 qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
356 qt_config->setValue(name, value);
357 }
358}
359
275void Config::ReadPlayerValue(std::size_t player_index) { 360void Config::ReadPlayerValue(std::size_t player_index) {
276 const QString player_prefix = [this, player_index] { 361 const QString player_prefix = [this, player_index] {
277 if (type == ConfigType::InputProfile) { 362 if (type == ConfigType::InputProfile) {
@@ -395,8 +480,7 @@ void Config::ReadPlayerValue(std::size_t player_index) {
395} 480}
396 481
397void Config::ReadDebugValues() { 482void Config::ReadDebugValues() {
398 Settings::values.debug_pad_enabled = 483 ReadBasicSetting(Settings::values.debug_pad_enabled);
399 ReadSetting(QStringLiteral("debug_pad_enabled"), false).toBool();
400 484
401 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { 485 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
402 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); 486 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
@@ -432,8 +516,7 @@ void Config::ReadDebugValues() {
432} 516}
433 517
434void Config::ReadKeyboardValues() { 518void Config::ReadKeyboardValues() {
435 Settings::values.keyboard_enabled = 519 ReadBasicSetting(Settings::values.keyboard_enabled);
436 ReadSetting(QStringLiteral("keyboard_enabled"), false).toBool();
437 520
438 std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(), 521 std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
439 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); 522 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
@@ -446,7 +529,7 @@ void Config::ReadKeyboardValues() {
446} 529}
447 530
448void Config::ReadMouseValues() { 531void Config::ReadMouseValues() {
449 Settings::values.mouse_enabled = ReadSetting(QStringLiteral("mouse_enabled"), false).toBool(); 532 ReadBasicSetting(Settings::values.mouse_enabled);
450 533
451 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { 534 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
452 const std::string default_param = 535 const std::string default_param =
@@ -481,18 +564,11 @@ void Config::ReadAudioValues() {
481 qt_config->beginGroup(QStringLiteral("Audio")); 564 qt_config->beginGroup(QStringLiteral("Audio"));
482 565
483 if (global) { 566 if (global) {
484 Settings::values.sink_id = 567 ReadBasicSetting(Settings::values.audio_device_id);
485 ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto")) 568 ReadBasicSetting(Settings::values.sink_id);
486 .toString()
487 .toStdString();
488 Settings::values.audio_device_id =
489 ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
490 .toString()
491 .toStdString();
492 } 569 }
493 ReadSettingGlobal(Settings::values.enable_audio_stretching, 570 ReadGlobalSetting(Settings::values.enable_audio_stretching);
494 QStringLiteral("enable_audio_stretching"), true); 571 ReadGlobalSetting(Settings::values.volume);
495 ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"), 1);
496 572
497 qt_config->endGroup(); 573 qt_config->endGroup();
498} 574}
@@ -509,13 +585,11 @@ void Config::ReadControlValues() {
509 ReadTouchscreenValues(); 585 ReadTouchscreenValues();
510 ReadMotionTouchValues(); 586 ReadMotionTouchValues();
511 587
512 Settings::values.emulate_analog_keyboard = 588 ReadBasicSetting(Settings::values.emulate_analog_keyboard);
513 ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
514 Settings::values.mouse_panning = false; 589 Settings::values.mouse_panning = false;
515 Settings::values.mouse_panning_sensitivity = 590 ReadBasicSetting(Settings::values.mouse_panning_sensitivity);
516 ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
517 591
518 ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), true); 592 ReadGlobalSetting(Settings::values.use_docked_mode);
519 593
520 // Disable docked mode if handheld is selected 594 // Disable docked mode if handheld is selected
521 const auto controller_type = Settings::values.players.GetValue()[0].controller_type; 595 const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
@@ -523,11 +597,9 @@ void Config::ReadControlValues() {
523 Settings::values.use_docked_mode.SetValue(false); 597 Settings::values.use_docked_mode.SetValue(false);
524 } 598 }
525 599
526 ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"), 600 ReadGlobalSetting(Settings::values.vibration_enabled);
527 true); 601 ReadGlobalSetting(Settings::values.enable_accurate_vibrations);
528 ReadSettingGlobal(Settings::values.enable_accurate_vibrations, 602 ReadGlobalSetting(Settings::values.motion_enabled);
529 QStringLiteral("enable_accurate_vibrations"), false);
530 ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
531 603
532 qt_config->endGroup(); 604 qt_config->endGroup();
533} 605}
@@ -565,33 +637,19 @@ void Config::ReadMotionTouchValues() {
565 } 637 }
566 qt_config->endArray(); 638 qt_config->endArray();
567 639
568 Settings::values.motion_device = 640 ReadBasicSetting(Settings::values.motion_device);
569 ReadSetting(QStringLiteral("motion_device"), 641 ReadBasicSetting(Settings::values.touch_device);
570 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")) 642 ReadBasicSetting(Settings::values.use_touch_from_button);
571 .toString() 643 ReadBasicSetting(Settings::values.touch_from_button_map_index);
572 .toStdString(); 644 Settings::values.touch_from_button_map_index = std::clamp(
573 Settings::values.touch_device = 645 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
574 ReadSetting(QStringLiteral("touch_device"), 646 ReadBasicSetting(Settings::values.udp_input_servers);
575 QStringLiteral("min_x:100,min_y:50,max_x:1800,max_y:850"))
576 .toString()
577 .toStdString();
578 Settings::values.use_touch_from_button =
579 ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool();
580 Settings::values.touch_from_button_map_index =
581 ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
582 Settings::values.touch_from_button_map_index =
583 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
584 Settings::values.udp_input_servers =
585 ReadSetting(QStringLiteral("udp_input_servers"),
586 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV))
587 .toString()
588 .toStdString();
589} 647}
590 648
591void Config::ReadCoreValues() { 649void Config::ReadCoreValues() {
592 qt_config->beginGroup(QStringLiteral("Core")); 650 qt_config->beginGroup(QStringLiteral("Core"));
593 651
594 ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), true); 652 ReadGlobalSetting(Settings::values.use_multi_core);
595 653
596 qt_config->endGroup(); 654 qt_config->endGroup();
597} 655}
@@ -599,7 +657,7 @@ void Config::ReadCoreValues() {
599void Config::ReadDataStorageValues() { 657void Config::ReadDataStorageValues() {
600 qt_config->beginGroup(QStringLiteral("Data Storage")); 658 qt_config->beginGroup(QStringLiteral("Data Storage"));
601 659
602 Settings::values.use_virtual_sd = ReadSetting(QStringLiteral("use_virtual_sd"), true).toBool(); 660 ReadBasicSetting(Settings::values.use_virtual_sd);
603 FS::SetYuzuPath( 661 FS::SetYuzuPath(
604 FS::YuzuPath::NANDDir, 662 FS::YuzuPath::NANDDir,
605 qt_config 663 qt_config
@@ -628,12 +686,9 @@ void Config::ReadDataStorageValues() {
628 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))) 686 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)))
629 .toString() 687 .toString()
630 .toStdString()); 688 .toStdString());
631 Settings::values.gamecard_inserted = 689 ReadBasicSetting(Settings::values.gamecard_inserted);
632 ReadSetting(QStringLiteral("gamecard_inserted"), false).toBool(); 690 ReadBasicSetting(Settings::values.gamecard_current_game);
633 Settings::values.gamecard_current_game = 691 ReadBasicSetting(Settings::values.gamecard_path);
634 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
635 Settings::values.gamecard_path =
636 ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString();
637 692
638 qt_config->endGroup(); 693 qt_config->endGroup();
639} 694}
@@ -644,34 +699,24 @@ void Config::ReadDebuggingValues() {
644 // Intentionally not using the QT default setting as this is intended to be changed in the ini 699 // Intentionally not using the QT default setting as this is intended to be changed in the ini
645 Settings::values.record_frame_times = 700 Settings::values.record_frame_times =
646 qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); 701 qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
647 Settings::values.program_args = 702 ReadBasicSetting(Settings::values.program_args);
648 ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString(); 703 ReadBasicSetting(Settings::values.dump_exefs);
649 Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool(); 704 ReadBasicSetting(Settings::values.dump_nso);
650 Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool(); 705 ReadBasicSetting(Settings::values.enable_fs_access_log);
651 Settings::values.enable_fs_access_log = 706 ReadBasicSetting(Settings::values.reporting_services);
652 ReadSetting(QStringLiteral("enable_fs_access_log"), false).toBool(); 707 ReadBasicSetting(Settings::values.quest_flag);
653 Settings::values.reporting_services = 708 ReadBasicSetting(Settings::values.disable_macro_jit);
654 ReadSetting(QStringLiteral("reporting_services"), false).toBool(); 709 ReadBasicSetting(Settings::values.extended_logging);
655 Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); 710 ReadBasicSetting(Settings::values.use_debug_asserts);
656 Settings::values.disable_macro_jit = 711 ReadBasicSetting(Settings::values.use_auto_stub);
657 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
658 Settings::values.extended_logging =
659 ReadSetting(QStringLiteral("extended_logging"), false).toBool();
660 Settings::values.use_debug_asserts =
661 ReadSetting(QStringLiteral("use_debug_asserts"), false).toBool();
662 Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
663 712
664 qt_config->endGroup(); 713 qt_config->endGroup();
665} 714}
666 715
667void Config::ReadServiceValues() { 716void Config::ReadServiceValues() {
668 qt_config->beginGroup(QStringLiteral("Services")); 717 qt_config->beginGroup(QStringLiteral("Services"));
669 Settings::values.bcat_backend = 718 ReadBasicSetting(Settings::values.bcat_backend);
670 ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("none")) 719 ReadBasicSetting(Settings::values.bcat_boxcat_local);
671 .toString()
672 .toStdString();
673 Settings::values.bcat_boxcat_local =
674 ReadSetting(QStringLiteral("bcat_boxcat_local"), false).toBool();
675 qt_config->endGroup(); 720 qt_config->endGroup();
676} 721}
677 722
@@ -697,11 +742,8 @@ void Config::ReadDisabledAddOnValues() {
697void Config::ReadMiscellaneousValues() { 742void Config::ReadMiscellaneousValues() {
698 qt_config->beginGroup(QStringLiteral("Miscellaneous")); 743 qt_config->beginGroup(QStringLiteral("Miscellaneous"));
699 744
700 Settings::values.log_filter = 745 ReadBasicSetting(Settings::values.log_filter);
701 ReadSetting(QStringLiteral("log_filter"), QStringLiteral("*:Info")) 746 ReadBasicSetting(Settings::values.use_dev_keys);
702 .toString()
703 .toStdString();
704 Settings::values.use_dev_keys = ReadSetting(QStringLiteral("use_dev_keys"), false).toBool();
705 747
706 qt_config->endGroup(); 748 qt_config->endGroup();
707} 749}
@@ -751,38 +793,31 @@ void Config::ReadPathValues() {
751void Config::ReadCpuValues() { 793void Config::ReadCpuValues() {
752 qt_config->beginGroup(QStringLiteral("Cpu")); 794 qt_config->beginGroup(QStringLiteral("Cpu"));
753 795
754 ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0); 796 ReadBasicSetting(Settings::values.cpu_accuracy_first_time);
797 if (Settings::values.cpu_accuracy_first_time) {
798 Settings::values.cpu_accuracy.SetValue(Settings::values.cpu_accuracy.GetDefault());
799 Settings::values.cpu_accuracy_first_time.SetValue(false);
800 } else {
801 ReadGlobalSetting(Settings::values.cpu_accuracy);
802 }
755 803
756 ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma, 804 ReadGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
757 QStringLiteral("cpuopt_unsafe_unfuse_fma"), true); 805 ReadGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
758 ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error, 806 ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
759 QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true); 807 ReadGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
760 ReadSettingGlobal(Settings::values.cpuopt_unsafe_ignore_standard_fpcr, 808 ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
761 QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"), true);
762 ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
763 QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
764 ReadSettingGlobal(Settings::values.cpuopt_unsafe_fastmem_check,
765 QStringLiteral("cpuopt_unsafe_fastmem_check"), true);
766 809
767 if (global) { 810 if (global) {
768 Settings::values.cpuopt_page_tables = 811 ReadBasicSetting(Settings::values.cpu_debug_mode);
769 ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool(); 812 ReadBasicSetting(Settings::values.cpuopt_page_tables);
770 Settings::values.cpuopt_block_linking = 813 ReadBasicSetting(Settings::values.cpuopt_block_linking);
771 ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool(); 814 ReadBasicSetting(Settings::values.cpuopt_return_stack_buffer);
772 Settings::values.cpuopt_return_stack_buffer = 815 ReadBasicSetting(Settings::values.cpuopt_fast_dispatcher);
773 ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool(); 816 ReadBasicSetting(Settings::values.cpuopt_context_elimination);
774 Settings::values.cpuopt_fast_dispatcher = 817 ReadBasicSetting(Settings::values.cpuopt_const_prop);
775 ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool(); 818 ReadBasicSetting(Settings::values.cpuopt_misc_ir);
776 Settings::values.cpuopt_context_elimination = 819 ReadBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
777 ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool(); 820 ReadBasicSetting(Settings::values.cpuopt_fastmem);
778 Settings::values.cpuopt_const_prop =
779 ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool();
780 Settings::values.cpuopt_misc_ir =
781 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
782 Settings::values.cpuopt_reduce_misalign_checks =
783 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
784 Settings::values.cpuopt_fastmem =
785 ReadSetting(QStringLiteral("cpuopt_fastmem"), true).toBool();
786 } 821 }
787 822
788 qt_config->endGroup(); 823 qt_config->endGroup();
@@ -791,41 +826,30 @@ void Config::ReadCpuValues() {
791void Config::ReadRendererValues() { 826void Config::ReadRendererValues() {
792 qt_config->beginGroup(QStringLiteral("Renderer")); 827 qt_config->beginGroup(QStringLiteral("Renderer"));
793 828
794 ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0); 829 ReadGlobalSetting(Settings::values.renderer_backend);
795 ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false); 830 ReadGlobalSetting(Settings::values.vulkan_device);
796 ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0); 831 ReadGlobalSetting(Settings::values.fullscreen_mode);
797#ifdef _WIN32 832 ReadGlobalSetting(Settings::values.aspect_ratio);
798 ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0); 833 ReadGlobalSetting(Settings::values.max_anisotropy);
799#else 834 ReadGlobalSetting(Settings::values.use_frame_limit);
800 // *nix platforms may have issues with the borderless windowed fullscreen mode. 835 ReadGlobalSetting(Settings::values.frame_limit);
801 // Default to exclusive fullscreen on these platforms for now. 836 ReadGlobalSetting(Settings::values.use_disk_shader_cache);
802 ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1); 837 ReadGlobalSetting(Settings::values.gpu_accuracy);
803#endif 838 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
804 ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0); 839 ReadGlobalSetting(Settings::values.use_nvdec_emulation);
805 ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0); 840 ReadGlobalSetting(Settings::values.accelerate_astc);
806 ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true); 841 ReadGlobalSetting(Settings::values.use_vsync);
807 ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"), 100); 842 ReadGlobalSetting(Settings::values.use_assembly_shaders);
808 ReadSettingGlobal(Settings::values.use_disk_shader_cache, 843 ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
809 QStringLiteral("use_disk_shader_cache"), true); 844 ReadGlobalSetting(Settings::values.use_fast_gpu_time);
810 ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 1); 845 ReadGlobalSetting(Settings::values.use_caches_gc);
811 ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation, 846 ReadGlobalSetting(Settings::values.bg_red);
812 QStringLiteral("use_asynchronous_gpu_emulation"), true); 847 ReadGlobalSetting(Settings::values.bg_green);
813 ReadSettingGlobal(Settings::values.use_nvdec_emulation, QStringLiteral("use_nvdec_emulation"), 848 ReadGlobalSetting(Settings::values.bg_blue);
814 true); 849
815 ReadSettingGlobal(Settings::values.accelerate_astc, QStringLiteral("accelerate_astc"), true); 850 if (global) {
816 ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true); 851 ReadBasicSetting(Settings::values.renderer_debug);
817 ReadSettingGlobal(Settings::values.disable_fps_limit, QStringLiteral("disable_fps_limit"), 852 }
818 false);
819 ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
820 false);
821 ReadSettingGlobal(Settings::values.use_asynchronous_shaders,
822 QStringLiteral("use_asynchronous_shaders"), false);
823 ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
824 true);
825 ReadSettingGlobal(Settings::values.use_caches_gc, QStringLiteral("use_caches_gc"), false);
826 ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
827 ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
828 ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
829 853
830 qt_config->endGroup(); 854 qt_config->endGroup();
831} 855}
@@ -870,15 +894,15 @@ void Config::ReadShortcutValues() {
870void Config::ReadSystemValues() { 894void Config::ReadSystemValues() {
871 qt_config->beginGroup(QStringLiteral("System")); 895 qt_config->beginGroup(QStringLiteral("System"));
872 896
873 ReadSettingGlobal(Settings::values.current_user, QStringLiteral("current_user"), 0); 897 ReadBasicSetting(Settings::values.current_user);
874 Settings::values.current_user = 898 Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
875 std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1); 899 Service::Account::MAX_USERS - 1);
876 900
877 ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"), 1); 901 ReadGlobalSetting(Settings::values.language_index);
878 902
879 ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"), 1); 903 ReadGlobalSetting(Settings::values.region_index);
880 904
881 ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"), 0); 905 ReadGlobalSetting(Settings::values.time_zone_index);
882 906
883 bool rng_seed_enabled; 907 bool rng_seed_enabled;
884 ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false); 908 ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
@@ -904,7 +928,7 @@ void Config::ReadSystemValues() {
904 } 928 }
905 } 929 }
906 930
907 ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1); 931 ReadGlobalSetting(Settings::values.sound_index);
908 932
909 qt_config->endGroup(); 933 qt_config->endGroup();
910} 934}
@@ -915,10 +939,8 @@ void Config::ReadUIValues() {
915 UISettings::values.theme = 939 UISettings::values.theme =
916 ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second)) 940 ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second))
917 .toString(); 941 .toString();
918 UISettings::values.enable_discord_presence = 942 ReadBasicSetting(UISettings::values.enable_discord_presence);
919 ReadSetting(QStringLiteral("enable_discord_presence"), true).toBool(); 943 ReadBasicSetting(UISettings::values.select_user_on_boot);
920 UISettings::values.select_user_on_boot =
921 ReadSetting(QStringLiteral("select_user_on_boot"), false).toBool();
922 944
923 ReadUIGamelistValues(); 945 ReadUIGamelistValues();
924 ReadUILayoutValues(); 946 ReadUILayoutValues();
@@ -926,24 +948,17 @@ void Config::ReadUIValues() {
926 ReadScreenshotValues(); 948 ReadScreenshotValues();
927 ReadShortcutValues(); 949 ReadShortcutValues();
928 950
929 UISettings::values.single_window_mode = 951 ReadBasicSetting(UISettings::values.single_window_mode);
930 ReadSetting(QStringLiteral("singleWindowMode"), true).toBool(); 952 ReadBasicSetting(UISettings::values.fullscreen);
931 UISettings::values.fullscreen = ReadSetting(QStringLiteral("fullscreen"), false).toBool(); 953 ReadBasicSetting(UISettings::values.display_titlebar);
932 UISettings::values.display_titlebar = 954 ReadBasicSetting(UISettings::values.show_filter_bar);
933 ReadSetting(QStringLiteral("displayTitleBars"), true).toBool(); 955 ReadBasicSetting(UISettings::values.show_status_bar);
934 UISettings::values.show_filter_bar = 956 ReadBasicSetting(UISettings::values.confirm_before_closing);
935 ReadSetting(QStringLiteral("showFilterBar"), true).toBool(); 957 ReadBasicSetting(UISettings::values.first_start);
936 UISettings::values.show_status_bar = 958 ReadBasicSetting(UISettings::values.callout_flags);
937 ReadSetting(QStringLiteral("showStatusBar"), true).toBool(); 959 ReadBasicSetting(UISettings::values.show_console);
938 UISettings::values.confirm_before_closing = 960 ReadBasicSetting(UISettings::values.pause_when_in_background);
939 ReadSetting(QStringLiteral("confirmClose"), true).toBool(); 961 ReadBasicSetting(UISettings::values.hide_mouse);
940 UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool();
941 UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt();
942 UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool();
943 UISettings::values.pause_when_in_background =
944 ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool();
945 UISettings::values.hide_mouse =
946 ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool();
947 962
948 qt_config->endGroup(); 963 qt_config->endGroup();
949} 964}
@@ -951,12 +966,11 @@ void Config::ReadUIValues() {
951void Config::ReadUIGamelistValues() { 966void Config::ReadUIGamelistValues() {
952 qt_config->beginGroup(QStringLiteral("UIGameList")); 967 qt_config->beginGroup(QStringLiteral("UIGameList"));
953 968
954 UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool(); 969 ReadBasicSetting(UISettings::values.show_add_ons);
955 UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt(); 970 ReadBasicSetting(UISettings::values.icon_size);
956 UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt(); 971 ReadBasicSetting(UISettings::values.row_1_text_id);
957 UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt(); 972 ReadBasicSetting(UISettings::values.row_2_text_id);
958 UISettings::values.cache_game_list = 973 ReadBasicSetting(UISettings::values.cache_game_list);
959 ReadSetting(QStringLiteral("cache_game_list"), true).toBool();
960 const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); 974 const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites"));
961 for (int i = 0; i < favorites_size; i++) { 975 for (int i = 0; i < favorites_size; i++) {
962 qt_config->setArrayIndex(i); 976 qt_config->setArrayIndex(i);
@@ -979,8 +993,7 @@ void Config::ReadUILayoutValues() {
979 ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray(); 993 ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray();
980 UISettings::values.microprofile_geometry = 994 UISettings::values.microprofile_geometry =
981 ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray(); 995 ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray();
982 UISettings::values.microprofile_visible = 996 ReadBasicSetting(UISettings::values.microprofile_visible);
983 ReadSetting(QStringLiteral("microProfileDialogVisible"), false).toBool();
984 997
985 qt_config->endGroup(); 998 qt_config->endGroup();
986} 999}
@@ -988,16 +1001,10 @@ void Config::ReadUILayoutValues() {
988void Config::ReadWebServiceValues() { 1001void Config::ReadWebServiceValues() {
989 qt_config->beginGroup(QStringLiteral("WebService")); 1002 qt_config->beginGroup(QStringLiteral("WebService"));
990 1003
991 Settings::values.enable_telemetry = 1004 ReadBasicSetting(Settings::values.enable_telemetry);
992 ReadSetting(QStringLiteral("enable_telemetry"), true).toBool(); 1005 ReadBasicSetting(Settings::values.web_api_url);
993 Settings::values.web_api_url = 1006 ReadBasicSetting(Settings::values.yuzu_username);
994 ReadSetting(QStringLiteral("web_api_url"), QStringLiteral("https://api.yuzu-emu.org")) 1007 ReadBasicSetting(Settings::values.yuzu_token);
995 .toString()
996 .toStdString();
997 Settings::values.yuzu_username =
998 ReadSetting(QStringLiteral("yuzu_username")).toString().toStdString();
999 Settings::values.yuzu_token =
1000 ReadSetting(QStringLiteral("yuzu_token")).toString().toStdString();
1001 1008
1002 qt_config->endGroup(); 1009 qt_config->endGroup();
1003} 1010}
@@ -1083,7 +1090,7 @@ void Config::SavePlayerValue(std::size_t player_index) {
1083} 1090}
1084 1091
1085void Config::SaveDebugValues() { 1092void Config::SaveDebugValues() {
1086 WriteSetting(QStringLiteral("debug_pad_enabled"), Settings::values.debug_pad_enabled, false); 1093 WriteBasicSetting(Settings::values.debug_pad_enabled);
1087 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { 1094 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
1088 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); 1095 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
1089 WriteSetting(QStringLiteral("debug_pad_") + 1096 WriteSetting(QStringLiteral("debug_pad_") +
@@ -1103,7 +1110,7 @@ void Config::SaveDebugValues() {
1103} 1110}
1104 1111
1105void Config::SaveMouseValues() { 1112void Config::SaveMouseValues() {
1106 WriteSetting(QStringLiteral("mouse_enabled"), Settings::values.mouse_enabled, false); 1113 WriteBasicSetting(Settings::values.mouse_enabled);
1107 1114
1108 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { 1115 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
1109 const std::string default_param = 1116 const std::string default_param =
@@ -1126,19 +1133,11 @@ void Config::SaveTouchscreenValues() {
1126} 1133}
1127 1134
1128void Config::SaveMotionTouchValues() { 1135void Config::SaveMotionTouchValues() {
1129 WriteSetting(QStringLiteral("motion_device"), 1136 WriteBasicSetting(Settings::values.motion_device);
1130 QString::fromStdString(Settings::values.motion_device), 1137 WriteBasicSetting(Settings::values.touch_device);
1131 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")); 1138 WriteBasicSetting(Settings::values.use_touch_from_button);
1132 WriteSetting(QStringLiteral("touch_device"), 1139 WriteBasicSetting(Settings::values.touch_from_button_map_index);
1133 QString::fromStdString(Settings::values.touch_device), 1140 WriteBasicSetting(Settings::values.udp_input_servers);
1134 QStringLiteral("engine:emu_window"));
1135 WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button,
1136 false);
1137 WriteSetting(QStringLiteral("touch_from_button_map"),
1138 Settings::values.touch_from_button_map_index, 0);
1139 WriteSetting(QStringLiteral("udp_input_servers"),
1140 QString::fromStdString(Settings::values.udp_input_servers),
1141 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV));
1142 1141
1143 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); 1142 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
1144 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { 1143 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
@@ -1181,15 +1180,11 @@ void Config::SaveAudioValues() {
1181 qt_config->beginGroup(QStringLiteral("Audio")); 1180 qt_config->beginGroup(QStringLiteral("Audio"));
1182 1181
1183 if (global) { 1182 if (global) {
1184 WriteSetting(QStringLiteral("output_engine"), 1183 WriteBasicSetting(Settings::values.sink_id);
1185 QString::fromStdString(Settings::values.sink_id), QStringLiteral("auto")); 1184 WriteBasicSetting(Settings::values.audio_device_id);
1186 WriteSetting(QStringLiteral("output_device"),
1187 QString::fromStdString(Settings::values.audio_device_id),
1188 QStringLiteral("auto"));
1189 } 1185 }
1190 WriteSettingGlobal(QStringLiteral("enable_audio_stretching"), 1186 WriteGlobalSetting(Settings::values.enable_audio_stretching);
1191 Settings::values.enable_audio_stretching, true); 1187 WriteGlobalSetting(Settings::values.volume);
1192 WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume, 1.0f);
1193 1188
1194 qt_config->endGroup(); 1189 qt_config->endGroup();
1195} 1190}
@@ -1205,30 +1200,21 @@ void Config::SaveControlValues() {
1205 SaveTouchscreenValues(); 1200 SaveTouchscreenValues();
1206 SaveMotionTouchValues(); 1201 SaveMotionTouchValues();
1207 1202
1208 WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, true); 1203 WriteGlobalSetting(Settings::values.use_docked_mode);
1209 WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, 1204 WriteGlobalSetting(Settings::values.vibration_enabled);
1210 true); 1205 WriteGlobalSetting(Settings::values.enable_accurate_vibrations);
1211 WriteSettingGlobal(QStringLiteral("enable_accurate_vibrations"), 1206 WriteGlobalSetting(Settings::values.motion_enabled);
1212 Settings::values.enable_accurate_vibrations, false); 1207 WriteBasicSetting(Settings::values.keyboard_enabled);
1213 WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true); 1208 WriteBasicSetting(Settings::values.emulate_analog_keyboard);
1214 WriteSetting(QStringLiteral("motion_device"), 1209 WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
1215 QString::fromStdString(Settings::values.motion_device), 1210
1216 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
1217 WriteSetting(QStringLiteral("touch_device"),
1218 QString::fromStdString(Settings::values.touch_device),
1219 QStringLiteral("engine:emu_window"));
1220 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
1221 WriteSetting(QStringLiteral("emulate_analog_keyboard"),
1222 Settings::values.emulate_analog_keyboard, false);
1223 WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
1224 Settings::values.mouse_panning_sensitivity, 1.0f);
1225 qt_config->endGroup(); 1211 qt_config->endGroup();
1226} 1212}
1227 1213
1228void Config::SaveCoreValues() { 1214void Config::SaveCoreValues() {
1229 qt_config->beginGroup(QStringLiteral("Core")); 1215 qt_config->beginGroup(QStringLiteral("Core"));
1230 1216
1231 WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, true); 1217 WriteGlobalSetting(Settings::values.use_multi_core);
1232 1218
1233 qt_config->endGroup(); 1219 qt_config->endGroup();
1234} 1220}
@@ -1236,7 +1222,7 @@ void Config::SaveCoreValues() {
1236void Config::SaveDataStorageValues() { 1222void Config::SaveDataStorageValues() {
1237 qt_config->beginGroup(QStringLiteral("Data Storage")); 1223 qt_config->beginGroup(QStringLiteral("Data Storage"));
1238 1224
1239 WriteSetting(QStringLiteral("use_virtual_sd"), Settings::values.use_virtual_sd, true); 1225 WriteBasicSetting(Settings::values.use_virtual_sd);
1240 WriteSetting(QStringLiteral("nand_directory"), 1226 WriteSetting(QStringLiteral("nand_directory"),
1241 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)), 1227 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)),
1242 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); 1228 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -1249,11 +1235,9 @@ void Config::SaveDataStorageValues() {
1249 WriteSetting(QStringLiteral("dump_directory"), 1235 WriteSetting(QStringLiteral("dump_directory"),
1250 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)), 1236 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)),
1251 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); 1237 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
1252 WriteSetting(QStringLiteral("gamecard_inserted"), Settings::values.gamecard_inserted, false); 1238 WriteBasicSetting(Settings::values.gamecard_inserted);
1253 WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game, 1239 WriteBasicSetting(Settings::values.gamecard_current_game);
1254 false); 1240 WriteBasicSetting(Settings::values.gamecard_path);
1255 WriteSetting(QStringLiteral("gamecard_path"),
1256 QString::fromStdString(Settings::values.gamecard_path), QString{});
1257 1241
1258 qt_config->endGroup(); 1242 qt_config->endGroup();
1259} 1243}
@@ -1263,24 +1247,23 @@ void Config::SaveDebuggingValues() {
1263 1247
1264 // Intentionally not using the QT default setting as this is intended to be changed in the ini 1248 // Intentionally not using the QT default setting as this is intended to be changed in the ini
1265 qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); 1249 qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
1266 WriteSetting(QStringLiteral("program_args"), 1250 WriteBasicSetting(Settings::values.program_args);
1267 QString::fromStdString(Settings::values.program_args), QString{}); 1251 WriteBasicSetting(Settings::values.dump_exefs);
1268 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); 1252 WriteBasicSetting(Settings::values.dump_nso);
1269 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); 1253 WriteBasicSetting(Settings::values.enable_fs_access_log);
1270 WriteSetting(QStringLiteral("enable_fs_access_log"), Settings::values.enable_fs_access_log, 1254 WriteBasicSetting(Settings::values.quest_flag);
1271 false); 1255 WriteBasicSetting(Settings::values.use_debug_asserts);
1272 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); 1256 WriteBasicSetting(Settings::values.disable_macro_jit);
1273 WriteSetting(QStringLiteral("use_debug_asserts"), Settings::values.use_debug_asserts, false);
1274 WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
1275 1257
1276 qt_config->endGroup(); 1258 qt_config->endGroup();
1277} 1259}
1278 1260
1279void Config::SaveServiceValues() { 1261void Config::SaveServiceValues() {
1280 qt_config->beginGroup(QStringLiteral("Services")); 1262 qt_config->beginGroup(QStringLiteral("Services"));
1281 WriteSetting(QStringLiteral("bcat_backend"), 1263
1282 QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("none")); 1264 WriteBasicSetting(Settings::values.bcat_backend);
1283 WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false); 1265 WriteBasicSetting(Settings::values.bcat_boxcat_local);
1266
1284 qt_config->endGroup(); 1267 qt_config->endGroup();
1285} 1268}
1286 1269
@@ -1306,9 +1289,8 @@ void Config::SaveDisabledAddOnValues() {
1306void Config::SaveMiscellaneousValues() { 1289void Config::SaveMiscellaneousValues() {
1307 qt_config->beginGroup(QStringLiteral("Miscellaneous")); 1290 qt_config->beginGroup(QStringLiteral("Miscellaneous"));
1308 1291
1309 WriteSetting(QStringLiteral("log_filter"), QString::fromStdString(Settings::values.log_filter), 1292 WriteBasicSetting(Settings::values.log_filter);
1310 QStringLiteral("*:Info")); 1293 WriteBasicSetting(Settings::values.use_dev_keys);
1311 WriteSetting(QStringLiteral("use_dev_keys"), Settings::values.use_dev_keys, false);
1312 1294
1313 qt_config->endGroup(); 1295 qt_config->endGroup();
1314} 1296}
@@ -1336,38 +1318,29 @@ void Config::SavePathValues() {
1336void Config::SaveCpuValues() { 1318void Config::SaveCpuValues() {
1337 qt_config->beginGroup(QStringLiteral("Cpu")); 1319 qt_config->beginGroup(QStringLiteral("Cpu"));
1338 1320
1339 WriteSettingGlobal(QStringLiteral("cpu_accuracy"), 1321 WriteBasicSetting(Settings::values.cpu_accuracy_first_time);
1340 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)), 1322 WriteSetting(QStringLiteral("cpu_accuracy"),
1341 Settings::values.cpu_accuracy.UsingGlobal(), 1323 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
1342 static_cast<u32>(Settings::CPUAccuracy::Accurate)); 1324 static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()),
1343 1325 Settings::values.cpu_accuracy.UsingGlobal());
1344 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"), 1326
1345 Settings::values.cpuopt_unsafe_unfuse_fma, true); 1327 WriteGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
1346 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), 1328 WriteGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
1347 Settings::values.cpuopt_unsafe_reduce_fp_error, true); 1329 WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
1348 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"), 1330 WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
1349 Settings::values.cpuopt_unsafe_ignore_standard_fpcr, true); 1331 WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
1350 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
1351 Settings::values.cpuopt_unsafe_inaccurate_nan, true);
1352 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_fastmem_check"),
1353 Settings::values.cpuopt_unsafe_fastmem_check, true);
1354 1332
1355 if (global) { 1333 if (global) {
1356 WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables, 1334 WriteBasicSetting(Settings::values.cpu_debug_mode);
1357 true); 1335 WriteBasicSetting(Settings::values.cpuopt_page_tables);
1358 WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking, 1336 WriteBasicSetting(Settings::values.cpuopt_block_linking);
1359 true); 1337 WriteBasicSetting(Settings::values.cpuopt_return_stack_buffer);
1360 WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"), 1338 WriteBasicSetting(Settings::values.cpuopt_fast_dispatcher);
1361 Settings::values.cpuopt_return_stack_buffer, true); 1339 WriteBasicSetting(Settings::values.cpuopt_context_elimination);
1362 WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"), 1340 WriteBasicSetting(Settings::values.cpuopt_const_prop);
1363 Settings::values.cpuopt_fast_dispatcher, true); 1341 WriteBasicSetting(Settings::values.cpuopt_misc_ir);
1364 WriteSetting(QStringLiteral("cpuopt_context_elimination"), 1342 WriteBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
1365 Settings::values.cpuopt_context_elimination, true); 1343 WriteBasicSetting(Settings::values.cpuopt_fastmem);
1366 WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true);
1367 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
1368 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
1369 Settings::values.cpuopt_reduce_misalign_checks, true);
1370 WriteSetting(QStringLiteral("cpuopt_fastmem"), Settings::values.cpuopt_fastmem, true);
1371 } 1344 }
1372 1345
1373 qt_config->endGroup(); 1346 qt_config->endGroup();
@@ -1376,46 +1349,36 @@ void Config::SaveCpuValues() {
1376void Config::SaveRendererValues() { 1349void Config::SaveRendererValues() {
1377 qt_config->beginGroup(QStringLiteral("Renderer")); 1350 qt_config->beginGroup(QStringLiteral("Renderer"));
1378 1351
1379 WriteSettingGlobal(QStringLiteral("backend"), 1352 WriteSetting(QString::fromStdString(Settings::values.renderer_backend.GetLabel()),
1380 static_cast<int>(Settings::values.renderer_backend.GetValue(global)), 1353 static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
1381 Settings::values.renderer_backend.UsingGlobal(), 0); 1354 static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
1382 WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false); 1355 Settings::values.renderer_backend.UsingGlobal());
1383 WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0); 1356 WriteGlobalSetting(Settings::values.vulkan_device);
1384#ifdef _WIN32 1357 WriteGlobalSetting(Settings::values.fullscreen_mode);
1385 WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0); 1358 WriteGlobalSetting(Settings::values.aspect_ratio);
1386#else 1359 WriteGlobalSetting(Settings::values.max_anisotropy);
1387 // *nix platforms may have issues with the borderless windowed fullscreen mode. 1360 WriteGlobalSetting(Settings::values.use_frame_limit);
1388 // Default to exclusive fullscreen on these platforms for now. 1361 WriteGlobalSetting(Settings::values.frame_limit);
1389 WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1); 1362 WriteGlobalSetting(Settings::values.use_disk_shader_cache);
1390#endif 1363 WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
1391 WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0); 1364 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
1392 WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0); 1365 static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()),
1393 WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true); 1366 Settings::values.gpu_accuracy.UsingGlobal());
1394 WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100); 1367 WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
1395 WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"), 1368 WriteGlobalSetting(Settings::values.use_nvdec_emulation);
1396 Settings::values.use_disk_shader_cache, true); 1369 WriteGlobalSetting(Settings::values.accelerate_astc);
1397 WriteSettingGlobal(QStringLiteral("gpu_accuracy"), 1370 WriteGlobalSetting(Settings::values.use_vsync);
1398 static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)), 1371 WriteGlobalSetting(Settings::values.use_assembly_shaders);
1399 Settings::values.gpu_accuracy.UsingGlobal(), 1); 1372 WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
1400 WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"), 1373 WriteGlobalSetting(Settings::values.use_fast_gpu_time);
1401 Settings::values.use_asynchronous_gpu_emulation, true); 1374 WriteGlobalSetting(Settings::values.use_caches_gc);
1402 WriteSettingGlobal(QStringLiteral("use_nvdec_emulation"), Settings::values.use_nvdec_emulation, 1375 WriteGlobalSetting(Settings::values.bg_red);
1403 true); 1376 WriteGlobalSetting(Settings::values.bg_green);
1404 WriteSettingGlobal(QStringLiteral("accelerate_astc"), Settings::values.accelerate_astc, true); 1377 WriteGlobalSetting(Settings::values.bg_blue);
1405 WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true); 1378
1406 WriteSettingGlobal(QStringLiteral("disable_fps_limit"), Settings::values.disable_fps_limit, 1379 if (global) {
1407 false); 1380 WriteBasicSetting(Settings::values.renderer_debug);
1408 WriteSettingGlobal(QStringLiteral("use_assembly_shaders"), 1381 }
1409 Settings::values.use_assembly_shaders, false);
1410 WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"),
1411 Settings::values.use_asynchronous_shaders, false);
1412 WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
1413 true);
1414 WriteSettingGlobal(QStringLiteral("use_caches_gc"), Settings::values.use_caches_gc, false);
1415 // Cast to double because Qt's written float values are not human-readable
1416 WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
1417 WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
1418 WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue, 0.0);
1419 1382
1420 qt_config->endGroup(); 1383 qt_config->endGroup();
1421} 1384}
@@ -1423,8 +1386,7 @@ void Config::SaveRendererValues() {
1423void Config::SaveScreenshotValues() { 1386void Config::SaveScreenshotValues() {
1424 qt_config->beginGroup(QStringLiteral("Screenshots")); 1387 qt_config->beginGroup(QStringLiteral("Screenshots"));
1425 1388
1426 WriteSetting(QStringLiteral("enable_screenshot_save_as"), 1389 WriteBasicSetting(UISettings::values.enable_screenshot_save_as);
1427 UISettings::values.enable_screenshot_save_as);
1428 WriteSetting(QStringLiteral("screenshot_path"), 1390 WriteSetting(QStringLiteral("screenshot_path"),
1429 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))); 1391 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)));
1430 1392
@@ -1454,17 +1416,16 @@ void Config::SaveShortcutValues() {
1454void Config::SaveSystemValues() { 1416void Config::SaveSystemValues() {
1455 qt_config->beginGroup(QStringLiteral("System")); 1417 qt_config->beginGroup(QStringLiteral("System"));
1456 1418
1457 WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0); 1419 WriteBasicSetting(Settings::values.current_user);
1458 WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index, 1); 1420 WriteGlobalSetting(Settings::values.language_index);
1459 WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index, 1); 1421 WriteGlobalSetting(Settings::values.region_index);
1460 WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0); 1422 WriteGlobalSetting(Settings::values.time_zone_index);
1461 1423
1462 WriteSettingGlobal(QStringLiteral("rng_seed_enabled"), 1424 WriteSetting(QStringLiteral("rng_seed_enabled"),
1463 Settings::values.rng_seed.GetValue(global).has_value(), 1425 Settings::values.rng_seed.GetValue(global).has_value(), false,
1464 Settings::values.rng_seed.UsingGlobal(), false); 1426 Settings::values.rng_seed.UsingGlobal());
1465 WriteSettingGlobal(QStringLiteral("rng_seed"), 1427 WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0),
1466 Settings::values.rng_seed.GetValue(global).value_or(0), 1428 0, Settings::values.rng_seed.UsingGlobal());
1467 Settings::values.rng_seed.UsingGlobal(), 0);
1468 1429
1469 if (global) { 1430 if (global) {
1470 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(), 1431 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
@@ -1475,7 +1436,7 @@ void Config::SaveSystemValues() {
1475 0); 1436 0);
1476 } 1437 }
1477 1438
1478 WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1); 1439 WriteGlobalSetting(Settings::values.sound_index);
1479 1440
1480 qt_config->endGroup(); 1441 qt_config->endGroup();
1481} 1442}
@@ -1485,10 +1446,8 @@ void Config::SaveUIValues() {
1485 1446
1486 WriteSetting(QStringLiteral("theme"), UISettings::values.theme, 1447 WriteSetting(QStringLiteral("theme"), UISettings::values.theme,
1487 QString::fromUtf8(UISettings::themes[0].second)); 1448 QString::fromUtf8(UISettings::themes[0].second));
1488 WriteSetting(QStringLiteral("enable_discord_presence"), 1449 WriteBasicSetting(UISettings::values.enable_discord_presence);
1489 UISettings::values.enable_discord_presence, true); 1450 WriteBasicSetting(UISettings::values.select_user_on_boot);
1490 WriteSetting(QStringLiteral("select_user_on_boot"), UISettings::values.select_user_on_boot,
1491 false);
1492 1451
1493 SaveUIGamelistValues(); 1452 SaveUIGamelistValues();
1494 SaveUILayoutValues(); 1453 SaveUILayoutValues();
@@ -1496,18 +1455,17 @@ void Config::SaveUIValues() {
1496 SaveScreenshotValues(); 1455 SaveScreenshotValues();
1497 SaveShortcutValues(); 1456 SaveShortcutValues();
1498 1457
1499 WriteSetting(QStringLiteral("singleWindowMode"), UISettings::values.single_window_mode, true); 1458 WriteBasicSetting(UISettings::values.single_window_mode);
1500 WriteSetting(QStringLiteral("fullscreen"), UISettings::values.fullscreen, false); 1459 WriteBasicSetting(UISettings::values.fullscreen);
1501 WriteSetting(QStringLiteral("displayTitleBars"), UISettings::values.display_titlebar, true); 1460 WriteBasicSetting(UISettings::values.display_titlebar);
1502 WriteSetting(QStringLiteral("showFilterBar"), UISettings::values.show_filter_bar, true); 1461 WriteBasicSetting(UISettings::values.show_filter_bar);
1503 WriteSetting(QStringLiteral("showStatusBar"), UISettings::values.show_status_bar, true); 1462 WriteBasicSetting(UISettings::values.show_status_bar);
1504 WriteSetting(QStringLiteral("confirmClose"), UISettings::values.confirm_before_closing, true); 1463 WriteBasicSetting(UISettings::values.confirm_before_closing);
1505 WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true); 1464 WriteBasicSetting(UISettings::values.first_start);
1506 WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0); 1465 WriteBasicSetting(UISettings::values.callout_flags);
1507 WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false); 1466 WriteBasicSetting(UISettings::values.show_console);
1508 WriteSetting(QStringLiteral("pauseWhenInBackground"), 1467 WriteBasicSetting(UISettings::values.pause_when_in_background);
1509 UISettings::values.pause_when_in_background, false); 1468 WriteBasicSetting(UISettings::values.hide_mouse);
1510 WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false);
1511 1469
1512 qt_config->endGroup(); 1470 qt_config->endGroup();
1513} 1471}
@@ -1515,11 +1473,11 @@ void Config::SaveUIValues() {
1515void Config::SaveUIGamelistValues() { 1473void Config::SaveUIGamelistValues() {
1516 qt_config->beginGroup(QStringLiteral("UIGameList")); 1474 qt_config->beginGroup(QStringLiteral("UIGameList"));
1517 1475
1518 WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true); 1476 WriteBasicSetting(UISettings::values.show_add_ons);
1519 WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64); 1477 WriteBasicSetting(UISettings::values.icon_size);
1520 WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3); 1478 WriteBasicSetting(UISettings::values.row_1_text_id);
1521 WriteSetting(QStringLiteral("row_2_text_id"), UISettings::values.row_2_text_id, 2); 1479 WriteBasicSetting(UISettings::values.row_2_text_id);
1522 WriteSetting(QStringLiteral("cache_game_list"), UISettings::values.cache_game_list, true); 1480 WriteBasicSetting(UISettings::values.cache_game_list);
1523 qt_config->beginWriteArray(QStringLiteral("favorites")); 1481 qt_config->beginWriteArray(QStringLiteral("favorites"));
1524 for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { 1482 for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
1525 qt_config->setArrayIndex(i); 1483 qt_config->setArrayIndex(i);
@@ -1540,8 +1498,7 @@ void Config::SaveUILayoutValues() {
1540 WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state); 1498 WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state);
1541 WriteSetting(QStringLiteral("microProfileDialogGeometry"), 1499 WriteSetting(QStringLiteral("microProfileDialogGeometry"),
1542 UISettings::values.microprofile_geometry); 1500 UISettings::values.microprofile_geometry);
1543 WriteSetting(QStringLiteral("microProfileDialogVisible"), 1501 WriteBasicSetting(UISettings::values.microprofile_visible);
1544 UISettings::values.microprofile_visible, false);
1545 1502
1546 qt_config->endGroup(); 1503 qt_config->endGroup();
1547} 1504}
@@ -1549,13 +1506,10 @@ void Config::SaveUILayoutValues() {
1549void Config::SaveWebServiceValues() { 1506void Config::SaveWebServiceValues() {
1550 qt_config->beginGroup(QStringLiteral("WebService")); 1507 qt_config->beginGroup(QStringLiteral("WebService"));
1551 1508
1552 WriteSetting(QStringLiteral("enable_telemetry"), Settings::values.enable_telemetry, true); 1509 WriteBasicSetting(Settings::values.enable_telemetry);
1553 WriteSetting(QStringLiteral("web_api_url"), 1510 WriteBasicSetting(Settings::values.web_api_url);
1554 QString::fromStdString(Settings::values.web_api_url), 1511 WriteBasicSetting(Settings::values.yuzu_username);
1555 QStringLiteral("https://api.yuzu-emu.org")); 1512 WriteBasicSetting(Settings::values.yuzu_token);
1556 WriteSetting(QStringLiteral("yuzu_username"),
1557 QString::fromStdString(Settings::values.yuzu_username));
1558 WriteSetting(QStringLiteral("yuzu_token"), QString::fromStdString(Settings::values.yuzu_token));
1559 1513
1560 qt_config->endGroup(); 1514 qt_config->endGroup();
1561} 1515}
@@ -1575,21 +1529,14 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
1575} 1529}
1576 1530
1577template <typename Type> 1531template <typename Type>
1578void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) { 1532void Config::ReadGlobalSetting(Settings::Setting<Type>& setting) {
1579 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); 1533 QString name = QString::fromStdString(setting.GetLabel());
1580 setting.SetGlobal(use_global);
1581 if (global || !use_global) {
1582 setting.SetValue(ReadSetting(name).value<Type>());
1583 }
1584}
1585
1586template <typename Type>
1587void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
1588 const QVariant& default_value) {
1589 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); 1534 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
1590 setting.SetGlobal(use_global); 1535 setting.SetGlobal(use_global);
1591 if (global || !use_global) { 1536 if (global || !use_global) {
1592 setting.SetValue(ReadSetting(name, default_value).value<Type>()); 1537 setting.SetValue(static_cast<QVariant>(
1538 ReadSetting(name, QVariant::fromValue<Type>(setting.GetDefault())))
1539 .value<Type>());
1593 } 1540 }
1594} 1541}
1595 1542
@@ -1612,31 +1559,8 @@ void Config::WriteSetting(const QString& name, const QVariant& value,
1612 qt_config->setValue(name, value); 1559 qt_config->setValue(name, value);
1613} 1560}
1614 1561
1615template <typename Type> 1562void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
1616void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting) { 1563 bool use_global) {
1617 if (!global) {
1618 qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
1619 }
1620 if (global || !setting.UsingGlobal()) {
1621 qt_config->setValue(name, setting.GetValue(global));
1622 }
1623}
1624
1625template <typename Type>
1626void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
1627 const QVariant& default_value) {
1628 if (!global) {
1629 qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
1630 }
1631 if (global || !setting.UsingGlobal()) {
1632 qt_config->setValue(name + QStringLiteral("/default"),
1633 setting.GetValue(global) == default_value.value<Type>());
1634 qt_config->setValue(name, setting.GetValue(global));
1635 }
1636}
1637
1638void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
1639 const QVariant& default_value) {
1640 if (!global) { 1564 if (!global) {
1641 qt_config->setValue(name + QStringLiteral("/use_global"), use_global); 1565 qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
1642 } 1566 }
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 3c1de0ac9..96f9b6de1 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -102,28 +102,75 @@ private:
102 void SaveUILayoutValues(); 102 void SaveUILayoutValues();
103 void SaveWebServiceValues(); 103 void SaveWebServiceValues();
104 104
105 /**
106 * Reads a setting from the qt_config.
107 *
108 * @param name The setting's identifier
109 * @param default_value The value to use when the setting is not already present in the config
110 */
105 QVariant ReadSetting(const QString& name) const; 111 QVariant ReadSetting(const QString& name) const;
106 QVariant ReadSetting(const QString& name, const QVariant& default_value) const; 112 QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
107 // Templated ReadSettingGlobal functions will also look for the use_global setting and set 113
108 // both the value and the global state properly 114 /**
109 template <typename Type> 115 * Only reads a setting from the qt_config if the current config is a global config, or if the
110 void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name); 116 * current config is a custom config and the setting is overriding the global setting. Otherwise
111 template <typename Type> 117 * it does nothing.
112 void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name, 118 *
113 const QVariant& default_value); 119 * @param setting The variable to be modified
120 * @param name The setting's identifier
121 * @param default_value The value to use when the setting is not already present in the config
122 */
114 template <typename Type> 123 template <typename Type>
115 void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const; 124 void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
116 // Templated WriteSettingGlobal functions will also write the global state if needed and will 125
117 // skip writing the actual setting if it defers to the global value 126 /**
127 * Writes a setting to the qt_config.
128 *
129 * @param name The setting's idetentifier
130 * @param value Value of the setting
131 * @param default_value Default of the setting if not present in qt_config
132 * @param use_global Specifies if the custom or global config should be in use, for custom
133 * configs
134 */
118 void WriteSetting(const QString& name, const QVariant& value); 135 void WriteSetting(const QString& name, const QVariant& value);
119 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); 136 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
137 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
138 bool use_global);
139
140 /**
141 * Reads a value from the qt_config and applies it to the setting, using its label and default
142 * value. If the config is a custom config, this will also read the global state of the setting
143 * and apply that information to it.
144 *
145 * @param The setting
146 */
120 template <typename Type> 147 template <typename Type>
121 void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting); 148 void ReadGlobalSetting(Settings::Setting<Type>& setting);
149
150 /**
151 * Sets a value to the qt_config using the setting's label and default value. If the config is a
152 * custom config, it will apply the global state, and the custom value if needed.
153 *
154 * @param The setting
155 */
156 template <typename Type>
157 void WriteGlobalSetting(const Settings::Setting<Type>& setting);
158
159 /**
160 * Reads a value from the qt_config using the setting's label and default value and applies the
161 * value to the setting.
162 *
163 * @param The setting
164 */
165 template <typename Type>
166 void ReadBasicSetting(Settings::BasicSetting<Type>& setting);
167
168 /** Sets a value from the setting in the qt_config using the setting's label and default value.
169 *
170 * @param The setting
171 */
122 template <typename Type> 172 template <typename Type>
123 void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting, 173 void WriteBasicSetting(const Settings::BasicSetting<Type>& setting);
124 const QVariant& default_value);
125 void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
126 const QVariant& default_value);
127 174
128 ConfigType type; 175 ConfigType type;
129 std::unique_ptr<QSettings> qt_config; 176 std::unique_ptr<QSettings> qt_config;
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index f92c3aff3..fca9aed5f 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -41,7 +41,7 @@
41 <item> 41 <item>
42 <widget class="QTabWidget" name="tabWidget"> 42 <widget class="QTabWidget" name="tabWidget">
43 <property name="currentIndex"> 43 <property name="currentIndex">
44 <number>0</number> 44 <number>11</number>
45 </property> 45 </property>
46 <widget class="ConfigureGeneral" name="generalTab"> 46 <widget class="ConfigureGeneral" name="generalTab">
47 <property name="accessibleName"> 47 <property name="accessibleName">
@@ -107,14 +107,6 @@
107 <string>CPU</string> 107 <string>CPU</string>
108 </attribute> 108 </attribute>
109 </widget> 109 </widget>
110 <widget class="ConfigureCpuDebug" name="cpuDebugTab">
111 <property name="accessibleName">
112 <string>Debug</string>
113 </property>
114 <attribute name="title">
115 <string>Debug</string>
116 </attribute>
117 </widget>
118 <widget class="ConfigureGraphics" name="graphicsTab"> 110 <widget class="ConfigureGraphics" name="graphicsTab">
119 <property name="accessibleName"> 111 <property name="accessibleName">
120 <string>Graphics</string> 112 <string>Graphics</string>
@@ -139,7 +131,7 @@
139 <string>Audio</string> 131 <string>Audio</string>
140 </attribute> 132 </attribute>
141 </widget> 133 </widget>
142 <widget class="ConfigureDebug" name="debugTab"> 134 <widget class="ConfigureDebugTab" name="debugTab">
143 <property name="accessibleName"> 135 <property name="accessibleName">
144 <string>Debug</string> 136 <string>Debug</string>
145 </property> 137 </property>
@@ -208,24 +200,12 @@
208 <container>1</container> 200 <container>1</container>
209 </customwidget> 201 </customwidget>
210 <customwidget> 202 <customwidget>
211 <class>ConfigureDebug</class>
212 <extends>QWidget</extends>
213 <header>configuration/configure_debug.h</header>
214 <container>1</container>
215 </customwidget>
216 <customwidget>
217 <class>ConfigureCpu</class> 203 <class>ConfigureCpu</class>
218 <extends>QWidget</extends> 204 <extends>QWidget</extends>
219 <header>configuration/configure_cpu.h</header> 205 <header>configuration/configure_cpu.h</header>
220 <container>1</container> 206 <container>1</container>
221 </customwidget> 207 </customwidget>
222 <customwidget> 208 <customwidget>
223 <class>ConfigureCpuDebug</class>
224 <extends>QWidget</extends>
225 <header>configuration/configure_cpu_debug.h</header>
226 <container>1</container>
227 </customwidget>
228 <customwidget>
229 <class>ConfigureGraphics</class> 209 <class>ConfigureGraphics</class>
230 <extends>QWidget</extends> 210 <extends>QWidget</extends>
231 <header>configuration/configure_graphics.h</header> 211 <header>configuration/configure_graphics.h</header>
@@ -267,6 +247,12 @@
267 <header>configuration/configure_service.h</header> 247 <header>configuration/configure_service.h</header>
268 <container>1</container> 248 <container>1</container>
269 </customwidget> 249 </customwidget>
250 <customwidget>
251 <class>ConfigureDebugTab</class>
252 <extends>QWidget</extends>
253 <header>configuration/configure_debug_tab.h</header>
254 <container>1</container>
255 </customwidget>
270 </customwidgets> 256 </customwidgets>
271 <resources/> 257 <resources/>
272 <connections> 258 <connections>
@@ -275,12 +261,32 @@
275 <signal>accepted()</signal> 261 <signal>accepted()</signal>
276 <receiver>ConfigureDialog</receiver> 262 <receiver>ConfigureDialog</receiver>
277 <slot>accept()</slot> 263 <slot>accept()</slot>
264 <hints>
265 <hint type="sourcelabel">
266 <x>20</x>
267 <y>20</y>
268 </hint>
269 <hint type="destinationlabel">
270 <x>20</x>
271 <y>20</y>
272 </hint>
273 </hints>
278 </connection> 274 </connection>
279 <connection> 275 <connection>
280 <sender>buttonBox</sender> 276 <sender>buttonBox</sender>
281 <signal>rejected()</signal> 277 <signal>rejected()</signal>
282 <receiver>ConfigureDialog</receiver> 278 <receiver>ConfigureDialog</receiver>
283 <slot>reject()</slot> 279 <slot>reject()</slot>
280 <hints>
281 <hint type="sourcelabel">
282 <x>20</x>
283 <y>20</y>
284 </hint>
285 <hint type="destinationlabel">
286 <x>20</x>
287 <y>20</y>
288 </hint>
289 </hints>
284 </connection> 290 </connection>
285 </connections> 291 </connections>
286</ui> 292</ui>
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index fc0191432..5aba1a3b2 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -69,7 +69,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
69 [[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box); 69 [[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box);
70 70
71 int new_sink_index = 0; 71 int new_sink_index = 0;
72 const QString sink_id = QString::fromStdString(Settings::values.sink_id); 72 const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
73 for (int index = 0; index < ui->output_sink_combo_box->count(); index++) { 73 for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
74 if (ui->output_sink_combo_box->itemText(index) == sink_id) { 74 if (ui->output_sink_combo_box->itemText(index) == sink_id) {
75 new_sink_index = index; 75 new_sink_index = index;
@@ -83,7 +83,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
83void ConfigureAudio::SetAudioDeviceFromDeviceID() { 83void ConfigureAudio::SetAudioDeviceFromDeviceID() {
84 int new_device_index = -1; 84 int new_device_index = -1;
85 85
86 const QString device_id = QString::fromStdString(Settings::values.audio_device_id); 86 const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue());
87 for (int index = 0; index < ui->audio_device_combo_box->count(); index++) { 87 for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
88 if (ui->audio_device_combo_box->itemText(index) == device_id) { 88 if (ui->audio_device_combo_box->itemText(index) == device_id) {
89 new_device_index = index; 89 new_device_index = index;
@@ -106,9 +106,9 @@ void ConfigureAudio::ApplyConfiguration() {
106 Settings::values.sink_id = 106 Settings::values.sink_id =
107 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) 107 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
108 .toStdString(); 108 .toStdString();
109 Settings::values.audio_device_id = 109 Settings::values.audio_device_id.SetValue(
110 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex()) 110 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
111 .toStdString(); 111 .toStdString());
112 112
113 // Guard if during game and set to game-specific value 113 // Guard if during game and set to game-specific value
114 if (Settings::values.volume.UsingGlobal()) { 114 if (Settings::values.volume.UsingGlobal()) {
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 13db2ba98..8d7171487 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -20,8 +20,6 @@ ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::Config
20 20
21 SetConfiguration(); 21 SetConfiguration();
22 22
23 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
24 &ConfigureCpu::AccuracyUpdated);
25 connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this, 23 connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this,
26 &ConfigureCpu::UpdateGroup); 24 &ConfigureCpu::UpdateGroup);
27} 25}
@@ -58,20 +56,6 @@ void ConfigureCpu::SetConfiguration() {
58 UpdateGroup(ui->accuracy->currentIndex()); 56 UpdateGroup(ui->accuracy->currentIndex());
59} 57}
60 58
61void ConfigureCpu::AccuracyUpdated(int index) {
62 if (Settings::IsConfiguringGlobal() &&
63 static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
64 const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
65 tr("CPU Debug Mode is only intended for developer "
66 "use. Are you sure you want to enable this?"),
67 QMessageBox::Yes | QMessageBox::No);
68 if (result == QMessageBox::No) {
69 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
70 UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate));
71 }
72 }
73}
74
75void ConfigureCpu::UpdateGroup(int index) { 59void ConfigureCpu::UpdateGroup(int index) {
76 if (!Settings::IsConfiguringGlobal()) { 60 if (!Settings::IsConfiguringGlobal()) {
77 index -= ConfigurationShared::USE_GLOBAL_OFFSET; 61 index -= ConfigurationShared::USE_GLOBAL_OFFSET;
@@ -134,8 +118,6 @@ void ConfigureCpu::SetupPerGameUI() {
134 ConfigurationShared::SetColoredComboBox( 118 ConfigurationShared::SetColoredComboBox(
135 ui->accuracy, ui->widget_accuracy, 119 ui->accuracy, ui->widget_accuracy,
136 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true))); 120 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
137 ui->accuracy->removeItem(static_cast<u32>(Settings::CPUAccuracy::DebugMode) +
138 ConfigurationShared::USE_GLOBAL_OFFSET);
139 121
140 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma, 122 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
141 Settings::values.cpuopt_unsafe_unfuse_fma, 123 Settings::values.cpuopt_unsafe_unfuse_fma,
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index b2b5f1671..154931482 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -29,7 +29,6 @@ private:
29 void changeEvent(QEvent* event) override; 29 void changeEvent(QEvent* event) override;
30 void RetranslateUI(); 30 void RetranslateUI();
31 31
32 void AccuracyUpdated(int index);
33 void UpdateGroup(int index); 32 void UpdateGroup(int index);
34 33
35 void SetConfiguration(); 34 void SetConfiguration();
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index 0e296d4e5..5b9457faf 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -6,8 +6,8 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>400</width> 9 <width>448</width>
10 <height>321</height> 10 <height>433</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -17,7 +17,7 @@
17 <item> 17 <item>
18 <layout class="QVBoxLayout"> 18 <layout class="QVBoxLayout">
19 <item> 19 <item>
20 <widget class="QGroupBox"> 20 <widget class="QGroupBox" name="groupBox">
21 <property name="title"> 21 <property name="title">
22 <string>General</string> 22 <string>General</string>
23 </property> 23 </property>
@@ -36,17 +36,17 @@
36 <widget class="QComboBox" name="accuracy"> 36 <widget class="QComboBox" name="accuracy">
37 <item> 37 <item>
38 <property name="text"> 38 <property name="text">
39 <string>Accurate</string> 39 <string>Auto</string>
40 </property> 40 </property>
41 </item> 41 </item>
42 <item> 42 <item>
43 <property name="text"> 43 <property name="text">
44 <string>Unsafe</string> 44 <string>Accurate</string>
45 </property> 45 </property>
46 </item> 46 </item>
47 <item> 47 <item>
48 <property name="text"> 48 <property name="text">
49 <string>Enable Debug Mode</string> 49 <string>Unsafe</string>
50 </property> 50 </property>
51 </item> 51 </item>
52 </widget> 52 </widget>
@@ -57,7 +57,7 @@
57 <item> 57 <item>
58 <widget class="QLabel" name="label_recommended_accuracy"> 58 <widget class="QLabel" name="label_recommended_accuracy">
59 <property name="text"> 59 <property name="text">
60 <string>We recommend setting accuracy to &quot;Accurate&quot;.</string> 60 <string>We recommend setting accuracy to &quot;Auto&quot;.</string>
61 </property> 61 </property>
62 <property name="wordWrap"> 62 <property name="wordWrap">
63 <bool>false</bool> 63 <bool>false</bool>
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
index e25c52baf..98e2d2be5 100644
--- a/src/yuzu/configuration/configure_cpu_debug.cpp
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -24,23 +24,26 @@ void ConfigureCpuDebug::SetConfiguration() {
24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
25 25
26 ui->cpuopt_page_tables->setEnabled(runtime_lock); 26 ui->cpuopt_page_tables->setEnabled(runtime_lock);
27 ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables); 27 ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue());
28 ui->cpuopt_block_linking->setEnabled(runtime_lock); 28 ui->cpuopt_block_linking->setEnabled(runtime_lock);
29 ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking); 29 ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking.GetValue());
30 ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock); 30 ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
31 ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer); 31 ui->cpuopt_return_stack_buffer->setChecked(
32 Settings::values.cpuopt_return_stack_buffer.GetValue());
32 ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock); 33 ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
33 ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher); 34 ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher.GetValue());
34 ui->cpuopt_context_elimination->setEnabled(runtime_lock); 35 ui->cpuopt_context_elimination->setEnabled(runtime_lock);
35 ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination); 36 ui->cpuopt_context_elimination->setChecked(
37 Settings::values.cpuopt_context_elimination.GetValue());
36 ui->cpuopt_const_prop->setEnabled(runtime_lock); 38 ui->cpuopt_const_prop->setEnabled(runtime_lock);
37 ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop); 39 ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop.GetValue());
38 ui->cpuopt_misc_ir->setEnabled(runtime_lock); 40 ui->cpuopt_misc_ir->setEnabled(runtime_lock);
39 ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir); 41 ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir.GetValue());
40 ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock); 42 ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
41 ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks); 43 ui->cpuopt_reduce_misalign_checks->setChecked(
44 Settings::values.cpuopt_reduce_misalign_checks.GetValue());
42 ui->cpuopt_fastmem->setEnabled(runtime_lock); 45 ui->cpuopt_fastmem->setEnabled(runtime_lock);
43 ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem); 46 ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue());
44} 47}
45 48
46void ConfigureCpuDebug::ApplyConfiguration() { 49void ConfigureCpuDebug::ApplyConfiguration() {
diff --git a/src/yuzu/configuration/configure_cpu_debug.h b/src/yuzu/configuration/configure_cpu_debug.h
index 10de55099..1b0d8050c 100644
--- a/src/yuzu/configuration/configure_cpu_debug.h
+++ b/src/yuzu/configuration/configure_cpu_debug.h
@@ -6,7 +6,6 @@
6 6
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9#include "common/settings.h"
10 9
11namespace Ui { 10namespace Ui {
12class ConfigureCpuDebug; 11class ConfigureCpuDebug;
diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui
index c43f89a5a..abf469b55 100644
--- a/src/yuzu/configuration/configure_cpu_debug.ui
+++ b/src/yuzu/configuration/configure_cpu_debug.ui
@@ -6,8 +6,8 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>400</width> 9 <width>592</width>
10 <height>321</height> 10 <height>503</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -17,140 +17,132 @@
17 <item> 17 <item>
18 <layout class="QVBoxLayout"> 18 <layout class="QVBoxLayout">
19 <item> 19 <item>
20 <widget class="QGroupBox"> 20 <widget class="QGroupBox" name="groupBox">
21 <property name="title"> 21 <property name="title">
22 <string>Toggle CPU Optimizations</string> 22 <string>Toggle CPU Optimizations</string>
23 </property> 23 </property>
24 <layout class="QVBoxLayout"> 24 <layout class="QVBoxLayout">
25 <item> 25 <item>
26 <widget class="QLabel"> 26 <widget class="QLabel" name="label">
27 <property name="wordWrap">
28 <bool>1</bool>
29 </property>
30 <property name="text"> 27 <property name="text">
31 <string> 28 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;For debugging only.&lt;/span&gt;&lt;br/&gt;If you're not sure what these do, keep all of these enabled. &lt;br/&gt;These settings, when disabled, only take effect when CPU Debugging is enabled. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
32 &lt;div&gt; 29 </property>
33 &lt;b&gt;For debugging only.&lt;/b&gt; 30 <property name="wordWrap">
34 &lt;br&gt; 31 <bool>false</bool>
35 If you're not sure what these do, keep all of these enabled.
36 &lt;br&gt;
37 These settings, when disabled, only take effect when CPU Accuracy is "Debug Mode".
38 &lt;/div&gt;
39 </string>
40 </property> 32 </property>
41 </widget> 33 </widget>
42 </item> 34 </item>
43 <item> 35 <item>
44 <widget class="QCheckBox" name="cpuopt_page_tables"> 36 <widget class="QCheckBox" name="cpuopt_page_tables">
45 <property name="text">
46 <string>Enable inline page tables</string>
47 </property>
48 <property name="toolTip"> 37 <property name="toolTip">
49 <string> 38 <string>
50 &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt; 39 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
51 &lt;div style="white-space: nowrap"&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt; 40 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
52 &lt;div style="white-space: nowrap"&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt; 41 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
53 </string> 42 </string>
54 </property> 43 </property>
44 <property name="text">
45 <string>Enable inline page tables</string>
46 </property>
55 </widget> 47 </widget>
56 </item> 48 </item>
57 <item> 49 <item>
58 <widget class="QCheckBox" name="cpuopt_block_linking"> 50 <widget class="QCheckBox" name="cpuopt_block_linking">
59 <property name="text">
60 <string>Enable block linking</string>
61 </property>
62 <property name="toolTip"> 51 <property name="toolTip">
63 <string> 52 <string>
64 &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt; 53 &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
65 </string> 54 </string>
66 </property> 55 </property>
56 <property name="text">
57 <string>Enable block linking</string>
58 </property>
67 </widget> 59 </widget>
68 </item> 60 </item>
69 <item> 61 <item>
70 <widget class="QCheckBox" name="cpuopt_return_stack_buffer"> 62 <widget class="QCheckBox" name="cpuopt_return_stack_buffer">
71 <property name="text">
72 <string>Enable return stack buffer</string>
73 </property>
74 <property name="toolTip"> 63 <property name="toolTip">
75 <string> 64 <string>
76 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt; 65 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
77 </string> 66 </string>
78 </property> 67 </property>
68 <property name="text">
69 <string>Enable return stack buffer</string>
70 </property>
79 </widget> 71 </widget>
80 </item> 72 </item>
81 <item> 73 <item>
82 <widget class="QCheckBox" name="cpuopt_fast_dispatcher"> 74 <widget class="QCheckBox" name="cpuopt_fast_dispatcher">
83 <property name="text">
84 <string>Enable fast dispatcher</string>
85 </property>
86 <property name="toolTip"> 75 <property name="toolTip">
87 <string> 76 <string>
88 &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt; 77 &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
89 </string> 78 </string>
90 </property> 79 </property>
80 <property name="text">
81 <string>Enable fast dispatcher</string>
82 </property>
91 </widget> 83 </widget>
92 </item> 84 </item>
93 <item> 85 <item>
94 <widget class="QCheckBox" name="cpuopt_context_elimination"> 86 <widget class="QCheckBox" name="cpuopt_context_elimination">
95 <property name="text">
96 <string>Enable context elimination</string>
97 </property>
98 <property name="toolTip"> 87 <property name="toolTip">
99 <string> 88 <string>
100 &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt; 89 &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
101 </string> 90 </string>
102 </property> 91 </property>
92 <property name="text">
93 <string>Enable context elimination</string>
94 </property>
103 </widget> 95 </widget>
104 </item> 96 </item>
105 <item> 97 <item>
106 <widget class="QCheckBox" name="cpuopt_const_prop"> 98 <widget class="QCheckBox" name="cpuopt_const_prop">
107 <property name="text">
108 <string>Enable constant propagation</string>
109 </property>
110 <property name="toolTip"> 99 <property name="toolTip">
111 <string> 100 <string>
112 &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt; 101 &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
113 </string> 102 </string>
114 </property> 103 </property>
104 <property name="text">
105 <string>Enable constant propagation</string>
106 </property>
115 </widget> 107 </widget>
116 </item> 108 </item>
117 <item> 109 <item>
118 <widget class="QCheckBox" name="cpuopt_misc_ir"> 110 <widget class="QCheckBox" name="cpuopt_misc_ir">
119 <property name="text">
120 <string>Enable miscellaneous optimizations</string>
121 </property>
122 <property name="toolTip"> 111 <property name="toolTip">
123 <string> 112 <string>
124 &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt; 113 &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
125 </string> 114 </string>
126 </property> 115 </property>
116 <property name="text">
117 <string>Enable miscellaneous optimizations</string>
118 </property>
127 </widget> 119 </widget>
128 </item> 120 </item>
129 <item> 121 <item>
130 <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks"> 122 <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks">
131 <property name="text">
132 <string>Enable misalignment check reduction</string>
133 </property>
134 <property name="toolTip"> 123 <property name="toolTip">
135 <string> 124 <string>
136 &lt;div style="white-space: nowrap"&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt; 125 &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
137 &lt;div style="white-space: nowrap"&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt; 126 &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
138 </string> 127 </string>
139 </property> 128 </property>
129 <property name="text">
130 <string>Enable misalignment check reduction</string>
131 </property>
140 </widget> 132 </widget>
141 </item> 133 </item>
142 <item> 134 <item>
143 <widget class="QCheckBox" name="cpuopt_fastmem"> 135 <widget class="QCheckBox" name="cpuopt_fastmem">
144 <property name="text">
145 <string>Enable Host MMU Emulation</string>
146 </property>
147 <property name="toolTip"> 136 <property name="toolTip">
148 <string> 137 <string>
149 &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt; 138 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
150 &lt;div style="white-space: nowrap"&gt;Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt; 139 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt;
151 &lt;div style="white-space: nowrap"&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt; 140 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt;
152 </string> 141 </string>
153 </property> 142 </property>
143 <property name="text">
144 <string>Enable Host MMU Emulation</string>
145 </property>
154 </widget> 146 </widget>
155 </item> 147 </item>
156 </layout> 148 </layout>
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 15d6a5ad7..8fceb3878 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -31,20 +31,23 @@ void ConfigureDebug::SetConfiguration() {
31 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 31 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
32 32
33 ui->toggle_console->setEnabled(runtime_lock); 33 ui->toggle_console->setEnabled(runtime_lock);
34 ui->toggle_console->setChecked(UISettings::values.show_console); 34 ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); 35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 36 ui->homebrew_args_edit->setText(
37 QString::fromStdString(Settings::values.program_args.GetValue()));
37 ui->fs_access_log->setEnabled(runtime_lock); 38 ui->fs_access_log->setEnabled(runtime_lock);
38 ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log); 39 ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log.GetValue());
39 ui->reporting_services->setChecked(Settings::values.reporting_services); 40 ui->reporting_services->setChecked(Settings::values.reporting_services.GetValue());
40 ui->quest_flag->setChecked(Settings::values.quest_flag); 41 ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue());
41 ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts); 42 ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue());
42 ui->use_auto_stub->setChecked(Settings::values.use_auto_stub); 43 ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue());
43 ui->enable_graphics_debugging->setEnabled(runtime_lock); 44 ui->enable_graphics_debugging->setEnabled(runtime_lock);
44 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); 45 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
46 ui->enable_cpu_debugging->setEnabled(runtime_lock);
47 ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue());
45 ui->disable_macro_jit->setEnabled(runtime_lock); 48 ui->disable_macro_jit->setEnabled(runtime_lock);
46 ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit); 49 ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
47 ui->extended_logging->setChecked(Settings::values.extended_logging); 50 ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
48} 51}
49 52
50void ConfigureDebug::ApplyConfiguration() { 53void ConfigureDebug::ApplyConfiguration() {
@@ -57,11 +60,12 @@ void ConfigureDebug::ApplyConfiguration() {
57 Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); 60 Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
58 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); 61 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
59 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); 62 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
63 Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
60 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); 64 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
61 Settings::values.extended_logging = ui->extended_logging->isChecked(); 65 Settings::values.extended_logging = ui->extended_logging->isChecked();
62 Debugger::ToggleConsole(); 66 Debugger::ToggleConsole();
63 Common::Log::Filter filter; 67 Common::Log::Filter filter;
64 filter.ParseFilterString(Settings::values.log_filter); 68 filter.ParseFilterString(Settings::values.log_filter.GetValue());
65 Common::Log::SetGlobalFilter(filter); 69 Common::Log::SetGlobalFilter(filter);
66} 70}
67 71
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index c8087542f..1260ad6f0 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -7,7 +7,7 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>400</width> 9 <width>400</width>
10 <height>486</height> 10 <height>777</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -192,34 +192,41 @@
192 </property> 192 </property>
193 </widget> 193 </widget>
194 </item> 194 </item>
195 <item>
196 <widget class="QCheckBox" name="use_debug_asserts">
197 <property name="text">
198 <string>Enable Debug Asserts</string>
199 </property>
200 </widget>
201 </item>
202 <item>
203 <widget class="QCheckBox" name="use_auto_stub">
204 <property name="text">
205 <string>Enable Auto-Stub</string>
206 </property>
207 </widget>
208 </item>
209 <item> 195 <item>
210 <widget class="QLabel" name="label_5"> 196 <widget class="QCheckBox" name="enable_cpu_debugging">
211 <property name="font"> 197 <property name="text">
212 <font> 198 <string>Enable CPU Debugging</string>
213 <italic>true</italic> 199 </property>
214 </font> 200 </widget>
215 </property> 201 </item>
216 <property name="text"> 202 <item>
217 <string>This will be reset automatically when yuzu closes.</string> 203 <widget class="QCheckBox" name="use_debug_asserts">
218 </property> 204 <property name="text">
219 <property name="indent"> 205 <string>Enable Debug Asserts</string>
220 <number>20</number> 206 </property>
221 </property> 207 </widget>
222 </widget> 208 </item>
209 <item>
210 <widget class="QCheckBox" name="use_auto_stub">
211 <property name="text">
212 <string>Enable Auto-Stub</string>
213 </property>
214 </widget>
215 </item>
216 <item>
217 <widget class="QLabel" name="label_5">
218 <property name="font">
219 <font>
220 <italic>true</italic>
221 </font>
222 </property>
223 <property name="text">
224 <string>This will be reset automatically when yuzu closes.</string>
225 </property>
226 <property name="indent">
227 <number>20</number>
228 </property>
229 </widget>
223 </item> 230 </item>
224 </layout> 231 </layout>
225 </widget> 232 </widget>
diff --git a/src/yuzu/configuration/configure_debug_tab.cpp b/src/yuzu/configuration/configure_debug_tab.cpp
new file mode 100644
index 000000000..67d369249
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_tab.cpp
@@ -0,0 +1,38 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "ui_configure_debug_tab.h"
6#include "yuzu/configuration/configure_debug_tab.h"
7
8ConfigureDebugTab::ConfigureDebugTab(QWidget* parent)
9 : QWidget(parent), ui(new Ui::ConfigureDebugTab) {
10 ui->setupUi(this);
11
12 SetConfiguration();
13}
14
15ConfigureDebugTab::~ConfigureDebugTab() = default;
16
17void ConfigureDebugTab::ApplyConfiguration() {
18 ui->debugTab->ApplyConfiguration();
19 ui->cpuDebugTab->ApplyConfiguration();
20}
21
22void ConfigureDebugTab::SetCurrentIndex(int index) {
23 ui->tabWidget->setCurrentIndex(index);
24}
25
26void ConfigureDebugTab::changeEvent(QEvent* event) {
27 if (event->type() == QEvent::LanguageChange) {
28 RetranslateUI();
29 }
30
31 QWidget::changeEvent(event);
32}
33
34void ConfigureDebugTab::RetranslateUI() {
35 ui->retranslateUi(this);
36}
37
38void ConfigureDebugTab::SetConfiguration() {}
diff --git a/src/yuzu/configuration/configure_debug_tab.h b/src/yuzu/configuration/configure_debug_tab.h
new file mode 100644
index 000000000..0a96d43d0
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_tab.h
@@ -0,0 +1,32 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9
10namespace Ui {
11class ConfigureDebugTab;
12}
13
14class ConfigureDebugTab : public QWidget {
15 Q_OBJECT
16
17public:
18 explicit ConfigureDebugTab(QWidget* parent = nullptr);
19 ~ConfigureDebugTab() override;
20
21 void ApplyConfiguration();
22
23 void SetCurrentIndex(int index);
24
25private:
26 void changeEvent(QEvent* event) override;
27 void RetranslateUI();
28
29 void SetConfiguration();
30
31 std::unique_ptr<Ui::ConfigureDebugTab> ui;
32};
diff --git a/src/yuzu/configuration/configure_debug_tab.ui b/src/yuzu/configuration/configure_debug_tab.ui
new file mode 100644
index 000000000..7dc6dd704
--- /dev/null
+++ b/src/yuzu/configuration/configure_debug_tab.ui
@@ -0,0 +1,52 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureDebugTab</class>
4 <widget class="QWidget" name="ConfigureDebugTab">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>320</width>
10 <height>240</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QTabWidget" name="tabWidget">
19 <property name="currentIndex">
20 <number>1</number>
21 </property>
22 <widget class="ConfigureDebug" name="debugTab">
23 <attribute name="title">
24 <string>General</string>
25 </attribute>
26 </widget>
27 <widget class="ConfigureCpuDebug" name="cpuDebugTab">
28 <attribute name="title">
29 <string>CPU</string>
30 </attribute>
31 </widget>
32 </widget>
33 </item>
34 </layout>
35 </widget>
36 <customwidgets>
37 <customwidget>
38 <class>ConfigureDebug</class>
39 <extends>QWidget</extends>
40 <header>configuration/configure_debug.h</header>
41 <container>1</container>
42 </customwidget>
43 <customwidget>
44 <class>ConfigureCpuDebug</class>
45 <extends>QWidget</extends>
46 <header>configuration/configure_cpu_debug.h</header>
47 <container>1</container>
48 </customwidget>
49 </customwidgets>
50 <resources/>
51 <connections/>
52</ui>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 371bc01b1..bc009b6b3 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -8,6 +8,7 @@
8#include <QListWidgetItem> 8#include <QListWidgetItem>
9#include <QPushButton> 9#include <QPushButton>
10#include <QSignalBlocker> 10#include <QSignalBlocker>
11#include <QTabWidget>
11#include "common/settings.h" 12#include "common/settings.h"
12#include "core/core.h" 13#include "core/core.h"
13#include "ui_configure.h" 14#include "ui_configure.h"
@@ -32,6 +33,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
32 SetConfiguration(); 33 SetConfiguration();
33 PopulateSelectionList(); 34 PopulateSelectionList();
34 35
36 connect(ui->tabWidget, &QTabWidget::currentChanged, this,
37 [this]() { ui->debugTab->SetCurrentIndex(0); });
35 connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged); 38 connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
36 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, 39 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
37 &ConfigureDialog::UpdateVisibleTabs); 40 &ConfigureDialog::UpdateVisibleTabs);
@@ -59,7 +62,6 @@ void ConfigureDialog::ApplyConfiguration() {
59 ui->inputTab->ApplyConfiguration(); 62 ui->inputTab->ApplyConfiguration();
60 ui->hotkeysTab->ApplyConfiguration(registry); 63 ui->hotkeysTab->ApplyConfiguration(registry);
61 ui->cpuTab->ApplyConfiguration(); 64 ui->cpuTab->ApplyConfiguration();
62 ui->cpuDebugTab->ApplyConfiguration();
63 ui->graphicsTab->ApplyConfiguration(); 65 ui->graphicsTab->ApplyConfiguration();
64 ui->graphicsAdvancedTab->ApplyConfiguration(); 66 ui->graphicsAdvancedTab->ApplyConfiguration();
65 ui->audioTab->ApplyConfiguration(); 67 ui->audioTab->ApplyConfiguration();
@@ -102,7 +104,7 @@ void ConfigureDialog::PopulateSelectionList() {
102 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ 104 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
103 {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}}, 105 {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
104 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, 106 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
105 {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}}, 107 {tr("CPU"), {ui->cpuTab}},
106 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, 108 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
107 {tr("Audio"), {ui->audioTab}}, 109 {tr("Audio"), {ui->audioTab}},
108 {tr("Controls"), ui->inputTab->GetSubTabs()}}, 110 {tr("Controls"), ui->inputTab->GetSubTabs()}},
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index d223c40ea..9cb317822 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -43,18 +43,19 @@ void ConfigureFilesystem::setConfiguration() {
43 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir))); 43 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir)));
44 ui->sdmc_directory_edit->setText( 44 ui->sdmc_directory_edit->setText(
45 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir))); 45 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir)));
46 ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path)); 46 ui->gamecard_path_edit->setText(
47 QString::fromStdString(Settings::values.gamecard_path.GetValue()));
47 ui->dump_path_edit->setText( 48 ui->dump_path_edit->setText(
48 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir))); 49 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
49 ui->load_path_edit->setText( 50 ui->load_path_edit->setText(
50 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir))); 51 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
51 52
52 ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted); 53 ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue());
53 ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game); 54 ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue());
54 ui->dump_exefs->setChecked(Settings::values.dump_exefs); 55 ui->dump_exefs->setChecked(Settings::values.dump_exefs.GetValue());
55 ui->dump_nso->setChecked(Settings::values.dump_nso); 56 ui->dump_nso->setChecked(Settings::values.dump_nso.GetValue());
56 57
57 ui->cache_game_list->setChecked(UISettings::values.cache_game_list); 58 ui->cache_game_list->setChecked(UISettings::values.cache_game_list.GetValue());
58 59
59 UpdateEnabledControls(); 60 UpdateEnabledControls();
60} 61}
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 38edb4d8d..18f25def6 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -40,10 +40,10 @@ void ConfigureGeneral::SetConfiguration() {
40 ui->use_multi_core->setEnabled(runtime_lock); 40 ui->use_multi_core->setEnabled(runtime_lock);
41 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); 41 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
42 42
43 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); 43 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
44 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot); 44 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
45 ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background); 45 ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
46 ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse); 46 ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
47 47
48 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue()); 48 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
49 ui->frame_limit->setValue(Settings::values.frame_limit.GetValue()); 49 ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 8d13c9857..a9e611125 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -28,7 +28,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
28 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 28 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
29 29
30 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); 30 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
31 ui->disable_fps_limit->setChecked(Settings::values.disable_fps_limit.GetValue());
32 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue()); 31 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
33 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); 32 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
34 ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue()); 33 ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue());
@@ -59,8 +58,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
59 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, 58 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
60 ui->anisotropic_filtering_combobox); 59 ui->anisotropic_filtering_combobox);
61 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); 60 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
62 ConfigurationShared::ApplyPerGameSetting(&Settings::values.disable_fps_limit,
63 ui->disable_fps_limit, disable_fps_limit);
64 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders, 61 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
65 ui->use_assembly_shaders, use_assembly_shaders); 62 ui->use_assembly_shaders, use_assembly_shaders);
66 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, 63 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
@@ -103,7 +100,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
103 if (Settings::IsConfiguringGlobal()) { 100 if (Settings::IsConfiguringGlobal()) {
104 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); 101 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
105 ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); 102 ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
106 ui->disable_fps_limit->setEnabled(Settings::values.disable_fps_limit.UsingGlobal());
107 ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal()); 103 ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal());
108 ui->use_asynchronous_shaders->setEnabled( 104 ui->use_asynchronous_shaders->setEnabled(
109 Settings::values.use_asynchronous_shaders.UsingGlobal()); 105 Settings::values.use_asynchronous_shaders.UsingGlobal());
@@ -116,8 +112,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
116 } 112 }
117 113
118 ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); 114 ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync);
119 ConfigurationShared::SetColoredTristate(ui->disable_fps_limit,
120 Settings::values.disable_fps_limit, disable_fps_limit);
121 ConfigurationShared::SetColoredTristate( 115 ConfigurationShared::SetColoredTristate(
122 ui->use_assembly_shaders, Settings::values.use_assembly_shaders, use_assembly_shaders); 116 ui->use_assembly_shaders, Settings::values.use_assembly_shaders, use_assembly_shaders);
123 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, 117 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders,
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 6ac5f20ec..9148aacf2 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -35,7 +35,6 @@ private:
35 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; 35 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
36 36
37 ConfigurationShared::CheckState use_vsync; 37 ConfigurationShared::CheckState use_vsync;
38 ConfigurationShared::CheckState disable_fps_limit;
39 ConfigurationShared::CheckState use_assembly_shaders; 38 ConfigurationShared::CheckState use_assembly_shaders;
40 ConfigurationShared::CheckState use_asynchronous_shaders; 39 ConfigurationShared::CheckState use_asynchronous_shaders;
41 ConfigurationShared::CheckState use_fast_gpu_time; 40 ConfigurationShared::CheckState use_fast_gpu_time;
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 18c43629e..ad0840355 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -77,24 +77,6 @@
77 </widget> 77 </widget>
78 </item> 78 </item>
79 <item> 79 <item>
80 <widget class="QCheckBox" name="disable_fps_limit">
81 <property name="enabled">
82 <bool>true</bool>
83 </property>
84 <property name="toolTip">
85 <string>
86 &lt;html&gt;&lt;head/&gt;&lt;body&gt;
87 &lt;p&gt;Presents guest frames as they become available, disabling the FPS limit in most titles.&lt;/p&gt;
88 &lt;p&gt;NOTE: Will cause instabilities.&lt;/p&gt;
89 &lt;/body&gt;&lt;/html&gt;
90 </string>
91 </property>
92 <property name="text">
93 <string>Disable framerate limit (experimental)</string>
94 </property>
95 </widget>
96 </item>
97 <item>
98 <widget class="QCheckBox" name="use_assembly_shaders"> 80 <widget class="QCheckBox" name="use_assembly_shaders">
99 <property name="toolTip"> 81 <property name="toolTip">
100 <string>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</string> 82 <string>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</string>
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index d8d3b83dc..2f1419b5b 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -148,12 +148,12 @@ void ConfigureInputAdvanced::LoadConfiguration() {
148 } 148 }
149 } 149 }
150 150
151 ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled); 151 ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled.GetValue());
152 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled); 152 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue());
153 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled); 153 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue());
154 ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard); 154 ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue());
155 ui->mouse_panning->setChecked(Settings::values.mouse_panning); 155 ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue());
156 ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity); 156 ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
157 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); 157 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
158 158
159 UpdateUIEnabled(); 159 UpdateUIEnabled();
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 6a5d625df..f8e08c422 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,
101ConfigureMotionTouch::~ConfigureMotionTouch() = default; 101ConfigureMotionTouch::~ConfigureMotionTouch() = default;
102 102
103void ConfigureMotionTouch::SetConfiguration() { 103void ConfigureMotionTouch::SetConfiguration() {
104 const Common::ParamPackage motion_param(Settings::values.motion_device); 104 const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue());
105 const Common::ParamPackage touch_param(Settings::values.touch_device); 105 const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
106 106
107 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); 107 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue());
108 touch_from_button_maps = Settings::values.touch_from_button_maps; 108 touch_from_button_maps = Settings::values.touch_from_button_maps;
109 for (const auto& touch_map : touch_from_button_maps) { 109 for (const auto& touch_map : touch_from_button_maps) {
110 ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); 110 ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
111 } 111 }
112 ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index); 112 ui->touch_from_button_map->setCurrentIndex(
113 Settings::values.touch_from_button_map_index.GetValue());
113 ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f)); 114 ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
114 115
115 min_x = touch_param.Get("min_x", 100); 116 min_x = touch_param.Get("min_x", 100);
@@ -124,7 +125,7 @@ void ConfigureMotionTouch::SetConfiguration() {
124 udp_server_list_model->setStringList({}); 125 udp_server_list_model->setStringList({});
125 ui->udp_server_list->setModel(udp_server_list_model); 126 ui->udp_server_list->setModel(udp_server_list_model);
126 127
127 std::stringstream ss(Settings::values.udp_input_servers); 128 std::stringstream ss(Settings::values.udp_input_servers.GetValue());
128 std::string token; 129 std::string token;
129 130
130 while (std::getline(ss, token, ',')) { 131 while (std::getline(ss, token, ',')) {
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index f5881e58d..ac849b01d 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -166,7 +166,7 @@ void ConfigureProfileManager::PopulateUserList() {
166void ConfigureProfileManager::UpdateCurrentUser() { 166void ConfigureProfileManager::UpdateCurrentUser() {
167 ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS); 167 ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
168 168
169 const auto& current_user = profile_manager->GetUser(Settings::values.current_user); 169 const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
170 ASSERT(current_user); 170 ASSERT(current_user);
171 const auto username = GetAccountUsername(*profile_manager, *current_user); 171 const auto username = GetAccountUsername(*profile_manager, *current_user);
172 172
@@ -245,15 +245,18 @@ void ConfigureProfileManager::DeleteUser() {
245 this, tr("Confirm Delete"), 245 this, tr("Confirm Delete"),
246 tr("You are about to delete user with name \"%1\". Are you sure?").arg(username)); 246 tr("You are about to delete user with name \"%1\". Are you sure?").arg(username));
247 247
248 if (confirm == QMessageBox::No) 248 if (confirm == QMessageBox::No) {
249 return; 249 return;
250 }
250 251
251 if (Settings::values.current_user == tree_view->currentIndex().row()) 252 if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) {
252 Settings::values.current_user = 0; 253 Settings::values.current_user = 0;
254 }
253 UpdateCurrentUser(); 255 UpdateCurrentUser();
254 256
255 if (!profile_manager->RemoveUser(*uuid)) 257 if (!profile_manager->RemoveUser(*uuid)) {
256 return; 258 return;
259 }
257 260
258 item_model->removeRows(tree_view->currentIndex().row(), 1); 261 item_model->removeRows(tree_view->currentIndex().row(), 1);
259 tree_view->clearSelection(); 262 tree_view->clearSelection();
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp
index 6d954a67f..4aa424803 100644
--- a/src/yuzu/configuration/configure_service.cpp
+++ b/src/yuzu/configuration/configure_service.cpp
@@ -65,7 +65,7 @@ void ConfigureService::RetranslateUi() {
65 65
66void ConfigureService::SetConfiguration() { 66void ConfigureService::SetConfiguration() {
67 const int index = 67 const int index =
68 ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend)); 68 ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
69 ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index); 69 ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
70} 70}
71 71
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 9674119e1..e8f41bf65 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -113,11 +113,12 @@ void ConfigureUi::SetConfiguration() {
113 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 113 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
114 ui->language_combobox->setCurrentIndex( 114 ui->language_combobox->setCurrentIndex(
115 ui->language_combobox->findData(UISettings::values.language)); 115 ui->language_combobox->findData(UISettings::values.language));
116 ui->show_add_ons->setChecked(UISettings::values.show_add_ons); 116 ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
117 ui->icon_size_combobox->setCurrentIndex( 117 ui->icon_size_combobox->setCurrentIndex(
118 ui->icon_size_combobox->findData(UISettings::values.icon_size)); 118 ui->icon_size_combobox->findData(UISettings::values.icon_size.GetValue()));
119 119
120 ui->enable_screenshot_save_as->setChecked(UISettings::values.enable_screenshot_save_as); 120 ui->enable_screenshot_save_as->setChecked(
121 UISettings::values.enable_screenshot_save_as.GetValue());
121 ui->screenshot_path_edit->setText(QString::fromStdString( 122 ui->screenshot_path_edit->setText(QString::fromStdString(
122 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir))); 123 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
123} 124}
@@ -178,7 +179,7 @@ void ConfigureUi::InitializeRowComboBoxes() {
178 179
179void ConfigureUi::UpdateFirstRowComboBox(bool init) { 180void ConfigureUi::UpdateFirstRowComboBox(bool init) {
180 const int currentIndex = 181 const int currentIndex =
181 init ? UISettings::values.row_1_text_id 182 init ? UISettings::values.row_1_text_id.GetValue()
182 : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData()); 183 : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
183 184
184 ui->row_1_text_combobox->clear(); 185 ui->row_1_text_combobox->clear();
@@ -197,7 +198,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
197 198
198void ConfigureUi::UpdateSecondRowComboBox(bool init) { 199void ConfigureUi::UpdateSecondRowComboBox(bool init) {
199 const int currentIndex = 200 const int currentIndex =
200 init ? UISettings::values.row_2_text_id 201 init ? UISettings::values.row_2_text_id.GetValue()
201 : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData()); 202 : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
202 203
203 ui->row_2_text_combobox->clear(); 204 ui->row_2_text_combobox->clear();
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index f3f3b54d6..d779251b4 100644
--- a/src/yuzu/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -88,22 +88,22 @@ void ConfigureWeb::SetConfiguration() {
88 ui->web_signup_link->setOpenExternalLinks(true); 88 ui->web_signup_link->setOpenExternalLinks(true);
89 ui->web_token_info_link->setOpenExternalLinks(true); 89 ui->web_token_info_link->setOpenExternalLinks(true);
90 90
91 if (Settings::values.yuzu_username.empty()) { 91 if (Settings::values.yuzu_username.GetValue().empty()) {
92 ui->username->setText(tr("Unspecified")); 92 ui->username->setText(tr("Unspecified"));
93 } else { 93 } else {
94 ui->username->setText(QString::fromStdString(Settings::values.yuzu_username)); 94 ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
95 } 95 }
96 96
97 ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry); 97 ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry.GetValue());
98 ui->edit_token->setText(QString::fromStdString( 98 ui->edit_token->setText(QString::fromStdString(GenerateDisplayToken(
99 GenerateDisplayToken(Settings::values.yuzu_username, Settings::values.yuzu_token))); 99 Settings::values.yuzu_username.GetValue(), Settings::values.yuzu_token.GetValue())));
100 100
101 // Connect after setting the values, to avoid calling OnLoginChanged now 101 // Connect after setting the values, to avoid calling OnLoginChanged now
102 connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged); 102 connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
103 103
104 user_verified = true; 104 user_verified = true;
105 105
106 ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence); 106 ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
107} 107}
108 108
109void ConfigureWeb::ApplyConfiguration() { 109void ConfigureWeb::ApplyConfiguration() {
diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp
index c11a326ac..22ca1285d 100644
--- a/src/yuzu/debugger/console.cpp
+++ b/src/yuzu/debugger/console.cpp
@@ -15,10 +15,10 @@
15namespace Debugger { 15namespace Debugger {
16void ToggleConsole() { 16void ToggleConsole() {
17 static bool console_shown = false; 17 static bool console_shown = false;
18 if (console_shown == UISettings::values.show_console) { 18 if (console_shown == UISettings::values.show_console.GetValue()) {
19 return; 19 return;
20 } else { 20 } else {
21 console_shown = UISettings::values.show_console; 21 console_shown = UISettings::values.show_console.GetValue();
22 } 22 }
23 23
24#if defined(_WIN32) && !defined(_DEBUG) 24#if defined(_WIN32) && !defined(_DEBUG)
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index e44907be8..218b4782b 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -244,7 +244,8 @@ void GameList::OnUpdateThemedIcons() {
244 for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) { 244 for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) {
245 QStandardItem* child = item_model->invisibleRootItem()->child(i); 245 QStandardItem* child = item_model->invisibleRootItem()->child(i);
246 246
247 const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); 247 const int icon_size =
248 std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
248 switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) { 249 switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) {
249 case GameListItemType::SdmcDir: 250 case GameListItemType::SdmcDir:
250 child->setData( 251 child->setData(
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 978d27325..982c0789d 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -80,7 +80,7 @@ public:
80 setData(qulonglong(program_id), ProgramIdRole); 80 setData(qulonglong(program_id), ProgramIdRole);
81 setData(game_type, FileTypeRole); 81 setData(game_type, FileTypeRole);
82 82
83 const u32 size = UISettings::values.icon_size; 83 const u32 size = UISettings::values.icon_size.GetValue();
84 84
85 QPixmap picture; 85 QPixmap picture;
86 if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) { 86 if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
@@ -108,8 +108,8 @@ public:
108 data(TitleRole).toString(), 108 data(TitleRole).toString(),
109 }}; 109 }};
110 110
111 const auto& row1 = row_data.at(UISettings::values.row_1_text_id); 111 const auto& row1 = row_data.at(UISettings::values.row_1_text_id.GetValue());
112 const int row2_id = UISettings::values.row_2_text_id; 112 const int row2_id = UISettings::values.row_2_text_id.GetValue();
113 113
114 if (role == SortRole) { 114 if (role == SortRole) {
115 return row1.toLower(); 115 return row1.toLower();
@@ -233,7 +233,8 @@ public:
233 UISettings::GameDir* game_dir = &directory; 233 UISettings::GameDir* game_dir = &directory;
234 setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole); 234 setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole);
235 235
236 const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); 236 const int icon_size =
237 std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
237 switch (dir_type) { 238 switch (dir_type) {
238 case GameListItemType::SdmcDir: 239 case GameListItemType::SdmcDir:
239 setData( 240 setData(
@@ -294,7 +295,8 @@ public:
294 explicit GameListAddDir() { 295 explicit GameListAddDir() {
295 setData(type(), TypeRole); 296 setData(type(), TypeRole);
296 297
297 const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); 298 const int icon_size =
299 std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
298 setData(QIcon::fromTheme(QStringLiteral("plus")) 300 setData(QIcon::fromTheme(QStringLiteral("plus"))
299 .pixmap(icon_size) 301 .pixmap(icon_size)
300 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), 302 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
@@ -316,7 +318,8 @@ public:
316 explicit GameListFavorites() { 318 explicit GameListFavorites() {
317 setData(type(), TypeRole); 319 setData(type(), TypeRole);
318 320
319 const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64); 321 const int icon_size =
322 std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
320 setData(QIcon::fromTheme(QStringLiteral("star")) 323 setData(QIcon::fromTheme(QStringLiteral("star"))
321 .pixmap(icon_size) 324 .pixmap(icon_size)
322 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), 325 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f462cd072..cb9c01154 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -156,11 +156,13 @@ enum class CalloutFlag : uint32_t {
156}; 156};
157 157
158void GMainWindow::ShowTelemetryCallout() { 158void GMainWindow::ShowTelemetryCallout() {
159 if (UISettings::values.callout_flags & static_cast<uint32_t>(CalloutFlag::Telemetry)) { 159 if (UISettings::values.callout_flags.GetValue() &
160 static_cast<uint32_t>(CalloutFlag::Telemetry)) {
160 return; 161 return;
161 } 162 }
162 163
163 UISettings::values.callout_flags |= static_cast<uint32_t>(CalloutFlag::Telemetry); 164 UISettings::values.callout_flags =
165 UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
164 const QString telemetry_message = 166 const QString telemetry_message =
165 tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous " 167 tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
166 "data is collected</a> to help improve yuzu. " 168 "data is collected</a> to help improve yuzu. "
@@ -177,7 +179,7 @@ static void InitializeLogging() {
177 using namespace Common; 179 using namespace Common;
178 180
179 Log::Filter log_filter; 181 Log::Filter log_filter;
180 log_filter.ParseFilterString(Settings::values.log_filter); 182 log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
181 Log::SetGlobalFilter(log_filter); 183 Log::SetGlobalFilter(log_filter);
182 184
183 const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir); 185 const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
@@ -216,7 +218,7 @@ GMainWindow::GMainWindow()
216 default_theme_paths = QIcon::themeSearchPaths(); 218 default_theme_paths = QIcon::themeSearchPaths();
217 UpdateUITheme(); 219 UpdateUITheme();
218 220
219 SetDiscordEnabled(UISettings::values.enable_discord_presence); 221 SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
220 discord_rpc->Update(); 222 discord_rpc->Update();
221 223
222 RegisterMetaTypes(); 224 RegisterMetaTypes();
@@ -1060,23 +1062,24 @@ void GMainWindow::RestoreUIState() {
1060 render_window->restoreGeometry(UISettings::values.renderwindow_geometry); 1062 render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
1061#if MICROPROFILE_ENABLED 1063#if MICROPROFILE_ENABLED
1062 microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry); 1064 microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
1063 microProfileDialog->setVisible(UISettings::values.microprofile_visible); 1065 microProfileDialog->setVisible(UISettings::values.microprofile_visible.GetValue());
1064#endif 1066#endif
1065 1067
1066 game_list->LoadInterfaceLayout(); 1068 game_list->LoadInterfaceLayout();
1067 1069
1068 ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode); 1070 ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue());
1069 ToggleWindowMode(); 1071 ToggleWindowMode();
1070 1072
1071 ui.action_Fullscreen->setChecked(UISettings::values.fullscreen); 1073 ui.action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue());
1072 1074
1073 ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar); 1075 ui.action_Display_Dock_Widget_Headers->setChecked(
1076 UISettings::values.display_titlebar.GetValue());
1074 OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); 1077 OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
1075 1078
1076 ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar); 1079 ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue());
1077 game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); 1080 game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
1078 1081
1079 ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); 1082 ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
1080 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); 1083 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
1081 Debugger::ToggleConsole(); 1084 Debugger::ToggleConsole();
1082} 1085}
@@ -1243,13 +1246,14 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
1243 const Core::System::ResultStatus result{ 1246 const Core::System::ResultStatus result{
1244 system.Load(*render_window, filename.toStdString(), program_index)}; 1247 system.Load(*render_window, filename.toStdString(), program_index)};
1245 1248
1246 const auto drd_callout = 1249 const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
1247 (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; 1250 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
1248 1251
1249 if (result == Core::System::ResultStatus::Success && 1252 if (result == Core::System::ResultStatus::Success &&
1250 system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && 1253 system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
1251 drd_callout) { 1254 drd_callout) {
1252 UISettings::values.callout_flags |= static_cast<u32>(CalloutFlag::DRDDeprecation); 1255 UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() |
1256 static_cast<u32>(CalloutFlag::DRDDeprecation);
1253 QMessageBox::warning( 1257 QMessageBox::warning(
1254 this, tr("Warning Outdated Game Format"), 1258 this, tr("Warning Outdated Game Format"),
1255 tr("You are using the deconstructed ROM directory format for this game, which is an " 1259 tr("You are using the deconstructed ROM directory format for this game, which is an "
@@ -1351,6 +1355,9 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
1351 1355
1352 ConfigureVibration::SetAllVibrationDevices(); 1356 ConfigureVibration::SetAllVibrationDevices();
1353 1357
1358 // Disable fps limit toggle when booting a new title
1359 Settings::values.disable_fps_limit.SetValue(false);
1360
1354 // Save configurations 1361 // Save configurations
1355 UpdateUISettings(); 1362 UpdateUISettings();
1356 game_list->SaveInterfaceLayout(); 1363 game_list->SaveInterfaceLayout();
@@ -2453,7 +2460,8 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
2453} 2460}
2454 2461
2455void GMainWindow::OnMenuReportCompatibility() { 2462void GMainWindow::OnMenuReportCompatibility() {
2456 if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { 2463 if (!Settings::values.yuzu_token.GetValue().empty() &&
2464 !Settings::values.yuzu_username.GetValue().empty()) {
2457 CompatDB compatdb{this}; 2465 CompatDB compatdb{this};
2458 compatdb.exec(); 2466 compatdb.exec();
2459 } else { 2467 } else {
@@ -2618,7 +2626,7 @@ void GMainWindow::ResetWindowSize1080() {
2618 2626
2619void GMainWindow::OnConfigure() { 2627void GMainWindow::OnConfigure() {
2620 const auto old_theme = UISettings::values.theme; 2628 const auto old_theme = UISettings::values.theme;
2621 const bool old_discord_presence = UISettings::values.enable_discord_presence; 2629 const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
2622 2630
2623 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get()); 2631 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
2624 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, 2632 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
@@ -2675,8 +2683,8 @@ void GMainWindow::OnConfigure() {
2675 if (UISettings::values.theme != old_theme) { 2683 if (UISettings::values.theme != old_theme) {
2676 UpdateUITheme(); 2684 UpdateUITheme();
2677 } 2685 }
2678 if (UISettings::values.enable_discord_presence != old_discord_presence) { 2686 if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) {
2679 SetDiscordEnabled(UISettings::values.enable_discord_presence); 2687 SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
2680 } 2688 }
2681 emit UpdateThemedIcons(); 2689 emit UpdateThemedIcons();
2682 2690
@@ -2832,7 +2840,8 @@ void GMainWindow::OnCaptureScreenshot() {
2832 } 2840 }
2833 } 2841 }
2834#endif 2842#endif
2835 render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename); 2843 render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(),
2844 filename);
2836 OnStartGame(); 2845 OnStartGame();
2837} 2846}
2838 2847
@@ -2907,7 +2916,12 @@ void GMainWindow::UpdateStatusBar() {
2907 } else { 2916 } else {
2908 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); 2917 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
2909 } 2918 }
2910 game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0)); 2919 if (Settings::values.disable_fps_limit) {
2920 game_fps_label->setText(
2921 tr("Game: %1 FPS (Limit off)").arg(results.average_game_fps, 0, 'f', 0));
2922 } else {
2923 game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
2924 }
2911 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); 2925 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
2912 2926
2913 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); 2927 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index cdcb83f9f..7b9d2dd53 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -13,6 +13,7 @@
13#include <QStringList> 13#include <QStringList>
14#include <QVector> 14#include <QVector>
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "common/settings.h"
16 17
17namespace UISettings { 18namespace UISettings {
18 19
@@ -48,26 +49,26 @@ struct Values {
48 QByteArray gamelist_header_state; 49 QByteArray gamelist_header_state;
49 50
50 QByteArray microprofile_geometry; 51 QByteArray microprofile_geometry;
51 bool microprofile_visible; 52 Settings::BasicSetting<bool> microprofile_visible{false, "microProfileDialogVisible"};
52 53
53 bool single_window_mode; 54 Settings::BasicSetting<bool> single_window_mode{true, "singleWindowMode"};
54 bool fullscreen; 55 Settings::BasicSetting<bool> fullscreen{false, "fullscreen"};
55 bool display_titlebar; 56 Settings::BasicSetting<bool> display_titlebar{true, "displayTitleBars"};
56 bool show_filter_bar; 57 Settings::BasicSetting<bool> show_filter_bar{true, "showFilterBar"};
57 bool show_status_bar; 58 Settings::BasicSetting<bool> show_status_bar{true, "showStatusBar"};
58 59
59 bool confirm_before_closing; 60 Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
60 bool first_start; 61 Settings::BasicSetting<bool> first_start{true, "firstStart"};
61 bool pause_when_in_background; 62 Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
62 bool hide_mouse; 63 Settings::BasicSetting<bool> hide_mouse{false, "hideInactiveMouse"};
63 64
64 bool select_user_on_boot; 65 Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};
65 66
66 // Discord RPC 67 // Discord RPC
67 bool enable_discord_presence; 68 Settings::BasicSetting<bool> enable_discord_presence{true, "enable_discord_presence"};
68 69
69 bool enable_screenshot_save_as; 70 Settings::BasicSetting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
70 u16 screenshot_resolution_factor; 71 Settings::BasicSetting<u16> screenshot_resolution_factor{0, "screenshot_resolution_factor"};
71 72
72 QString roms_path; 73 QString roms_path;
73 QString symbols_path; 74 QString symbols_path;
@@ -83,18 +84,18 @@ struct Values {
83 // Shortcut name <Shortcut, context> 84 // Shortcut name <Shortcut, context>
84 std::vector<Shortcut> shortcuts; 85 std::vector<Shortcut> shortcuts;
85 86
86 uint32_t callout_flags; 87 Settings::BasicSetting<uint32_t> callout_flags{0, "calloutFlags"};
87 88
88 // logging 89 // logging
89 bool show_console; 90 Settings::BasicSetting<bool> show_console{false, "showConsole"};
90 91
91 // Game List 92 // Game List
92 bool show_add_ons; 93 Settings::BasicSetting<bool> show_add_ons{true, "show_add_ons"};
93 uint32_t icon_size; 94 Settings::BasicSetting<uint32_t> icon_size{64, "icon_size"};
94 uint8_t row_1_text_id; 95 Settings::BasicSetting<uint8_t> row_1_text_id{3, "row_1_text_id"};
95 uint8_t row_2_text_id; 96 Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"};
96 std::atomic_bool is_game_list_reload_pending{false}; 97 std::atomic_bool is_game_list_reload_pending{false};
97 bool cache_game_list; 98 Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"};
98 99
99 bool configuration_applied; 100 bool configuration_applied;
100 bool reset_to_defaults; 101 bool reset_to_defaults;
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 60bf66ec0..325584a1a 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{
241 SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI, 241 SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
242}; 242};
243 243
244template <>
245void Config::ReadSetting(const std::string& group, Settings::BasicSetting<float>& setting) {
246 setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
247}
248template <>
249void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
250 setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
251}
252template <>
253void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) {
254 setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
255}
256template <typename Type>
257void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting) {
258 setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
259 static_cast<long>(setting.GetDefault())));
260}
261
244void Config::ReadValues() { 262void Config::ReadValues() {
245 // Controls 263 // Controls
246 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { 264 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
@@ -264,8 +282,7 @@ void Config::ReadValues() {
264 } 282 }
265 } 283 }
266 284
267 Settings::values.mouse_enabled = 285 ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
268 sdl2_config->GetBoolean("ControlsGeneral", "mouse_enabled", false);
269 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { 286 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
270 std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); 287 std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
271 Settings::values.mouse_buttons[i] = sdl2_config->Get( 288 Settings::values.mouse_buttons[i] = sdl2_config->Get(
@@ -275,14 +292,11 @@ void Config::ReadValues() {
275 Settings::values.mouse_buttons[i] = default_param; 292 Settings::values.mouse_buttons[i] = default_param;
276 } 293 }
277 294
278 Settings::values.motion_device = sdl2_config->Get( 295 ReadSetting("ControlsGeneral", Settings::values.motion_device);
279 "ControlsGeneral", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01");
280 296
281 Settings::values.keyboard_enabled = 297 ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
282 sdl2_config->GetBoolean("ControlsGeneral", "keyboard_enabled", false);
283 298
284 Settings::values.debug_pad_enabled = 299 ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
285 sdl2_config->GetBoolean("ControlsGeneral", "debug_pad_enabled", false);
286 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { 300 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
287 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); 301 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
288 Settings::values.debug_pad_buttons[i] = sdl2_config->Get( 302 Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
@@ -303,12 +317,9 @@ void Config::ReadValues() {
303 Settings::values.debug_pad_analogs[i] = default_param; 317 Settings::values.debug_pad_analogs[i] = default_param;
304 } 318 }
305 319
306 Settings::values.vibration_enabled.SetValue( 320 ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
307 sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true)); 321 ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
308 Settings::values.enable_accurate_vibrations.SetValue( 322 ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
309 sdl2_config->GetBoolean("ControlsGeneral", "enable_accurate_vibrations", false));
310 Settings::values.motion_enabled.SetValue(
311 sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
312 Settings::values.touchscreen.enabled = 323 Settings::values.touchscreen.enabled =
313 sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); 324 sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
314 Settings::values.touchscreen.rotation_angle = 325 Settings::values.touchscreen.rotation_angle =
@@ -349,13 +360,11 @@ void Config::ReadValues() {
349 Settings::TouchFromButtonMap{"default", {}}); 360 Settings::TouchFromButtonMap{"default", {}});
350 num_touch_from_button_maps = 1; 361 num_touch_from_button_maps = 1;
351 } 362 }
352 Settings::values.use_touch_from_button = 363 ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button);
353 sdl2_config->GetBoolean("ControlsGeneral", "use_touch_from_button", false); 364 Settings::values.touch_from_button_map_index = std::clamp(
354 Settings::values.touch_from_button_map_index = 365 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
355 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
356 366
357 Settings::values.udp_input_servers = 367 ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
358 sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV);
359 368
360 std::transform(keyboard_keys.begin(), keyboard_keys.end(), 369 std::transform(keyboard_keys.begin(), keyboard_keys.end(),
361 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); 370 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
@@ -367,8 +376,7 @@ void Config::ReadValues() {
367 Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam); 376 Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
368 377
369 // Data Storage 378 // Data Storage
370 Settings::values.use_virtual_sd = 379 ReadSetting("Data Storage", Settings::values.use_virtual_sd);
371 sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
372 FS::SetYuzuPath(FS::YuzuPath::NANDDir, 380 FS::SetYuzuPath(FS::YuzuPath::NANDDir,
373 sdl2_config->Get("Data Storage", "nand_directory", 381 sdl2_config->Get("Data Storage", "nand_directory",
374 FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); 382 FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -381,18 +389,16 @@ void Config::ReadValues() {
381 FS::SetYuzuPath(FS::YuzuPath::DumpDir, 389 FS::SetYuzuPath(FS::YuzuPath::DumpDir,
382 sdl2_config->Get("Data Storage", "dump_directory", 390 sdl2_config->Get("Data Storage", "dump_directory",
383 FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); 391 FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
384 Settings::values.gamecard_inserted = 392 ReadSetting("Data Storage", Settings::values.gamecard_inserted);
385 sdl2_config->GetBoolean("Data Storage", "gamecard_inserted", false); 393 ReadSetting("Data Storage", Settings::values.gamecard_current_game);
386 Settings::values.gamecard_current_game = 394 ReadSetting("Data Storage", Settings::values.gamecard_path);
387 sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
388 Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
389 395
390 // System 396 // System
391 Settings::values.use_docked_mode.SetValue( 397 ReadSetting("System", Settings::values.use_docked_mode);
392 sdl2_config->GetBoolean("System", "use_docked_mode", true));
393 398
394 Settings::values.current_user = std::clamp<int>( 399 ReadSetting("System", Settings::values.current_user);
395 sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); 400 Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
401 Service::Account::MAX_USERS - 1);
396 402
397 const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); 403 const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
398 if (rng_seed_enabled) { 404 if (rng_seed_enabled) {
@@ -409,89 +415,60 @@ void Config::ReadValues() {
409 Settings::values.custom_rtc = std::nullopt; 415 Settings::values.custom_rtc = std::nullopt;
410 } 416 }
411 417
412 Settings::values.language_index.SetValue( 418 ReadSetting("System", Settings::values.language_index);
413 sdl2_config->GetInteger("System", "language_index", 1)); 419 ReadSetting("System", Settings::values.time_zone_index);
414 Settings::values.time_zone_index.SetValue(
415 sdl2_config->GetInteger("System", "time_zone_index", 0));
416 420
417 // Core 421 // Core
418 Settings::values.use_multi_core.SetValue( 422 ReadSetting("Core", Settings::values.use_multi_core);
419 sdl2_config->GetBoolean("Core", "use_multi_core", true));
420 423
421 // Renderer 424 // Renderer
422 const int renderer_backend = sdl2_config->GetInteger( 425 ReadSetting("Renderer", Settings::values.renderer_backend);
423 "Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL)); 426 ReadSetting("Renderer", Settings::values.renderer_debug);
424 Settings::values.renderer_backend.SetValue( 427 ReadSetting("Renderer", Settings::values.vulkan_device);
425 static_cast<Settings::RendererBackend>(renderer_backend)); 428
426 Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false); 429 ReadSetting("Renderer", Settings::values.aspect_ratio);
427 Settings::values.vulkan_device.SetValue( 430 ReadSetting("Renderer", Settings::values.max_anisotropy);
428 sdl2_config->GetInteger("Renderer", "vulkan_device", 0)); 431 ReadSetting("Renderer", Settings::values.use_frame_limit);
429 432 ReadSetting("Renderer", Settings::values.frame_limit);
430 Settings::values.aspect_ratio.SetValue( 433 ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
431 static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0))); 434 ReadSetting("Renderer", Settings::values.gpu_accuracy);
432 Settings::values.max_anisotropy.SetValue( 435 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
433 static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0))); 436 ReadSetting("Renderer", Settings::values.use_vsync);
434 Settings::values.use_frame_limit.SetValue( 437 ReadSetting("Renderer", Settings::values.disable_fps_limit);
435 sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)); 438 ReadSetting("Renderer", Settings::values.use_assembly_shaders);
436 Settings::values.frame_limit.SetValue( 439 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
437 static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100))); 440 ReadSetting("Renderer", Settings::values.use_nvdec_emulation);
438 Settings::values.use_disk_shader_cache.SetValue( 441 ReadSetting("Renderer", Settings::values.accelerate_astc);
439 sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false)); 442 ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
440 const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 1); 443
441 Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level)); 444 ReadSetting("Renderer", Settings::values.bg_red);
442 Settings::values.use_asynchronous_gpu_emulation.SetValue( 445 ReadSetting("Renderer", Settings::values.bg_green);
443 sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", true)); 446 ReadSetting("Renderer", Settings::values.bg_blue);
444 Settings::values.use_vsync.SetValue(
445 static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
446 Settings::values.disable_fps_limit.SetValue(
447 sdl2_config->GetBoolean("Renderer", "disable_fps_limit", false));
448 Settings::values.use_assembly_shaders.SetValue(
449 sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true));
450 Settings::values.use_asynchronous_shaders.SetValue(
451 sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
452 Settings::values.use_nvdec_emulation.SetValue(
453 sdl2_config->GetBoolean("Renderer", "use_nvdec_emulation", true));
454 Settings::values.accelerate_astc.SetValue(
455 sdl2_config->GetBoolean("Renderer", "accelerate_astc", true));
456 Settings::values.use_fast_gpu_time.SetValue(
457 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
458
459 Settings::values.bg_red.SetValue(
460 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
461 Settings::values.bg_green.SetValue(
462 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
463 Settings::values.bg_blue.SetValue(
464 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
465 447
466 // Audio 448 // Audio
467 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); 449 ReadSetting("Audio", Settings::values.sink_id);
468 Settings::values.enable_audio_stretching.SetValue( 450 ReadSetting("Audio", Settings::values.enable_audio_stretching);
469 sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true)); 451 ReadSetting("Audio", Settings::values.audio_device_id);
470 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); 452 ReadSetting("Audio", Settings::values.volume);
471 Settings::values.volume.SetValue(
472 static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)));
473 453
474 // Miscellaneous 454 // Miscellaneous
475 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); 455 // log_filter has a different default here than from common
476 Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); 456 Settings::values.log_filter =
457 sdl2_config->Get("Miscellaneous", Settings::values.log_filter.GetLabel(), "*:Trace");
458 ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
477 459
478 // Debugging 460 // Debugging
479 Settings::values.record_frame_times = 461 Settings::values.record_frame_times =
480 sdl2_config->GetBoolean("Debugging", "record_frame_times", false); 462 sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
481 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); 463 ReadSetting("Debugging", Settings::values.program_args);
482 Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false); 464 ReadSetting("Debugging", Settings::values.dump_exefs);
483 Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); 465 ReadSetting("Debugging", Settings::values.dump_nso);
484 Settings::values.enable_fs_access_log = 466 ReadSetting("Debugging", Settings::values.enable_fs_access_log);
485 sdl2_config->GetBoolean("Debugging", "enable_fs_access_log", false); 467 ReadSetting("Debugging", Settings::values.reporting_services);
486 Settings::values.reporting_services = 468 ReadSetting("Debugging", Settings::values.quest_flag);
487 sdl2_config->GetBoolean("Debugging", "reporting_services", false); 469 ReadSetting("Debugging", Settings::values.use_debug_asserts);
488 Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false); 470 ReadSetting("Debugging", Settings::values.use_auto_stub);
489 Settings::values.use_debug_asserts = 471 ReadSetting("Debugging", Settings::values.disable_macro_jit);
490 sdl2_config->GetBoolean("Debugging", "use_debug_asserts", false);
491 Settings::values.use_auto_stub = sdl2_config->GetBoolean("Debugging", "use_auto_stub", false);
492
493 Settings::values.disable_macro_jit =
494 sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
495 472
496 const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); 473 const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
497 std::stringstream ss(title_list); 474 std::stringstream ss(title_list);
@@ -511,17 +488,14 @@ void Config::ReadValues() {
511 } 488 }
512 489
513 // Web Service 490 // Web Service
514 Settings::values.enable_telemetry = 491 ReadSetting("WebService", Settings::values.enable_telemetry);
515 sdl2_config->GetBoolean("WebService", "enable_telemetry", true); 492 ReadSetting("WebService", Settings::values.web_api_url);
516 Settings::values.web_api_url = 493 ReadSetting("WebService", Settings::values.yuzu_username);
517 sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org"); 494 ReadSetting("WebService", Settings::values.yuzu_token);
518 Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", "");
519 Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", "");
520 495
521 // Services 496 // Services
522 Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "none"); 497 ReadSetting("Services", Settings::values.bcat_backend);
523 Settings::values.bcat_boxcat_local = 498 ReadSetting("Services", Settings::values.bcat_boxcat_local);
524 sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false);
525} 499}
526 500
527void Config::Reload() { 501void Config::Reload() {
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index 807199278..1ee932be2 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -8,6 +8,8 @@
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10 10
11#include "common/settings.h"
12
11class INIReader; 13class INIReader;
12 14
13class Config { 15class Config {
@@ -22,4 +24,14 @@ public:
22 ~Config(); 24 ~Config();
23 25
24 void Reload(); 26 void Reload();
27
28private:
29 /**
30 * Applies a value read from the sdl2_config to a BasicSetting.
31 *
32 * @param group The name of the INI group
33 * @param setting The yuzu setting to modify
34 */
35 template <typename Type>
36 void ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting);
25}; 37};
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 50e388312..9607cdcb1 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -78,7 +78,7 @@ static void InitializeLogging() {
78 using namespace Common; 78 using namespace Common;
79 79
80 Log::Filter log_filter(Log::Level::Debug); 80 Log::Filter log_filter(Log::Level::Debug);
81 log_filter.ParseFilterString(Settings::values.log_filter); 81 log_filter.ParseFilterString(static_cast<std::string>(Settings::values.log_filter));
82 Log::SetGlobalFilter(log_filter); 82 Log::SetGlobalFilter(log_filter);
83 83
84 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); 84 Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());