summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt7
-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
81 files changed, 1974 insertions, 1198 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b1734f36..716256cd5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,9 +47,10 @@ if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
endif()
if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
- message(STATUS "Copying pre-commit hook")
- file(COPY hooks/pre-commit
- DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
+ if (EXISTS ${PROJECT_SOURCE_DIR}/.git/)
+ message(STATUS "Copying pre-commit hook")
+ file(COPY hooks/pre-commit DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
+ endif()
endif()
# Sanity check : Check that all submodules are present
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
u32 num_channels, std::string&& name,
Stream::ReleaseCallback&& release_callback) {
if (!sink) {
- sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
+ sink = CreateSinkFromID(Settings::values.sink_id.GetValue(),
+ Settings::values.audio_device_id.GetValue());
}
return std::make_shared<Stream>(
diff --git a/src/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
}
} else {
switch (in_params.sample_format) {
+ case SampleFormat::Pcm8:
case SampleFormat::Pcm16:
+ case SampleFormat::Pcm32:
+ case SampleFormat::PcmFloat:
DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel,
worker_params.sample_rate, worker_params.sample_count,
in_params.node_id);
@@ -1018,9 +1021,10 @@ void CommandGenerator::GenerateFinalMixCommand() {
}
}
-s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
- s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
- s32 channel, std::size_t mix_offset) {
+template <typename T>
+s32 CommandGenerator::DecodePcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
+ s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
+ s32 channel, std::size_t mix_offset) {
const auto& in_params = voice_info.GetInParams();
const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
if (wave_buffer.buffer_address == 0) {
@@ -1034,24 +1038,37 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
}
const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset;
const auto start_offset =
- ((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(s16);
+ ((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(T);
const auto buffer_pos = wave_buffer.buffer_address + start_offset;
const auto samples_processed = std::min(sample_count, samples_remaining);
- if (in_params.channel_count == 1) {
- std::vector<s16> buffer(samples_processed);
- memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
- for (std::size_t i = 0; i < buffer.size(); i++) {
- sample_buffer[mix_offset + i] = buffer[i];
- }
- } else {
- const auto channel_count = in_params.channel_count;
- std::vector<s16> buffer(samples_processed * channel_count);
- memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
+ const auto channel_count = in_params.channel_count;
+ std::vector<T> buffer(samples_processed * channel_count);
+ memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(T));
+ if constexpr (std::is_floating_point_v<T>) {
+ for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
+ sample_buffer[mix_offset + i] = static_cast<s32>(buffer[i * channel_count + channel] *
+ std::numeric_limits<s16>::max());
+ }
+ } else if constexpr (sizeof(T) == 1) {
+ for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
+ sample_buffer[mix_offset + i] =
+ static_cast<s32>(static_cast<f32>(buffer[i * channel_count + channel] /
+ std::numeric_limits<s8>::max()) *
+ std::numeric_limits<s16>::max());
+ }
+ } else if constexpr (sizeof(T) == 2) {
for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
sample_buffer[mix_offset + i] = buffer[i * channel_count + channel];
}
+ } else {
+ for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
+ sample_buffer[mix_offset + i] =
+ static_cast<s32>(static_cast<f32>(buffer[i * channel_count + channel] /
+ std::numeric_limits<s32>::max()) *
+ std::numeric_limits<s16>::max());
+ }
}
return samples_processed;
@@ -1267,10 +1284,25 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::s
s32 samples_decoded{0};
switch (in_params.sample_format) {
+ case SampleFormat::Pcm8:
+ samples_decoded =
+ DecodePcm<s8>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
+ samples_to_read - samples_read, channel, temp_mix_offset);
+ break;
case SampleFormat::Pcm16:
samples_decoded =
- DecodePcm16(voice_info, dsp_state, samples_offset_start, samples_offset_end,
- samples_to_read - samples_read, channel, temp_mix_offset);
+ DecodePcm<s16>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
+ samples_to_read - samples_read, channel, temp_mix_offset);
+ break;
+ case SampleFormat::Pcm32:
+ samples_decoded =
+ DecodePcm<s32>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
+ samples_to_read - samples_read, channel, temp_mix_offset);
+ break;
+ case SampleFormat::PcmFloat:
+ samples_decoded =
+ DecodePcm<f32>(voice_info, dsp_state, samples_offset_start, samples_offset_end,
+ samples_to_read - samples_read, channel, temp_mix_offset);
break;
case SampleFormat::Adpcm:
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:
std::vector<u8>& work_buffer);
void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear);
// DSP Code
- s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
- s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
+ template <typename T>
+ s32 DecodePcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
+ s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
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
thread.cpp
thread.h
thread_queue_list.h
- thread_worker.cpp
thread_worker.h
threadsafe_queue.h
time_zone.cpp
@@ -188,6 +187,7 @@ add_library(common STATIC
tiny_mt.h
tree.h
uint128.h
+ unique_function.h
uuid.cpp
uuid.h
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() {
LOG_INFO(Config, "yuzu Configuration:");
log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
- log_setting("System_CurrentUser", values.current_user);
+ log_setting("System_CurrentUser", values.current_user.GetValue());
log_setting("System_LanguageIndex", values.language_index.GetValue());
log_setting("System_RegionIndex", values.region_index.GetValue());
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
@@ -61,18 +61,18 @@ void LogSettings() {
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
- log_setting("Audio_OutputEngine", values.sink_id);
+ log_setting("Audio_OutputEngine", values.sink_id.GetValue());
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
- log_setting("Audio_OutputDevice", values.audio_device_id);
- log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
+ log_setting("Audio_OutputDevice", values.audio_device_id.GetValue());
+ log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
- log_setting("Debugging_ProgramArgs", values.program_args);
- log_setting("Services_BCATBackend", values.bcat_backend);
- log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local);
+ log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
+ log_setting("Services_BCATBackend", values.bcat_backend.GetValue());
+ log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue());
}
bool IsConfiguringGlobal() {
@@ -93,8 +93,8 @@ bool IsGPULevelHigh() {
}
bool IsFastmemEnabled() {
- if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
- return values.cpuopt_fastmem;
+ if (values.cpu_debug_mode) {
+ return static_cast<bool>(values.cpuopt_fastmem);
}
return true;
}
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 @@
#include <map>
#include <optional>
#include <string>
+#include <utility>
#include <vector>
#include "common/common_types.h"
#include "common/settings_input.h"
+#include "input_common/udp/client.h"
namespace Settings {
@@ -29,73 +31,240 @@ enum class GPUAccuracy : u32 {
};
enum class CPUAccuracy : u32 {
- Accurate = 0,
- Unsafe = 1,
- DebugMode = 2,
+ Auto = 0,
+ Accurate = 1,
+ Unsafe = 2,
};
+/** The BasicSetting class is a simple resource manager. It defines a label and default value
+ * alongside the actual value of the setting for simpler and less-error prone use with frontend
+ * configurations. Setting a default value and label is required, though subclasses may deviate from
+ * this requirement.
+ */
+template <typename Type>
+class BasicSetting {
+protected:
+ BasicSetting() = default;
+
+ /**
+ * Only sets the setting to the given initializer, leaving the other members to their default
+ * initializers.
+ *
+ * @param global_val Initial value of the setting
+ */
+ explicit BasicSetting(const Type& global_val) : global{global_val} {}
+
+public:
+ /**
+ * Sets a default value, label, and setting value.
+ *
+ * @param default_val Intial value of the setting, and default value of the setting
+ * @param name Label for the setting
+ */
+ explicit BasicSetting(const Type& default_val, const std::string& name)
+ : default_value{default_val}, global{default_val}, label{name} {}
+ ~BasicSetting() = default;
+
+ /**
+ * Returns a reference to the setting's value.
+ *
+ * @returns A reference to the setting
+ */
+ [[nodiscard]] const Type& GetValue() const {
+ return global;
+ }
+
+ /**
+ * Sets the setting to the given value.
+ *
+ * @param value The desired value
+ */
+ void SetValue(const Type& value) {
+ Type temp{value};
+ std::swap(global, temp);
+ }
+
+ /**
+ * Returns the value that this setting was created with.
+ *
+ * @returns A reference to the default value
+ */
+ [[nodiscard]] const Type& GetDefault() const {
+ return default_value;
+ }
+
+ /**
+ * Returns the label this setting was created with.
+ *
+ * @returns A reference to the label
+ */
+ [[nodiscard]] const std::string& GetLabel() const {
+ return label;
+ }
+
+ /**
+ * Assigns a value to the setting.
+ *
+ * @param value The desired setting value
+ *
+ * @returns A reference to the setting
+ */
+ const Type& operator=(const Type& value) {
+ Type temp{value};
+ std::swap(global, temp);
+ return global;
+ }
+
+ /**
+ * Returns a reference to the setting.
+ *
+ * @returns A reference to the setting
+ */
+ explicit operator const Type&() const {
+ return global;
+ }
+
+protected:
+ const Type default_value{}; ///< The default value
+ Type global{}; ///< The setting
+ const std::string label{}; ///< The setting's label
+};
+
+/**
+ * The Setting class is a slightly more complex version of the BasicSetting class. This adds a
+ * custom setting to switch to when a guest application specifically requires it. The effect is that
+ * other components of the emulator can access the setting's intended value without any need for the
+ * component to ask whether the custom or global setting is needed at the moment.
+ *
+ * By default, the global setting is used.
+ *
+ * Like the BasicSetting, this requires setting a default value and label to use.
+ */
template <typename Type>
-class Setting final {
+class Setting final : public BasicSetting<Type> {
public:
- Setting() = default;
- explicit Setting(Type val) : global{val} {}
+ /**
+ * Sets a default value, label, and setting value.
+ *
+ * @param default_val Intial value of the setting, and default value of the setting
+ * @param name Label for the setting
+ */
+ explicit Setting(const Type& default_val, const std::string& name)
+ : BasicSetting<Type>(default_val, name) {}
~Setting() = default;
+
+ /**
+ * Tells this setting to represent either the global or custom setting when other member
+ * functions are used.
+ *
+ * @param to_global Whether to use the global or custom setting.
+ */
void SetGlobal(bool to_global) {
use_global = to_global;
}
- bool UsingGlobal() const {
+
+ /**
+ * Returns whether this setting is using the global setting or not.
+ *
+ * @returns The global state
+ */
+ [[nodiscard]] bool UsingGlobal() const {
return use_global;
}
- Type GetValue(bool need_global = false) const {
+
+ /**
+ * Returns either the global or custom setting depending on the values of this setting's global
+ * state or if the global value was specifically requested.
+ *
+ * @param need_global Request global value regardless of setting's state; defaults to false
+ *
+ * @returns The required value of the setting
+ */
+ [[nodiscard]] const Type& GetValue(bool need_global = false) const {
if (use_global || need_global) {
- return global;
+ return this->global;
}
- return local;
+ return custom;
}
+
+ /**
+ * Sets the current setting value depending on the global state.
+ *
+ * @param value The new value
+ */
void SetValue(const Type& value) {
+ Type temp{value};
if (use_global) {
- global = value;
+ std::swap(this->global, temp);
} else {
- local = value;
+ std::swap(custom, temp);
+ }
+ }
+
+ /**
+ * Assigns the current setting value depending on the global state.
+ *
+ * @param value The new value
+ *
+ * @returns A reference to the current setting value
+ */
+ const Type& operator=(const Type& value) {
+ Type temp{value};
+ if (use_global) {
+ std::swap(this->global, temp);
+ return this->global;
+ }
+ std::swap(custom, temp);
+ return custom;
+ }
+
+ /**
+ * Returns the current setting value depending on the global state.
+ *
+ * @returns A reference to the current setting value
+ */
+ explicit operator const Type&() const {
+ if (use_global) {
+ return this->global;
}
+ return custom;
}
private:
- bool use_global = true;
- Type global{};
- Type local{};
+ bool use_global{true}; ///< The setting's global state
+ Type custom{}; ///< The custom value of the setting
};
/**
- * The InputSetting class allows for getting a reference to either the global or local members.
+ * The InputSetting class allows for getting a reference to either the global or custom members.
* This is required as we cannot easily modify the values of user-defined types within containers
* using the SetValue() member function found in the Setting class. The primary purpose of this
- * class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
- * setting and allows for easily accessing and modifying both settings.
+ * class is to store an array of 10 PlayerInput structs for both the global and custom setting and
+ * allows for easily accessing and modifying both settings.
*/
template <typename Type>
class InputSetting final {
public:
InputSetting() = default;
- explicit InputSetting(Type val) : global{val} {}
+ explicit InputSetting(Type val) : BasicSetting<Type>(val) {}
~InputSetting() = default;
void SetGlobal(bool to_global) {
use_global = to_global;
}
- bool UsingGlobal() const {
+ [[nodiscard]] bool UsingGlobal() const {
return use_global;
}
- Type& GetValue(bool need_global = false) {
+ [[nodiscard]] Type& GetValue(bool need_global = false) {
if (use_global || need_global) {
return global;
}
- return local;
+ return custom;
}
private:
- bool use_global = true;
- Type global{};
- Type local{};
+ bool use_global{true}; ///< The setting's global state
+ Type global{}; ///< The setting
+ Type custom{}; ///< The custom setting value
};
struct TouchFromButtonMap {
@@ -105,144 +274,158 @@ struct TouchFromButtonMap {
struct Values {
// Audio
- std::string audio_device_id;
- std::string sink_id;
- bool audio_muted;
- Setting<bool> enable_audio_stretching;
- Setting<float> volume;
+ BasicSetting<std::string> audio_device_id{"auto", "output_device"};
+ BasicSetting<std::string> sink_id{"auto", "output_engine"};
+ BasicSetting<bool> audio_muted{false, "audio_muted"};
+ Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
+ Setting<float> volume{1.0f, "volume"};
// Core
- Setting<bool> use_multi_core;
+ Setting<bool> use_multi_core{true, "use_multi_core"};
// Cpu
- Setting<CPUAccuracy> cpu_accuracy;
-
- bool cpuopt_page_tables;
- bool cpuopt_block_linking;
- bool cpuopt_return_stack_buffer;
- bool cpuopt_fast_dispatcher;
- bool cpuopt_context_elimination;
- bool cpuopt_const_prop;
- bool cpuopt_misc_ir;
- bool cpuopt_reduce_misalign_checks;
- bool cpuopt_fastmem;
-
- Setting<bool> cpuopt_unsafe_unfuse_fma;
- Setting<bool> cpuopt_unsafe_reduce_fp_error;
- Setting<bool> cpuopt_unsafe_ignore_standard_fpcr;
- Setting<bool> cpuopt_unsafe_inaccurate_nan;
- Setting<bool> cpuopt_unsafe_fastmem_check;
+ Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, "cpu_accuracy"};
+ // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
+ BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
+ BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
+
+ BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
+ BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
+ BasicSetting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
+ BasicSetting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
+ BasicSetting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
+ BasicSetting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
+ BasicSetting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
+ BasicSetting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
+ BasicSetting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
+
+ Setting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
+ Setting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
+ Setting<bool> cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"};
+ Setting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
+ Setting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
// Renderer
- Setting<RendererBackend> renderer_backend;
- bool renderer_debug;
- Setting<int> vulkan_device;
-
- Setting<u16> resolution_factor{1};
- Setting<int> fullscreen_mode;
- Setting<int> aspect_ratio;
- Setting<int> max_anisotropy;
- Setting<bool> use_frame_limit;
- Setting<u16> frame_limit;
- Setting<bool> use_disk_shader_cache;
- Setting<GPUAccuracy> gpu_accuracy;
- Setting<bool> use_asynchronous_gpu_emulation;
- Setting<bool> use_nvdec_emulation;
- Setting<bool> accelerate_astc;
- Setting<bool> use_vsync;
- Setting<bool> disable_fps_limit;
- Setting<bool> use_assembly_shaders;
- Setting<bool> use_asynchronous_shaders;
- Setting<bool> use_fast_gpu_time;
- Setting<bool> use_caches_gc;
-
- Setting<float> bg_red;
- Setting<float> bg_green;
- Setting<float> bg_blue;
+ Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
+ BasicSetting<bool> renderer_debug{false, "debug"};
+ Setting<int> vulkan_device{0, "vulkan_device"};
+
+ Setting<u16> resolution_factor{1, "resolution_factor"};
+ // *nix platforms may have issues with the borderless windowed fullscreen mode.
+ // Default to exclusive fullscreen on these platforms for now.
+ Setting<int> fullscreen_mode{
+#ifdef _WIN32
+ 0,
+#else
+ 1,
+#endif
+ "fullscreen_mode"};
+ Setting<int> aspect_ratio{0, "aspect_ratio"};
+ Setting<int> max_anisotropy{0, "max_anisotropy"};
+ Setting<bool> use_frame_limit{true, "use_frame_limit"};
+ Setting<u16> frame_limit{100, "frame_limit"};
+ Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
+ Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
+ Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
+ Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
+ Setting<bool> accelerate_astc{true, "accelerate_astc"};
+ Setting<bool> use_vsync{true, "use_vsync"};
+ BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
+ Setting<bool> use_assembly_shaders{false, "use_assembly_shaders"};
+ Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
+ Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
+ Setting<bool> use_caches_gc{false, "use_caches_gc"};
+
+ Setting<float> bg_red{0.0f, "bg_red"};
+ Setting<float> bg_green{0.0f, "bg_green"};
+ Setting<float> bg_blue{0.0f, "bg_blue"};
// System
- Setting<std::optional<u32>> rng_seed;
+ Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
// Measured in seconds since epoch
std::optional<std::chrono::seconds> custom_rtc;
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
std::chrono::seconds custom_rtc_differential;
- s32 current_user;
- Setting<s32> language_index;
- Setting<s32> region_index;
- Setting<s32> time_zone_index;
- Setting<s32> sound_index;
+ BasicSetting<s32> current_user{0, "current_user"};
+ Setting<s32> language_index{1, "language_index"};
+ Setting<s32> region_index{1, "region_index"};
+ Setting<s32> time_zone_index{0, "time_zone_index"};
+ Setting<s32> sound_index{1, "sound_index"};
// Controls
InputSetting<std::array<PlayerInput, 10>> players;
- Setting<bool> use_docked_mode;
+ Setting<bool> use_docked_mode{true, "use_docked_mode"};
- Setting<bool> vibration_enabled;
- Setting<bool> enable_accurate_vibrations;
+ Setting<bool> vibration_enabled{true, "vibration_enabled"};
+ Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
- Setting<bool> motion_enabled;
- std::string motion_device;
- std::string udp_input_servers;
+ Setting<bool> motion_enabled{true, "motion_enabled"};
+ BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
+ "motion_device"};
+ BasicSetting<std::string> udp_input_servers{InputCommon::CemuhookUDP::DEFAULT_SRV,
+ "udp_input_servers"};
- bool mouse_panning;
- float mouse_panning_sensitivity;
- bool mouse_enabled;
+ BasicSetting<bool> mouse_panning{false, "mouse_panning"};
+ BasicSetting<float> mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"};
+ BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
std::string mouse_device;
MouseButtonsRaw mouse_buttons;
- bool emulate_analog_keyboard;
- bool keyboard_enabled;
+ BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
+ BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
KeyboardKeysRaw keyboard_keys;
KeyboardModsRaw keyboard_mods;
- bool debug_pad_enabled;
+ BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
ButtonsRaw debug_pad_buttons;
AnalogsRaw debug_pad_analogs;
TouchscreenInput touchscreen;
- bool use_touch_from_button;
- std::string touch_device;
- int touch_from_button_map_index;
+ BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
+ BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
+ "touch_device"};
+ BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
std::vector<TouchFromButtonMap> touch_from_button_maps;
std::atomic_bool is_device_reload_pending{true};
// Data Storage
- bool use_virtual_sd;
- bool gamecard_inserted;
- bool gamecard_current_game;
- std::string gamecard_path;
+ BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
+ BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};
+ BasicSetting<bool> gamecard_current_game{false, "gamecard_current_game"};
+ BasicSetting<std::string> gamecard_path{std::string(), "gamecard_path"};
// Debugging
bool record_frame_times;
- bool use_gdbstub;
- u16 gdbstub_port;
- std::string program_args;
- bool dump_exefs;
- bool dump_nso;
- bool enable_fs_access_log;
- bool reporting_services;
- bool quest_flag;
- bool disable_macro_jit;
- bool extended_logging;
- bool use_debug_asserts;
- bool use_auto_stub;
+ BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
+ BasicSetting<u16> gdbstub_port{0, "gdbstub_port"};
+ BasicSetting<std::string> program_args{std::string(), "program_args"};
+ BasicSetting<bool> dump_exefs{false, "dump_exefs"};
+ BasicSetting<bool> dump_nso{false, "dump_nso"};
+ BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
+ BasicSetting<bool> reporting_services{false, "reporting_services"};
+ BasicSetting<bool> quest_flag{false, "quest_flag"};
+ BasicSetting<bool> disable_macro_jit{false, "disable_macro_jit"};
+ BasicSetting<bool> extended_logging{false, "extended_logging"};
+ BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
+ BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
// Miscellaneous
- std::string log_filter;
- bool use_dev_keys;
+ BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
+ BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
// Services
- std::string bcat_backend;
- bool bcat_boxcat_local;
+ BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
+ BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
// WebService
- bool enable_telemetry;
- std::string web_api_url;
- std::string yuzu_username;
- std::string yuzu_token;
+ BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
+ BasicSetting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
+ BasicSetting<std::string> yuzu_username{std::string(), "yuzu_username"};
+ BasicSetting<std::string> yuzu_token{std::string(), "yuzu_token"};
// Add-Ons
std::map<u64, std::vector<std::string>> disabled_addons;
diff --git a/src/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 @@
-// Copyright 2020 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/thread.h"
-#include "common/thread_worker.h"
-
-namespace Common {
-
-ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
- for (std::size_t i = 0; i < num_workers; ++i)
- threads.emplace_back([this, thread_name{std::string{name}}] {
- Common::SetCurrentThreadName(thread_name.c_str());
-
- // Wait for first request
- {
- std::unique_lock lock{queue_mutex};
- condition.wait(lock, [this] { return stop || !requests.empty(); });
- }
-
- while (true) {
- std::function<void()> task;
-
- {
- std::unique_lock lock{queue_mutex};
- condition.wait(lock, [this] { return stop || !requests.empty(); });
- if (stop || requests.empty()) {
- return;
- }
- task = std::move(requests.front());
- requests.pop();
- }
-
- task();
- }
- });
-}
-
-ThreadWorker::~ThreadWorker() {
- {
- std::unique_lock lock{queue_mutex};
- stop = true;
- }
- condition.notify_all();
- for (std::thread& thread : threads) {
- thread.join();
- }
-}
-
-void ThreadWorker::QueueWork(std::function<void()>&& work) {
- {
- std::unique_lock lock{queue_mutex};
- requests.emplace(work);
- }
- condition.notify_one();
-}
-
-} // 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 @@
#include <atomic>
#include <functional>
#include <mutex>
+#include <stop_token>
#include <string>
+#include <thread>
+#include <type_traits>
#include <vector>
#include <queue>
+#include "common/thread.h"
+#include "common/unique_function.h"
+
namespace Common {
-class ThreadWorker final {
+template <class StateType = void>
+class StatefulThreadWorker {
+ static constexpr bool with_state = !std::is_same_v<StateType, void>;
+
+ struct DummyCallable {
+ int operator()() const noexcept {
+ return 0;
+ }
+ };
+
+ using Task =
+ std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
+ using StateMaker = std::conditional_t<with_state, std::function<StateType()>, DummyCallable>;
+
public:
- explicit ThreadWorker(std::size_t num_workers, const std::string& name);
- ~ThreadWorker();
- void QueueWork(std::function<void()>&& work);
+ explicit StatefulThreadWorker(size_t num_workers, std::string name, StateMaker func = {})
+ : workers_queued{num_workers}, thread_name{std::move(name)} {
+ const auto lambda = [this, func](std::stop_token stop_token) {
+ Common::SetCurrentThreadName(thread_name.c_str());
+ {
+ std::conditional_t<with_state, StateType, int> state{func()};
+ while (!stop_token.stop_requested()) {
+ Task task;
+ {
+ std::unique_lock lock{queue_mutex};
+ if (requests.empty()) {
+ wait_condition.notify_all();
+ }
+ condition.wait(lock, stop_token, [this] { return !requests.empty(); });
+ if (stop_token.stop_requested()) {
+ break;
+ }
+ task = std::move(requests.front());
+ requests.pop();
+ }
+ if constexpr (with_state) {
+ task(&state);
+ } else {
+ task();
+ }
+ ++work_done;
+ }
+ }
+ ++workers_stopped;
+ wait_condition.notify_all();
+ };
+ threads.reserve(num_workers);
+ for (size_t i = 0; i < num_workers; ++i) {
+ threads.emplace_back(lambda);
+ }
+ }
+
+ StatefulThreadWorker& operator=(const StatefulThreadWorker&) = delete;
+ StatefulThreadWorker(const StatefulThreadWorker&) = delete;
+
+ StatefulThreadWorker& operator=(StatefulThreadWorker&&) = delete;
+ StatefulThreadWorker(StatefulThreadWorker&&) = delete;
+
+ void QueueWork(Task work) {
+ {
+ std::unique_lock lock{queue_mutex};
+ requests.emplace(std::move(work));
+ ++work_scheduled;
+ }
+ condition.notify_one();
+ }
+
+ void WaitForRequests(std::stop_token stop_token = {}) {
+ std::stop_callback callback(stop_token, [this] {
+ for (auto& thread : threads) {
+ thread.request_stop();
+ }
+ });
+ std::unique_lock lock{queue_mutex};
+ wait_condition.wait(lock, [this] {
+ return workers_stopped >= workers_queued || work_done >= work_scheduled;
+ });
+ }
private:
- std::vector<std::thread> threads;
- std::queue<std::function<void()>> requests;
+ std::queue<Task> requests;
std::mutex queue_mutex;
- std::condition_variable condition;
- std::atomic_bool stop{};
+ std::condition_variable_any condition;
+ std::condition_variable wait_condition;
+ std::atomic<size_t> work_scheduled{};
+ std::atomic<size_t> work_done{};
+ std::atomic<size_t> workers_stopped{};
+ std::atomic<size_t> workers_queued{};
+ std::string thread_name;
+ std::vector<std::jthread> threads;
};
+using ThreadWorker = StatefulThreadWorker<>;
+
} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <utility>
+
+namespace Common {
+
+/// General purpose function wrapper similar to std::function.
+/// Unlike std::function, the captured values don't have to be copyable.
+/// This class can be moved but not copied.
+template <typename ResultType, typename... Args>
+class UniqueFunction {
+ class CallableBase {
+ public:
+ virtual ~CallableBase() = default;
+ virtual ResultType operator()(Args&&...) = 0;
+ };
+
+ template <typename Functor>
+ class Callable final : public CallableBase {
+ public:
+ Callable(Functor&& functor_) : functor{std::move(functor_)} {}
+ ~Callable() override = default;
+
+ ResultType operator()(Args&&... args) override {
+ return functor(std::forward<Args>(args)...);
+ }
+
+ private:
+ Functor functor;
+ };
+
+public:
+ UniqueFunction() = default;
+
+ template <typename Functor>
+ UniqueFunction(Functor&& functor)
+ : callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
+
+ UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
+ UniqueFunction(UniqueFunction&& rhs) noexcept = default;
+
+ UniqueFunction& operator=(const UniqueFunction&) = delete;
+ UniqueFunction(const UniqueFunction&) = delete;
+
+ ResultType operator()(Args&&... args) const {
+ return (*callable)(std::forward<Args>(args)...);
+ }
+
+ explicit operator bool() const noexcept {
+ return static_cast<bool>(callable);
+ }
+
+private:
+ std::unique_ptr<CallableBase> callable;
+};
+
+} // 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*
config.far_code_offset = 400_MiB;
// Safe optimizations
- if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
+ if (Settings::values.cpu_debug_mode) {
if (!Settings::values.cpuopt_page_tables) {
config.page_table = nullptr;
}
@@ -183,20 +183,28 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
// Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
config.unsafe_optimizations = true;
- if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_unfuse_fma) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
}
- if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
- if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
}
- if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
}
+ // Curated optimizations
+ if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
+ config.unsafe_optimizations = true;
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
+ }
+
return std::make_unique<Dynarmic::A32::Jit>(config);
}
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*
config.far_code_offset = 400_MiB;
// Safe optimizations
- if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
+ if (Settings::values.cpu_debug_mode) {
if (!Settings::values.cpuopt_page_tables) {
config.page_table = nullptr;
}
@@ -223,20 +223,28 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
// Unsafe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
config.unsafe_optimizations = true;
- if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_unfuse_fma) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
}
- if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
- if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
- if (Settings::values.cpuopt_unsafe_fastmem_check.GetValue()) {
+ if (Settings::values.cpuopt_unsafe_fastmem_check) {
config.fastmem_address_space_bits = 64;
}
}
+ // Curated optimizations
+ if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
+ config.unsafe_optimizations = true;
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
+ config.fastmem_address_space_bits = 64;
+ }
+
return std::make_shared<Dynarmic::A64::Jit>(config);
}
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 {
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
- } else if (!Settings::values.gamecard_path.empty()) {
- fs_controller.SetGameCard(
- GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
+ } else if (!Settings::values.gamecard_path.GetValue().empty()) {
+ const auto gamecard_path = Settings::values.gamecard_path.GetValue();
+ fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, gamecard_path));
}
}
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;
void DefaultProfileSelectApplet::SelectProfile(
std::function<void(std::optional<Common::UUID>)> callback) const {
Service::Account::ProfileManager manager;
- callback(manager.GetUser(Settings::values.current_user).value_or(Common::UUID{}));
+ callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
}
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 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() {
CreateNewUser(UUID::Generate(), "yuzu");
}
- auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1);
+ auto current =
+ std::clamp<int>(static_cast<s32>(Settings::values.current_user), 0, MAX_USERS - 1);
// If user index don't exist. Load the first user and change the active user
if (!UserExistsIndex(current)) {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 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) {
params.is_account_selected = 1;
Account::ProfileManager profile_manager{};
- const auto uuid = profile_manager.GetUser(Settings::values.current_user);
+ const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
ASSERT(uuid);
params.current_user = uuid->uuid;
diff --git a/src/core/hle/service/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(
std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
DirectoryGetter getter) {
#ifdef YUZU_ENABLE_BOXCAT
- if (Settings::values.bcat_backend == "boxcat") {
+ if (Settings::values.bcat_backend.GetValue() == "boxcat") {
return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
}
#endif
diff --git a/src/core/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:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Settings::values.bcat_backend == "none") {
+ if (Settings::values.bcat_backend.GetValue() == "none") {
rb.PushEnum(RequestState::NotSubmitted);
} else {
rb.PushEnum(RequestState::Connected);
@@ -384,7 +384,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Settings::values.bcat_backend == "none") {
+ if (Settings::values.bcat_backend.GetValue() == "none") {
rb.Push<u8>(0);
} else {
rb.Push<u8>(1);
@@ -395,7 +395,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Settings::values.bcat_backend == "none") {
+ if (Settings::values.bcat_backend.GetValue() == "none") {
rb.Push<u8>(0);
} else {
rb.Push<u8>(1);
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 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) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(static_cast<u32>(Settings::values.quest_flag));
+ rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
}
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 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)
codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
}
- if (!Settings::values.program_args.empty()) {
- const auto arg_data = Settings::values.program_args;
+ if (!Settings::values.program_args.GetValue().empty()) {
+ const auto arg_data = Settings::values.program_args.GetValue();
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
NSOArgumentHeader args_header{
NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 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::
codeset.segments[i].size = nso_header.segments[i].size;
}
- if (should_pass_arguments && !Settings::values.program_args.empty()) {
- const auto arg_data{Settings::values.program_args};
+ if (should_pass_arguments && !Settings::values.program_args.GetValue().empty()) {
+ const auto arg_data{Settings::values.program_args.GetValue()};
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
NSOArgumentHeader args_header{
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 82b0f535a..cfaf50105 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -397,7 +397,7 @@ void Reporter::ClearFSAccessLog() const {
}
bool Reporter::IsReportingEnabled() const {
- return Settings::values.reporting_services;
+ return Settings::values.reporting_services.GetValue();
}
} // namespace Core
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index d4c23ced2..066cb23e4 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -135,7 +135,7 @@ u64 RegenerateTelemetryId() {
bool VerifyLogin(const std::string& username, const std::string& token) {
#ifdef ENABLE_WEB_SERVICE
- return WebService::VerifyLogin(Settings::values.web_api_url, username, token);
+ return WebService::VerifyLogin(Settings::values.web_api_url.GetValue(), username, token);
#else
return false;
#endif
@@ -152,7 +152,8 @@ TelemetrySession::~TelemetrySession() {
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
- Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
+ Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
+ Settings::values.yuzu_token.GetValue());
#else
auto backend = std::make_unique<Telemetry::NullVisitor>();
#endif
@@ -212,7 +213,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
// Log user configuration information
constexpr auto field_type = Telemetry::FieldType::UserConfig;
- AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
+ AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
AddField(field_type, "Audio_EnableAudioStretching",
Settings::values.enable_audio_stretching.GetValue());
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
@@ -242,7 +243,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
bool TelemetrySession::SubmitTestcase() {
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
- Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
+ Settings::values.web_api_url.GetValue(), Settings::values.yuzu_username.GetValue(),
+ Settings::values.yuzu_token.GetValue());
field_collection.Accept(*backend);
return backend->SubmitTestcase();
#else
diff --git a/src/input_common/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:
std::lock_guard lock{mutex};
const auto axis_value =
static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
- return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
+ const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue();
+ return axis_value * sensitivity / (100.0f * range);
}
std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
diff --git a/src/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 {
public:
TouchFromButtonDevice() {
const auto button_index =
- static_cast<std::size_t>(Settings::values.touch_from_button_map_index);
+ static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
const auto& buttons = Settings::values.touch_from_button_maps[button_index].buttons;
for (const auto& config_entry : buttons) {
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 {
void Client::ReloadSockets() {
Reset();
- std::stringstream servers_ss(Settings::values.udp_input_servers);
+ std::stringstream servers_ss(static_cast<std::string>(Settings::values.udp_input_servers));
std::string server_token;
std::size_t client = 0;
while (std::getline(servers_ss, server_token, ',')) {
@@ -370,7 +370,7 @@ std::optional<std::size_t> Client::GetUnusedFingerID() const {
void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) {
// TODO: Use custom calibration per device
- const Common::ParamPackage touch_param(Settings::values.touch_device);
+ const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100));
const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50));
const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800));
diff --git a/src/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
common/host_memory.cpp
common/param_package.cpp
common/ring_buffer.cpp
+ common/unique_function.cpp
core/core_timing.cpp
core/network/network.cpp
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <string>
+
+#include <catch2/catch.hpp>
+
+#include "common/unique_function.h"
+
+namespace {
+struct Noisy {
+ Noisy() : state{"Default constructed"} {}
+ Noisy(Noisy&& rhs) noexcept : state{"Move constructed"} {
+ rhs.state = "Moved away";
+ }
+ Noisy& operator=(Noisy&& rhs) noexcept {
+ state = "Move assigned";
+ rhs.state = "Moved away";
+ }
+ Noisy(const Noisy&) : state{"Copied constructed"} {}
+ Noisy& operator=(const Noisy&) {
+ state = "Copied assigned";
+ }
+
+ std::string state;
+};
+} // Anonymous namespace
+
+TEST_CASE("UniqueFunction", "[common]") {
+ SECTION("Capture reference") {
+ int value = 0;
+ Common::UniqueFunction<void> func = [&value] { value = 5; };
+ func();
+ REQUIRE(value == 5);
+ }
+ SECTION("Capture pointer") {
+ int value = 0;
+ int* pointer = &value;
+ Common::UniqueFunction<void> func = [pointer] { *pointer = 5; };
+ func();
+ REQUIRE(value == 5);
+ }
+ SECTION("Move object") {
+ Noisy noisy;
+ REQUIRE(noisy.state == "Default constructed");
+
+ Common::UniqueFunction<void> func = [noisy = std::move(noisy)] {
+ REQUIRE(noisy.state == "Move constructed");
+ };
+ REQUIRE(noisy.state == "Moved away");
+ func();
+ }
+ SECTION("Move construct function") {
+ int value = 0;
+ Common::UniqueFunction<void> func = [&value] { value = 5; };
+ Common::UniqueFunction<void> new_func = std::move(func);
+ new_func();
+ REQUIRE(value == 5);
+ }
+ SECTION("Move assign function") {
+ int value = 0;
+ Common::UniqueFunction<void> func = [&value] { value = 5; };
+ Common::UniqueFunction<void> new_func;
+ new_func = std::move(func);
+ new_func();
+ REQUIRE(value == 5);
+ }
+ SECTION("Default construct then assign function") {
+ int value = 0;
+ Common::UniqueFunction<void> func;
+ func = [&value] { value = 5; };
+ func();
+ REQUIRE(value == 5);
+ }
+ SECTION("Pass arguments") {
+ int result = 0;
+ Common::UniqueFunction<void, int, int> func = [&result](int a, int b) { result = a + b; };
+ func(5, 4);
+ REQUIRE(result == 9);
+ }
+ SECTION("Pass arguments and return value") {
+ Common::UniqueFunction<int, int, int> func = [](int a, int b) { return a + b; };
+ REQUIRE(func(5, 4) == 9);
+ }
+ SECTION("Destructor") {
+ int num_destroyed = 0;
+ struct Foo {
+ Foo(int* num_) : num{num_} {}
+ Foo(Foo&& rhs) : num{std::exchange(rhs.num, nullptr)} {}
+ Foo(const Foo&) = delete;
+
+ ~Foo() {
+ if (num) {
+ ++*num;
+ }
+ }
+
+ int* num = nullptr;
+ };
+ Foo object{&num_destroyed};
+ {
+ Common::UniqueFunction<void> func = [object = std::move(object)] {};
+ REQUIRE(num_destroyed == 0);
+ }
+ REQUIRE(num_destroyed == 1);
+ }
+}
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") {
REQUIRE(rasterizer.Count() == 63);
buffer.MarkRegionAsGpuModified(c + PAGE, PAGE);
int num = 0;
- buffer.ForEachDownloadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
+ buffer.ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; });
buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
REQUIRE(num == 0);
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:
/// Call 'func' for each CPU modified range and unmark those pages as CPU modified
template <typename Func>
void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) {
- ForEachModifiedRange<Type::CPU>(query_cpu_range, size, func);
+ ForEachModifiedRange<Type::CPU>(query_cpu_range, size, true, func);
}
/// Call 'func' for each GPU modified range and unmark those pages as GPU modified
template <typename Func>
- void ForEachDownloadRange(VAddr query_cpu_range, u64 size, Func&& func) {
- ForEachModifiedRange<Type::GPU>(query_cpu_range, size, func);
+ void ForEachDownloadRange(VAddr query_cpu_range, u64 size, bool clear, Func&& func) {
+ ForEachModifiedRange<Type::GPU>(query_cpu_range, size, clear, func);
+ }
+
+ template <typename Func>
+ void ForEachDownloadRangeAndClear(VAddr query_cpu_range, u64 size, Func&& func) {
+ ForEachModifiedRange<Type::GPU>(query_cpu_range, size, true, func);
}
/// Call 'func' for each GPU modified range and unmark those pages as GPU modified
template <typename Func>
void ForEachDownloadRange(Func&& func) {
- ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), func);
+ ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), true, func);
}
/// Mark buffer as picked
@@ -415,7 +420,7 @@ private:
* @param func Function to call for each turned off region
*/
template <Type type, typename Func>
- void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) {
+ void ForEachModifiedRange(VAddr query_cpu_range, s64 size, bool clear, Func&& func) {
static_assert(type != Type::Untracked);
const s64 difference = query_cpu_range - cpu_addr;
@@ -467,7 +472,9 @@ private:
bits = (bits << left_offset) >> left_offset;
const u64 current_word = state_words[word_index] & bits;
- state_words[word_index] &= ~bits;
+ if (clear) {
+ state_words[word_index] &= ~bits;
+ }
if constexpr (type == Type::CPU) {
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 @@
#include <vector>
#include <boost/container/small_vector.hpp>
+#include <boost/icl/interval_set.hpp>
#include "common/common_types.h"
#include "common/div_ceil.h"
@@ -77,6 +78,9 @@ class BufferCache {
using Runtime = typename P::Runtime;
using Buffer = typename P::Buffer;
+ using IntervalSet = boost::icl::interval_set<VAddr>;
+ using IntervalType = typename IntervalSet::interval_type;
+
struct Empty {};
struct OverlapResult {
@@ -148,18 +152,26 @@ public:
/// Return true when there are uncommitted buffers to be downloaded
[[nodiscard]] bool HasUncommittedFlushes() const noexcept;
+ void AccumulateFlushes();
+
/// Return true when the caller should wait for async downloads
[[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
/// Commit asynchronous downloads
void CommitAsyncFlushes();
+ void CommitAsyncFlushesHigh();
/// Pop asynchronous downloads
void PopAsyncFlushes();
+ [[nodiscard]] bool DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount);
+
/// Return true when a CPU region is modified from the GPU
[[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
+ /// Return true when a CPU region is modified from the CPU
+ [[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size);
+
std::mutex mutex;
private:
@@ -190,6 +202,36 @@ private:
}
}
+ template <typename Func>
+ void ForEachWrittenRange(VAddr cpu_addr, u64 size, Func&& func) {
+ const VAddr start_address = cpu_addr;
+ const VAddr end_address = start_address + size;
+ const VAddr search_base =
+ static_cast<VAddr>(std::min<s64>(0LL, static_cast<s64>(start_address - size)));
+ const IntervalType search_interval{search_base, search_base + 1};
+ auto it = common_ranges.lower_bound(search_interval);
+ if (it == common_ranges.end()) {
+ it = common_ranges.begin();
+ }
+ for (; it != common_ranges.end(); it++) {
+ VAddr inter_addr_end = it->upper();
+ VAddr inter_addr = it->lower();
+ if (inter_addr >= end_address) {
+ break;
+ }
+ if (inter_addr_end <= start_address) {
+ continue;
+ }
+ if (inter_addr_end > end_address) {
+ inter_addr_end = end_address;
+ }
+ if (inter_addr < start_address) {
+ inter_addr = start_address;
+ }
+ func(inter_addr, inter_addr_end);
+ }
+ }
+
static bool IsRangeGranular(VAddr cpu_addr, size_t size) {
return (cpu_addr & ~Core::Memory::PAGE_MASK) ==
((cpu_addr + size) & ~Core::Memory::PAGE_MASK);
@@ -272,8 +314,6 @@ private:
void DeleteBuffer(BufferId buffer_id);
- void ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id);
-
void NotifyBufferDeletion();
[[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const;
@@ -327,9 +367,9 @@ private:
std::vector<BufferId> cached_write_buffer_ids;
- // TODO: This data structure is not optimal and it should be reworked
- std::vector<BufferId> uncommitted_downloads;
- std::deque<std::vector<BufferId>> committed_downloads;
+ IntervalSet uncommitted_ranges;
+ IntervalSet common_ranges;
+ std::deque<IntervalSet> committed_ranges;
size_t immediate_buffer_capacity = 0;
std::unique_ptr<u8[]> immediate_buffer_alloc;
@@ -352,6 +392,7 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
// Ensure the first slot is used for the null buffer
void(slot_buffers.insert(runtime, NullBufferParams{}));
deletion_iterator = slot_buffers.end();
+ common_ranges.clear();
}
template <class P>
@@ -422,6 +463,68 @@ void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
}
template <class P>
+bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
+ const std::optional<VAddr> cpu_src_address = gpu_memory.GpuToCpuAddress(src_address);
+ const std::optional<VAddr> cpu_dest_address = gpu_memory.GpuToCpuAddress(dest_address);
+ if (!cpu_src_address || !cpu_dest_address) {
+ return false;
+ }
+ const bool source_dirty = IsRegionGpuModified(*cpu_src_address, amount);
+ const bool dest_dirty = IsRegionGpuModified(*cpu_dest_address, amount);
+ if (!source_dirty && !dest_dirty) {
+ return false;
+ }
+
+ const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
+ uncommitted_ranges.subtract(subtract_interval);
+ for (auto& interval_set : committed_ranges) {
+ interval_set.subtract(subtract_interval);
+ }
+
+ BufferId buffer_a;
+ BufferId buffer_b;
+ do {
+ has_deleted_buffers = false;
+ buffer_a = FindBuffer(*cpu_src_address, static_cast<u32>(amount));
+ buffer_b = FindBuffer(*cpu_dest_address, static_cast<u32>(amount));
+ } while (has_deleted_buffers);
+ auto& src_buffer = slot_buffers[buffer_a];
+ auto& dest_buffer = slot_buffers[buffer_b];
+ SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
+ SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount));
+ std::array copies{BufferCopy{
+ .src_offset = src_buffer.Offset(*cpu_src_address),
+ .dst_offset = dest_buffer.Offset(*cpu_dest_address),
+ .size = amount,
+ }};
+
+ boost::container::small_vector<IntervalType, 4> tmp_intervals;
+ auto mirror = [&](VAddr base_address, VAddr base_address_end) {
+ const u64 size = base_address_end - base_address;
+ const VAddr diff = base_address - *cpu_src_address;
+ const VAddr new_base_address = *cpu_dest_address + diff;
+ const IntervalType add_interval{new_base_address, new_base_address + size};
+ uncommitted_ranges.add(add_interval);
+ tmp_intervals.push_back(add_interval);
+ };
+ ForEachWrittenRange(*cpu_src_address, amount, mirror);
+ // This subtraction in this order is important for overlapping copies.
+ common_ranges.subtract(subtract_interval);
+ for (const IntervalType add_interval : tmp_intervals) {
+ common_ranges.add(add_interval);
+ }
+
+ runtime.CopyBuffer(dest_buffer, src_buffer, copies);
+ if (source_dirty) {
+ dest_buffer.MarkRegionAsGpuModified(*cpu_dest_address, amount);
+ }
+ std::vector<u8> tmp_buffer(amount);
+ cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount);
+ cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount);
+ return true;
+}
+
+template <class P>
void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr,
u32 size) {
const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
@@ -547,29 +650,30 @@ void BufferCache<P>::FlushCachedWrites() {
template <class P>
bool BufferCache<P>::HasUncommittedFlushes() const noexcept {
- return !uncommitted_downloads.empty();
+ return !uncommitted_ranges.empty() || !committed_ranges.empty();
}
template <class P>
-bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
- return !committed_downloads.empty() && !committed_downloads.front().empty();
+void BufferCache<P>::AccumulateFlushes() {
+ if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) {
+ uncommitted_ranges.clear();
+ return;
+ }
+ if (uncommitted_ranges.empty()) {
+ return;
+ }
+ committed_ranges.emplace_back(std::move(uncommitted_ranges));
}
template <class P>
-void BufferCache<P>::CommitAsyncFlushes() {
- // This is intentionally passing the value by copy
- committed_downloads.push_front(uncommitted_downloads);
- uncommitted_downloads.clear();
+bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
+ return false;
}
template <class P>
-void BufferCache<P>::PopAsyncFlushes() {
- if (committed_downloads.empty()) {
- return;
- }
- auto scope_exit_pop_download = detail::ScopeExit([this] { committed_downloads.pop_back(); });
- const std::span<const BufferId> download_ids = committed_downloads.back();
- if (download_ids.empty()) {
+void BufferCache<P>::CommitAsyncFlushesHigh() {
+ AccumulateFlushes();
+ if (committed_ranges.empty()) {
return;
}
MICROPROFILE_SCOPE(GPU_DownloadMemory);
@@ -577,20 +681,43 @@ void BufferCache<P>::PopAsyncFlushes() {
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
u64 total_size_bytes = 0;
u64 largest_copy = 0;
- for (const BufferId buffer_id : download_ids) {
- slot_buffers[buffer_id].ForEachDownloadRange([&](u64 range_offset, u64 range_size) {
- downloads.push_back({
- BufferCopy{
- .src_offset = range_offset,
- .dst_offset = total_size_bytes,
- .size = range_size,
- },
- buffer_id,
+ for (const IntervalSet& intervals : committed_ranges) {
+ for (auto& interval : intervals) {
+ const std::size_t size = interval.upper() - interval.lower();
+ const VAddr cpu_addr = interval.lower();
+ ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
+ boost::container::small_vector<BufferCopy, 1> copies;
+ buffer.ForEachDownloadRangeAndClear(
+ cpu_addr, size, [&](u64 range_offset, u64 range_size) {
+ const VAddr buffer_addr = buffer.CpuAddr();
+ const auto add_download = [&](VAddr start, VAddr end) {
+ const u64 new_offset = start - buffer_addr;
+ const u64 new_size = end - start;
+ downloads.push_back({
+ BufferCopy{
+ .src_offset = new_offset,
+ .dst_offset = total_size_bytes,
+ .size = new_size,
+ },
+ buffer_id,
+ });
+ // Align up to avoid cache conflicts
+ constexpr u64 align = 256ULL;
+ constexpr u64 mask = ~(align - 1ULL);
+ total_size_bytes += (new_size + align - 1) & mask;
+ largest_copy = std::max(largest_copy, new_size);
+ };
+
+ const VAddr start_address = buffer_addr + range_offset;
+ const VAddr end_address = start_address + range_size;
+ ForEachWrittenRange(start_address, range_size, add_download);
+ const IntervalType subtract_interval{start_address, end_address};
+ common_ranges.subtract(subtract_interval);
+ });
});
- total_size_bytes += range_size;
- largest_copy = std::max(largest_copy, range_size);
- });
+ }
}
+ committed_ranges.clear();
if (downloads.empty()) {
return;
}
@@ -623,6 +750,19 @@ void BufferCache<P>::PopAsyncFlushes() {
}
template <class P>
+void BufferCache<P>::CommitAsyncFlushes() {
+ if (Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High) {
+ CommitAsyncFlushesHigh();
+ } else {
+ uncommitted_ranges.clear();
+ committed_ranges.clear();
+ }
+}
+
+template <class P>
+void BufferCache<P>::PopAsyncFlushes() {}
+
+template <class P>
bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
for (u64 page = addr >> PAGE_BITS; page < page_end;) {
@@ -642,6 +782,25 @@ bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
}
template <class P>
+bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) {
+ const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
+ for (u64 page = addr >> PAGE_BITS; page < page_end;) {
+ const BufferId image_id = page_table[page];
+ if (!image_id) {
+ ++page;
+ continue;
+ }
+ Buffer& buffer = slot_buffers[image_id];
+ if (buffer.IsRegionCpuModified(addr, size)) {
+ return true;
+ }
+ const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
+ page = Common::DivCeil(end_addr, PAGE_SIZE);
+ }
+ return false;
+}
+
+template <class P>
void BufferCache<P>::BindHostIndexBuffer() {
Buffer& buffer = slot_buffers[index_buffer.buffer_id];
TouchBuffer(buffer);
@@ -649,7 +808,9 @@ void BufferCache<P>::BindHostIndexBuffer() {
const u32 size = index_buffer.size;
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
- runtime.BindIndexBuffer(buffer, offset, size);
+ const u32 new_offset = offset + maxwell3d.regs.index_array.first *
+ maxwell3d.regs.index_array.FormatSizeInBytes();
+ runtime.BindIndexBuffer(buffer, new_offset, size);
} else {
runtime.BindIndexBuffer(maxwell3d.regs.draw.topology, maxwell3d.regs.index_array.format,
maxwell3d.regs.index_array.first, maxwell3d.regs.index_array.count,
@@ -863,7 +1024,7 @@ void BufferCache<P>::UpdateIndexBuffer() {
const GPUVAddr gpu_addr_end = index_array.EndAddress();
const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr_begin);
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
- const u32 draw_size = index_array.count * index_array.FormatSizeInBytes();
+ const u32 draw_size = (index_array.count + index_array.first) * index_array.FormatSizeInBytes();
const u32 size = std::min(address_size, draw_size);
if (size == 0 || !cpu_addr) {
index_buffer = NULL_BINDING;
@@ -1010,16 +1171,16 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 s
Buffer& buffer = slot_buffers[buffer_id];
buffer.MarkRegionAsGpuModified(cpu_addr, size);
- const bool is_accuracy_high = Settings::IsGPULevelHigh();
+ const IntervalType base_interval{cpu_addr, cpu_addr + size};
+ common_ranges.add(base_interval);
+
+ const bool is_accuracy_high =
+ Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High;
const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
- if (!is_accuracy_high || !is_async) {
- return;
- }
- if (std::ranges::find(uncommitted_downloads, buffer_id) != uncommitted_downloads.end()) {
- // Already inserted
+ if (!is_async && !is_accuracy_high) {
return;
}
- uncommitted_downloads.push_back(buffer_id);
+ uncommitted_ranges.add(base_interval);
}
template <class P>
@@ -1103,7 +1264,6 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
if (!copies.empty()) {
runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies);
}
- ReplaceBufferDownloads(overlap_id, new_buffer_id);
DeleteBuffer(overlap_id);
}
@@ -1244,14 +1404,28 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
boost::container::small_vector<BufferCopy, 1> copies;
u64 total_size_bytes = 0;
u64 largest_copy = 0;
- buffer.ForEachDownloadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
- copies.push_back(BufferCopy{
- .src_offset = range_offset,
- .dst_offset = total_size_bytes,
- .size = range_size,
- });
- total_size_bytes += range_size;
- largest_copy = std::max(largest_copy, range_size);
+ buffer.ForEachDownloadRangeAndClear(cpu_addr, size, [&](u64 range_offset, u64 range_size) {
+ const VAddr buffer_addr = buffer.CpuAddr();
+ const auto add_download = [&](VAddr start, VAddr end) {
+ const u64 new_offset = start - buffer_addr;
+ const u64 new_size = end - start;
+ copies.push_back(BufferCopy{
+ .src_offset = new_offset,
+ .dst_offset = total_size_bytes,
+ .size = new_size,
+ });
+ // Align up to avoid cache conflicts
+ constexpr u64 align = 256ULL;
+ constexpr u64 mask = ~(align - 1ULL);
+ total_size_bytes += (new_size + align - 1) & mask;
+ largest_copy = std::max(largest_copy, new_size);
+ };
+
+ const VAddr start_address = buffer_addr + range_offset;
+ const VAddr end_address = start_address + range_size;
+ ForEachWrittenRange(start_address, range_size, add_download);
+ const IntervalType subtract_interval{start_address, end_address};
+ common_ranges.subtract(subtract_interval);
});
if (total_size_bytes == 0) {
return;
@@ -1316,18 +1490,6 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id) {
}
template <class P>
-void BufferCache<P>::ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id) {
- const auto replace = [old_buffer_id, new_buffer_id](std::vector<BufferId>& buffers) {
- std::ranges::replace(buffers, old_buffer_id, new_buffer_id);
- if (auto it = std::ranges::find(buffers, new_buffer_id); it != buffers.end()) {
- buffers.erase(std::remove(it + 1, buffers.end(), new_buffer_id), buffers.end());
- }
- };
- replace(uncommitted_downloads);
- std::ranges::for_each(committed_downloads, replace);
-}
-
-template <class P>
void BufferCache<P>::NotifyBufferDeletion() {
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
dirty_uniform_buffers.fill(~u32{0});
@@ -1349,15 +1511,9 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
if (!cpu_addr || size == 0) {
return NULL_BINDING;
}
- // HACK(Rodrigo): This is the number of bytes bound in host beyond the guest API's range.
- // It exists due to some games like Astral Chain operate out of bounds.
- // Binding the whole map range would be technically correct, but games have large maps that make
- // this approach unaffordable for now.
- static constexpr u32 arbitrary_extra_bytes = 0xc000;
- const u32 bytes_to_map_end = static_cast<u32>(gpu_memory.BytesToMapEnd(gpu_addr));
const Binding binding{
.cpu_addr = *cpu_addr,
- .size = std::min(size + arbitrary_extra_bytes, bytes_to_map_end),
+ .size = size,
.buffer_id = BufferId{},
};
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 @@
#include "common/cityhash.h"
#include "common/microprofile.h"
+#include "common/settings.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/dma_pusher.h"
@@ -76,8 +77,13 @@ bool DmaPusher::Step() {
// Push buffer non-empty, read a word
command_headers.resize(command_list_header.size);
- gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(),
- command_list_header.size * sizeof(u32));
+ if (Settings::IsGPULevelHigh()) {
+ gpu.MemoryManager().ReadBlock(dma_get, command_headers.data(),
+ command_list_header.size * sizeof(u32));
+ } else {
+ gpu.MemoryManager().ReadBlockUnsafe(dma_get, command_headers.data(),
+ command_list_header.size * sizeof(u32));
+ }
}
for (std::size_t index = 0; index < command_headers.size();) {
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 @@
#include "video_core/engines/fermi_2d.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
+#include "video_core/surface.h"
+
+using VideoCore::Surface::BytesPerBlock;
+using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
namespace Tegra::Engines {
@@ -49,7 +53,7 @@ void Fermi2D::Blit() {
UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
const auto& args = regs.pixels_from_memory;
- const Config config{
+ Config config{
.operation = regs.operation,
.filter = args.sample_mode.filter,
.dst_x0 = args.dst_x0,
@@ -61,7 +65,21 @@ void Fermi2D::Blit() {
.src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32),
.src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32),
};
- if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, config)) {
+ Surface src = regs.src;
+ const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
+ const auto need_align_to_pitch =
+ src.linear == Tegra::Engines::Fermi2D::MemoryLayout::Pitch &&
+ static_cast<s32>(src.width) == config.src_x1 &&
+ config.src_x1 > static_cast<s32>(src.pitch / bytes_per_pixel) && config.src_x0 > 0;
+ if (need_align_to_pitch) {
+ auto address = src.Address() + config.src_x0 * bytes_per_pixel;
+ src.addr_upper = static_cast<u32>(address >> 32);
+ src.addr_lower = static_cast<u32>(address);
+ src.width -= config.src_x0;
+ config.src_x1 -= config.src_x0;
+ config.src_x0 = 0;
+ }
+ if (!rasterizer->AccelerateSurfaceCopy(src, regs.dst, config)) {
UNIMPLEMENTED();
}
}
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_)
MaxwellDMA::~MaxwellDMA() = default;
+void MaxwellDMA::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
+ rasterizer = rasterizer_;
+}
+
void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register");
@@ -44,7 +48,6 @@ void MaxwellDMA::Launch() {
// TODO(Subv): Perform more research and implement all features of this engine.
const LaunchDMA& launch = regs.launch_dma;
- ASSERT(launch.remap_enable == 0);
ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE);
ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE);
ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED);
@@ -77,11 +80,29 @@ void MaxwellDMA::CopyPitchToPitch() {
// When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D
// buffer of length `line_length_in`.
// Otherwise we copy a 2D image of dimensions (line_length_in, line_count).
+ auto& accelerate = rasterizer->AccessAccelerateDMA();
if (!regs.launch_dma.multi_line_enable) {
- memory_manager.CopyBlock(regs.offset_out, regs.offset_in, regs.line_length_in);
+ const bool is_buffer_clear = regs.launch_dma.remap_enable != 0 &&
+ regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A;
+ // TODO: allow multisized components.
+ if (is_buffer_clear) {
+ ASSERT(regs.remap_const.component_size_minus_one == 3);
+ std::vector<u32> tmp_buffer(regs.line_length_in, regs.remap_consta_value);
+ memory_manager.WriteBlock(regs.offset_out, reinterpret_cast<u8*>(tmp_buffer.data()),
+ regs.line_length_in * sizeof(u32));
+ return;
+ }
+ UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
+ if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
+ std::vector<u8> tmp_buffer(regs.line_length_in);
+ memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), regs.line_length_in);
+ memory_manager.WriteBlock(regs.offset_out, tmp_buffer.data(), regs.line_length_in);
+ }
return;
}
+ UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
+
// Perform a line-by-line copy.
// We're going to take a subrect of size (line_length_in, line_count) from the source rectangle.
// There is no need to manually flush/invalidate the regions because CopyBlock does that for us.
@@ -105,6 +126,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
}
// Deswizzle the input and copy it over.
+ UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in;
const Parameters& src_params = regs.src_params;
const u32 width = src_params.width;
@@ -134,6 +156,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
void MaxwellDMA::CopyPitchToBlockLinear() {
UNIMPLEMENTED_IF_MSG(regs.dst_params.block_size.width != 0, "Block width is not one");
+ UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
const auto& dst_params = regs.dst_params;
const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in;
@@ -156,13 +179,8 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
write_buffer.resize(dst_size);
}
- if (Settings::IsGPULevelExtreme()) {
- memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
- memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
- } else {
- memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
- memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
- }
+ memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
+ memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
// If the input is linear and the output is tiled, swizzle the input and copy it over.
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 {
class MemoryManager;
}
+namespace VideoCore {
+class RasterizerInterface;
+}
+
namespace Tegra::Engines {
+class AccelerateDMAInterface {
+public:
+ /// Write the value to the register identified by method.
+ virtual bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) = 0;
+};
+
/**
* This engine is known as gk104_copy. Documentation can be found in:
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h
@@ -187,6 +197,8 @@ public:
};
static_assert(sizeof(RemapConst) == 12);
+ void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
+
explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
~MaxwellDMA() override;
@@ -213,6 +225,7 @@ private:
Core::System& system;
MemoryManager& memory_manager;
+ VideoCore::RasterizerInterface* rasterizer;
std::vector<u8> read_buffer;
std::vector<u8> write_buffer;
@@ -240,7 +253,9 @@ private:
u32 pitch_out;
u32 line_length_in;
u32 line_count;
- u32 reserved06[0xb8];
+ u32 reserved06[0xb6];
+ u32 remap_consta_value;
+ u32 remap_constb_value;
RemapConst remap_const;
Parameters dst_params;
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 @@
#include <queue>
#include "common/common_types.h"
+#include "common/settings.h"
#include "core/core.h"
#include "video_core/delayed_destruction_ring.h"
#include "video_core/gpu.h"
@@ -53,6 +54,12 @@ public:
delayed_destruction_ring.Tick();
}
+ // Unlike other fences, this one doesn't
+ void SignalOrdering() {
+ std::scoped_lock lock{buffer_cache.mutex};
+ buffer_cache.AccumulateFlushes();
+ }
+
void SignalSemaphore(GPUVAddr addr, u32 value) {
TryReleasePendingFences();
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_) {
maxwell_3d->BindRasterizer(rasterizer);
fermi_2d->BindRasterizer(rasterizer);
kepler_compute->BindRasterizer(rasterizer);
+ maxwell_dma->BindRasterizer(rasterizer);
}
Engines::Maxwell3D& GPU::Maxwell3D() {
@@ -268,11 +269,13 @@ void GPU::CallPullerMethod(const MethodCall& method_call) {
case BufferMethods::SemaphoreAddressHigh:
case BufferMethods::SemaphoreAddressLow:
case BufferMethods::SemaphoreSequence:
- case BufferMethods::RefCnt:
case BufferMethods::UnkCacheFlush:
case BufferMethods::WrcacheFlush:
case BufferMethods::FenceValue:
break;
+ case BufferMethods::RefCnt:
+ rasterizer->SignalReference();
+ break;
case BufferMethods::FenceAction:
ProcessFenceActionMethod();
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 @@
namespace Tegra {
class MemoryManager;
+namespace Engines {
+class AccelerateDMAInterface;
}
+} // namespace Tegra
namespace VideoCore {
@@ -63,6 +66,9 @@ public:
/// Signal a GPU based syncpoint as a fence
virtual void SignalSyncPoint(u32 value) = 0;
+ /// Signal a GPU based reference as point
+ virtual void SignalReference() = 0;
+
/// Release all pending fences.
virtual void ReleaseFences() = 0;
@@ -116,6 +122,8 @@ public:
return false;
}
+ [[nodiscard]] virtual Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() = 0;
+
/// Attempt to use a faster method to display the framebuffer to screen
[[nodiscard]] virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config,
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
buffer_cache_runtime(device),
buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
shader_cache(*this, emu_window_, gpu, maxwell3d, kepler_compute, gpu_memory, device),
- query_cache(*this, maxwell3d, gpu_memory),
+ query_cache(*this, maxwell3d, gpu_memory), accelerate_dma(buffer_cache),
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
async_shaders(emu_window_) {
if (device.UseAsynchronousShaders()) {
@@ -634,6 +634,13 @@ void RasterizerOpenGL::SignalSyncPoint(u32 value) {
fence_manager.SignalSyncPoint(value);
}
+void RasterizerOpenGL::SignalReference() {
+ if (!gpu.IsAsync()) {
+ return;
+ }
+ fence_manager.SignalOrdering();
+}
+
void RasterizerOpenGL::ReleaseFences() {
if (!gpu.IsAsync()) {
return;
@@ -650,6 +657,7 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
void RasterizerOpenGL::WaitForIdle() {
glMemoryBarrier(GL_ALL_BARRIER_BITS);
+ SignalReference();
}
void RasterizerOpenGL::FragmentBarrier() {
@@ -693,6 +701,10 @@ bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surf
return true;
}
+Tegra::Engines::AccelerateDMAInterface& RasterizerOpenGL::AccessAccelerateDMA() {
+ return accelerate_dma;
+}
+
bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
VAddr framebuffer_addr, u32 pixel_stride) {
if (framebuffer_addr == 0) {
@@ -1388,4 +1400,11 @@ void RasterizerOpenGL::EndTransformFeedback() {
glEndTransformFeedback();
}
+AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
+
+bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
+ std::scoped_lock lock{buffer_cache.mutex};
+ return buffer_cache.DMACopy(src_address, dest_address, amount);
+}
+
} // 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 @@
#include "common/common_types.h"
#include "video_core/engines/const_buffer_info.h"
#include "video_core/engines/maxwell_3d.h"
+#include "video_core/engines/maxwell_dma.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_buffer_cache.h"
@@ -58,6 +59,16 @@ struct BindlessSSBO {
};
static_assert(sizeof(BindlessSSBO) * CHAR_BIT == 128);
+class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface {
+public:
+ explicit AccelerateDMA(BufferCache& buffer_cache);
+
+ bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) override;
+
+private:
+ BufferCache& buffer_cache;
+};
+
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
public:
explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -83,6 +94,7 @@ public:
void ModifyGPUMemory(GPUVAddr addr, u64 size) override;
void SignalSemaphore(GPUVAddr addr, u32 value) override;
void SignalSyncPoint(u32 value) override;
+ void SignalReference() override;
void ReleaseFences() override;
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
void WaitForIdle() override;
@@ -93,6 +105,7 @@ public:
bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
const Tegra::Engines::Fermi2D::Surface& dst,
const Tegra::Engines::Fermi2D::Config& copy_config) override;
+ Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
@@ -233,6 +246,7 @@ private:
BufferCache buffer_cache;
ShaderCacheOpenGL shader_cache;
QueryCache query_cache;
+ AccelerateDMA accelerate_dma;
FenceManagerOpenGL fence_manager;
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_,
gpu(gpu_),
library(OpenLibrary()),
instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
- true, Settings::values.renderer_debug)),
+ true, Settings::values.renderer_debug.GetValue())),
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
surface(CreateSurface(instance, render_window)),
device(CreateDevice(instance, dld, *surface)),
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
buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
descriptor_pool, update_descriptor_queue),
- query_cache{*this, maxwell3d, gpu_memory, device, scheduler},
+ query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{buffer_cache},
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) {
scheduler.SetQueryCache(query_cache);
@@ -580,6 +580,13 @@ void RasterizerVulkan::SignalSyncPoint(u32 value) {
fence_manager.SignalSyncPoint(value);
}
+void RasterizerVulkan::SignalReference() {
+ if (!gpu.IsAsync()) {
+ return;
+ }
+ fence_manager.SignalOrdering();
+}
+
void RasterizerVulkan::ReleaseFences() {
if (!gpu.IsAsync()) {
return;
@@ -612,6 +619,7 @@ void RasterizerVulkan::WaitForIdle() {
cmdbuf.SetEvent(event, flags);
cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {});
});
+ SignalReference();
}
void RasterizerVulkan::FragmentBarrier() {
@@ -652,6 +660,10 @@ bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surf
return true;
}
+Tegra::Engines::AccelerateDMAInterface& RasterizerVulkan::AccessAccelerateDMA() {
+ return accelerate_dma;
+}
+
bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
VAddr framebuffer_addr, u32 pixel_stride) {
if (!framebuffer_addr) {
@@ -690,6 +702,13 @@ void RasterizerVulkan::FlushWork() {
draw_counter = 0;
}
+AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {}
+
+bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) {
+ std::scoped_lock lock{buffer_cache.mutex};
+ return buffer_cache.DMACopy(src_address, dest_address, amount);
+}
+
void RasterizerVulkan::SetupShaderDescriptors(
const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders, bool is_indexed) {
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 @@
#include <boost/container/static_vector.hpp>
#include "common/common_types.h"
+#include "video_core/engines/maxwell_dma.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_vulkan/blit_image.h"
@@ -49,6 +50,16 @@ struct VKScreenInfo;
class StateTracker;
+class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface {
+public:
+ explicit AccelerateDMA(BufferCache& buffer_cache);
+
+ bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override;
+
+private:
+ BufferCache& buffer_cache;
+};
+
class RasterizerVulkan final : public VideoCore::RasterizerAccelerated {
public:
explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -75,6 +86,7 @@ public:
void ModifyGPUMemory(GPUVAddr addr, u64 size) override;
void SignalSemaphore(GPUVAddr addr, u32 value) override;
void SignalSyncPoint(u32 value) override;
+ void SignalReference() override;
void ReleaseFences() override;
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
void WaitForIdle() override;
@@ -85,6 +97,7 @@ public:
bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
const Tegra::Engines::Fermi2D::Surface& dst,
const Tegra::Engines::Fermi2D::Config& copy_config) override;
+ Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override;
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
u32 pixel_stride) override;
@@ -185,6 +198,7 @@ private:
BufferCache buffer_cache;
VKPipelineCache pipeline_cache;
VKQueryCache query_cache;
+ AccelerateDMA accelerate_dma;
VKFenceManager fence_manager;
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:
/// Blit an image with the given parameters
void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const Tegra::Engines::Fermi2D::Surface& src,
- const Tegra::Engines::Fermi2D::Config& copy,
- std::optional<Region2D> src_region_override = {},
- std::optional<Region2D> dst_region_override = {});
+ const Tegra::Engines::Fermi2D::Config& copy);
/// Invalidate the contents of the color buffer index
/// These contents become unspecified, the cache can assume aggressive optimizations.
@@ -760,9 +758,7 @@ void TextureCache<P>::UnmapGPUMemory(GPUVAddr gpu_addr, size_t size) {
template <class P>
void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const Tegra::Engines::Fermi2D::Surface& src,
- const Tegra::Engines::Fermi2D::Config& copy,
- std::optional<Region2D> src_override,
- std::optional<Region2D> dst_override) {
+ const Tegra::Engines::Fermi2D::Config& copy) {
const BlitImages images = GetBlitImages(dst, src);
const ImageId dst_id = images.dst_id;
const ImageId src_id = images.src_id;
@@ -773,47 +769,25 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const ImageBase& src_image = slot_images[src_id];
// TODO: Deduplicate
- const std::optional dst_base = dst_image.TryFindBase(dst.Address());
- const SubresourceRange dst_range{.base = dst_base.value(), .extent = {1, 1}};
- const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
- const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
- const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
-
- // out of bounds texture blit checking
- const bool use_override = src_override.has_value();
- const s32 src_x0 = copy.src_x0 >> src_samples_x;
- s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x;
- const s32 src_y0 = copy.src_y0 >> src_samples_y;
- const s32 src_y1 = copy.src_y1 >> src_samples_y;
-
- const auto src_width = static_cast<s32>(src_image.info.size.width);
- const bool width_oob = src_x1 > src_width;
- const auto width_diff = width_oob ? src_x1 - src_width : 0;
- if (width_oob) {
- src_x1 = src_width;
- }
-
- const Region2D src_dimensions{
- Offset2D{.x = src_x0, .y = src_y0},
- Offset2D{.x = src_x1, .y = src_y1},
- };
- const auto src_region = use_override ? *src_override : src_dimensions;
-
const std::optional src_base = src_image.TryFindBase(src.Address());
const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}};
const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range);
const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info);
- const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
+ const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
+ const Region2D src_region{
+ Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y},
+ Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y},
+ };
- const s32 dst_x0 = copy.dst_x0 >> dst_samples_x;
- const s32 dst_x1 = copy.dst_x1 >> dst_samples_x;
- const s32 dst_y0 = copy.dst_y0 >> dst_samples_y;
- const s32 dst_y1 = copy.dst_y1 >> dst_samples_y;
- const Region2D dst_dimensions{
- Offset2D{.x = dst_x0, .y = dst_y0},
- Offset2D{.x = dst_x1 - width_diff, .y = dst_y1},
+ const std::optional dst_base = dst_image.TryFindBase(dst.Address());
+ const SubresourceRange dst_range{.base = dst_base.value(), .extent = {1, 1}};
+ const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
+ const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
+ const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
+ const Region2D dst_region{
+ Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y},
+ Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y},
};
- const auto dst_region = use_override ? *dst_override : dst_dimensions;
// Always call this after src_framebuffer_id was queried, as the address might be invalidated.
Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id];
@@ -830,21 +804,6 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter,
copy.operation);
}
-
- if (width_oob) {
- // Continue copy of the oob region of the texture on the next row
- auto oob_src = src;
- oob_src.height++;
- const Region2D src_region_override{
- Offset2D{.x = 0, .y = src_y0 + 1},
- Offset2D{.x = width_diff, .y = src_y1 + 1},
- };
- const Region2D dst_region_override{
- Offset2D{.x = dst_x1 - width_diff, .y = dst_y0},
- Offset2D{.x = dst_x1, .y = dst_y1},
- };
- BlitImage(dst, oob_src, copy, src_region_override, dst_region_override);
- }
}
template <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 {
};
struct BufferCopy {
- size_t src_offset;
- size_t dst_offset;
+ u64 src_offset;
+ u64 dst_offset;
size_t size;
};
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
configuration/configure_debug_controller.cpp
configuration/configure_debug_controller.h
configuration/configure_debug_controller.ui
+ configuration/configure_debug_tab.cpp
+ configuration/configure_debug_tab.h
+ configuration/configure_debug_tab.ui
configuration/configure_dialog.cpp
configuration/configure_dialog.h
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) {
}
}
+/* {Read,Write}BasicSetting and WriteGlobalSetting templates must be defined here before their
+ * usages later in this file. This allows explicit definition of some types that don't work
+ * nicely with the general version.
+ */
+
+// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
+// can it implicitly convert a QVariant back to a {std::,Q}string
+template <>
+void Config::ReadBasicSetting(Settings::BasicSetting<std::string>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const auto default_value = QString::fromStdString(setting.GetDefault());
+ if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
+ setting.SetValue(default_value.toStdString());
+ } else {
+ setting.SetValue(qt_config->value(name, default_value).toString().toStdString());
+ }
+}
+
+template <typename Type>
+void Config::ReadBasicSetting(Settings::BasicSetting<Type>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const Type default_value = setting.GetDefault();
+ if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
+ setting.SetValue(default_value);
+ } else {
+ setting.SetValue(
+ static_cast<QVariant>(qt_config->value(name, default_value)).value<Type>());
+ }
+}
+
+// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant
+template <>
+void Config::WriteBasicSetting(const Settings::BasicSetting<std::string>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const std::string& value = setting.GetValue();
+ qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
+ qt_config->setValue(name, QString::fromStdString(value));
+}
+
+// Explicit float definition: use a double as Qt doesn't write legible floats to config files
+template <>
+void Config::WriteBasicSetting(const Settings::BasicSetting<float>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const double value = setting.GetValue();
+ qt_config->setValue(name + QStringLiteral("/default"),
+ setting.GetValue() == setting.GetDefault());
+ qt_config->setValue(name, value);
+}
+
+template <typename Type>
+void Config::WriteBasicSetting(const Settings::BasicSetting<Type>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const Type value = setting.GetValue();
+ qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
+ qt_config->setValue(name, value);
+}
+
+// Explicit float definition: use a double as Qt doesn't write legible floats to config files
+template <>
+void Config::WriteGlobalSetting(const Settings::Setting<float>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const double value = setting.GetValue(global);
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+ }
+ if (global || !setting.UsingGlobal()) {
+ qt_config->setValue(name + QStringLiteral("/default"),
+ setting.GetValue(global) == setting.GetDefault());
+ qt_config->setValue(name, value);
+ }
+}
+
+template <typename Type>
+void Config::WriteGlobalSetting(const Settings::Setting<Type>& setting) {
+ const QString name = QString::fromStdString(setting.GetLabel());
+ const Type& value = setting.GetValue(global);
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+ }
+ if (global || !setting.UsingGlobal()) {
+ qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
+ qt_config->setValue(name, value);
+ }
+}
+
void Config::ReadPlayerValue(std::size_t player_index) {
const QString player_prefix = [this, player_index] {
if (type == ConfigType::InputProfile) {
@@ -395,8 +480,7 @@ void Config::ReadPlayerValue(std::size_t player_index) {
}
void Config::ReadDebugValues() {
- Settings::values.debug_pad_enabled =
- ReadSetting(QStringLiteral("debug_pad_enabled"), false).toBool();
+ ReadBasicSetting(Settings::values.debug_pad_enabled);
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
@@ -432,8 +516,7 @@ void Config::ReadDebugValues() {
}
void Config::ReadKeyboardValues() {
- Settings::values.keyboard_enabled =
- ReadSetting(QStringLiteral("keyboard_enabled"), false).toBool();
+ ReadBasicSetting(Settings::values.keyboard_enabled);
std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
@@ -446,7 +529,7 @@ void Config::ReadKeyboardValues() {
}
void Config::ReadMouseValues() {
- Settings::values.mouse_enabled = ReadSetting(QStringLiteral("mouse_enabled"), false).toBool();
+ ReadBasicSetting(Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const std::string default_param =
@@ -481,18 +564,11 @@ void Config::ReadAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
if (global) {
- Settings::values.sink_id =
- ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
- .toString()
- .toStdString();
- Settings::values.audio_device_id =
- ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
- .toString()
- .toStdString();
+ ReadBasicSetting(Settings::values.audio_device_id);
+ ReadBasicSetting(Settings::values.sink_id);
}
- ReadSettingGlobal(Settings::values.enable_audio_stretching,
- QStringLiteral("enable_audio_stretching"), true);
- ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"), 1);
+ ReadGlobalSetting(Settings::values.enable_audio_stretching);
+ ReadGlobalSetting(Settings::values.volume);
qt_config->endGroup();
}
@@ -509,13 +585,11 @@ void Config::ReadControlValues() {
ReadTouchscreenValues();
ReadMotionTouchValues();
- Settings::values.emulate_analog_keyboard =
- ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
+ ReadBasicSetting(Settings::values.emulate_analog_keyboard);
Settings::values.mouse_panning = false;
- Settings::values.mouse_panning_sensitivity =
- ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
+ ReadBasicSetting(Settings::values.mouse_panning_sensitivity);
- ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), true);
+ ReadGlobalSetting(Settings::values.use_docked_mode);
// Disable docked mode if handheld is selected
const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
@@ -523,11 +597,9 @@ void Config::ReadControlValues() {
Settings::values.use_docked_mode.SetValue(false);
}
- ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
- true);
- ReadSettingGlobal(Settings::values.enable_accurate_vibrations,
- QStringLiteral("enable_accurate_vibrations"), false);
- ReadSettingGlobal(Settings::values.motion_enabled, QStringLiteral("motion_enabled"), true);
+ ReadGlobalSetting(Settings::values.vibration_enabled);
+ ReadGlobalSetting(Settings::values.enable_accurate_vibrations);
+ ReadGlobalSetting(Settings::values.motion_enabled);
qt_config->endGroup();
}
@@ -565,33 +637,19 @@ void Config::ReadMotionTouchValues() {
}
qt_config->endArray();
- Settings::values.motion_device =
- ReadSetting(QStringLiteral("motion_device"),
- QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"))
- .toString()
- .toStdString();
- Settings::values.touch_device =
- ReadSetting(QStringLiteral("touch_device"),
- QStringLiteral("min_x:100,min_y:50,max_x:1800,max_y:850"))
- .toString()
- .toStdString();
- Settings::values.use_touch_from_button =
- ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool();
- Settings::values.touch_from_button_map_index =
- ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
- Settings::values.touch_from_button_map_index =
- std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
- Settings::values.udp_input_servers =
- ReadSetting(QStringLiteral("udp_input_servers"),
- QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV))
- .toString()
- .toStdString();
+ ReadBasicSetting(Settings::values.motion_device);
+ ReadBasicSetting(Settings::values.touch_device);
+ ReadBasicSetting(Settings::values.use_touch_from_button);
+ ReadBasicSetting(Settings::values.touch_from_button_map_index);
+ Settings::values.touch_from_button_map_index = std::clamp(
+ Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
+ ReadBasicSetting(Settings::values.udp_input_servers);
}
void Config::ReadCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), true);
+ ReadGlobalSetting(Settings::values.use_multi_core);
qt_config->endGroup();
}
@@ -599,7 +657,7 @@ void Config::ReadCoreValues() {
void Config::ReadDataStorageValues() {
qt_config->beginGroup(QStringLiteral("Data Storage"));
- Settings::values.use_virtual_sd = ReadSetting(QStringLiteral("use_virtual_sd"), true).toBool();
+ ReadBasicSetting(Settings::values.use_virtual_sd);
FS::SetYuzuPath(
FS::YuzuPath::NANDDir,
qt_config
@@ -628,12 +686,9 @@ void Config::ReadDataStorageValues() {
QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)))
.toString()
.toStdString());
- Settings::values.gamecard_inserted =
- ReadSetting(QStringLiteral("gamecard_inserted"), false).toBool();
- Settings::values.gamecard_current_game =
- ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
- Settings::values.gamecard_path =
- ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString();
+ ReadBasicSetting(Settings::values.gamecard_inserted);
+ ReadBasicSetting(Settings::values.gamecard_current_game);
+ ReadBasicSetting(Settings::values.gamecard_path);
qt_config->endGroup();
}
@@ -644,34 +699,24 @@ void Config::ReadDebuggingValues() {
// Intentionally not using the QT default setting as this is intended to be changed in the ini
Settings::values.record_frame_times =
qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
- Settings::values.program_args =
- ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString();
- Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool();
- Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool();
- Settings::values.enable_fs_access_log =
- ReadSetting(QStringLiteral("enable_fs_access_log"), false).toBool();
- Settings::values.reporting_services =
- ReadSetting(QStringLiteral("reporting_services"), false).toBool();
- Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool();
- Settings::values.disable_macro_jit =
- ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
- Settings::values.extended_logging =
- ReadSetting(QStringLiteral("extended_logging"), false).toBool();
- Settings::values.use_debug_asserts =
- ReadSetting(QStringLiteral("use_debug_asserts"), false).toBool();
- Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
+ ReadBasicSetting(Settings::values.program_args);
+ ReadBasicSetting(Settings::values.dump_exefs);
+ ReadBasicSetting(Settings::values.dump_nso);
+ ReadBasicSetting(Settings::values.enable_fs_access_log);
+ ReadBasicSetting(Settings::values.reporting_services);
+ ReadBasicSetting(Settings::values.quest_flag);
+ ReadBasicSetting(Settings::values.disable_macro_jit);
+ ReadBasicSetting(Settings::values.extended_logging);
+ ReadBasicSetting(Settings::values.use_debug_asserts);
+ ReadBasicSetting(Settings::values.use_auto_stub);
qt_config->endGroup();
}
void Config::ReadServiceValues() {
qt_config->beginGroup(QStringLiteral("Services"));
- Settings::values.bcat_backend =
- ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("none"))
- .toString()
- .toStdString();
- Settings::values.bcat_boxcat_local =
- ReadSetting(QStringLiteral("bcat_boxcat_local"), false).toBool();
+ ReadBasicSetting(Settings::values.bcat_backend);
+ ReadBasicSetting(Settings::values.bcat_boxcat_local);
qt_config->endGroup();
}
@@ -697,11 +742,8 @@ void Config::ReadDisabledAddOnValues() {
void Config::ReadMiscellaneousValues() {
qt_config->beginGroup(QStringLiteral("Miscellaneous"));
- Settings::values.log_filter =
- ReadSetting(QStringLiteral("log_filter"), QStringLiteral("*:Info"))
- .toString()
- .toStdString();
- Settings::values.use_dev_keys = ReadSetting(QStringLiteral("use_dev_keys"), false).toBool();
+ ReadBasicSetting(Settings::values.log_filter);
+ ReadBasicSetting(Settings::values.use_dev_keys);
qt_config->endGroup();
}
@@ -751,38 +793,31 @@ void Config::ReadPathValues() {
void Config::ReadCpuValues() {
qt_config->beginGroup(QStringLiteral("Cpu"));
- ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0);
+ ReadBasicSetting(Settings::values.cpu_accuracy_first_time);
+ if (Settings::values.cpu_accuracy_first_time) {
+ Settings::values.cpu_accuracy.SetValue(Settings::values.cpu_accuracy.GetDefault());
+ Settings::values.cpu_accuracy_first_time.SetValue(false);
+ } else {
+ ReadGlobalSetting(Settings::values.cpu_accuracy);
+ }
- ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma,
- QStringLiteral("cpuopt_unsafe_unfuse_fma"), true);
- ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error,
- QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true);
- ReadSettingGlobal(Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
- QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"), true);
- ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
- QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
- ReadSettingGlobal(Settings::values.cpuopt_unsafe_fastmem_check,
- QStringLiteral("cpuopt_unsafe_fastmem_check"), true);
+ ReadGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
+ ReadGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
+ ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
+ ReadGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
+ ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
if (global) {
- Settings::values.cpuopt_page_tables =
- ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
- Settings::values.cpuopt_block_linking =
- ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool();
- Settings::values.cpuopt_return_stack_buffer =
- ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool();
- Settings::values.cpuopt_fast_dispatcher =
- ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool();
- Settings::values.cpuopt_context_elimination =
- ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool();
- Settings::values.cpuopt_const_prop =
- ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool();
- Settings::values.cpuopt_misc_ir =
- ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
- Settings::values.cpuopt_reduce_misalign_checks =
- ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
- Settings::values.cpuopt_fastmem =
- ReadSetting(QStringLiteral("cpuopt_fastmem"), true).toBool();
+ ReadBasicSetting(Settings::values.cpu_debug_mode);
+ ReadBasicSetting(Settings::values.cpuopt_page_tables);
+ ReadBasicSetting(Settings::values.cpuopt_block_linking);
+ ReadBasicSetting(Settings::values.cpuopt_return_stack_buffer);
+ ReadBasicSetting(Settings::values.cpuopt_fast_dispatcher);
+ ReadBasicSetting(Settings::values.cpuopt_context_elimination);
+ ReadBasicSetting(Settings::values.cpuopt_const_prop);
+ ReadBasicSetting(Settings::values.cpuopt_misc_ir);
+ ReadBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
+ ReadBasicSetting(Settings::values.cpuopt_fastmem);
}
qt_config->endGroup();
@@ -791,41 +826,30 @@ void Config::ReadCpuValues() {
void Config::ReadRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
- ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
- ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
- ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
-#ifdef _WIN32
- ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0);
-#else
- // *nix platforms may have issues with the borderless windowed fullscreen mode.
- // Default to exclusive fullscreen on these platforms for now.
- ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1);
-#endif
- ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
- ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
- ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
- ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"), 100);
- ReadSettingGlobal(Settings::values.use_disk_shader_cache,
- QStringLiteral("use_disk_shader_cache"), true);
- ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 1);
- ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
- QStringLiteral("use_asynchronous_gpu_emulation"), true);
- ReadSettingGlobal(Settings::values.use_nvdec_emulation, QStringLiteral("use_nvdec_emulation"),
- true);
- ReadSettingGlobal(Settings::values.accelerate_astc, QStringLiteral("accelerate_astc"), true);
- ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
- ReadSettingGlobal(Settings::values.disable_fps_limit, QStringLiteral("disable_fps_limit"),
- false);
- ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
- false);
- ReadSettingGlobal(Settings::values.use_asynchronous_shaders,
- QStringLiteral("use_asynchronous_shaders"), false);
- ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
- true);
- ReadSettingGlobal(Settings::values.use_caches_gc, QStringLiteral("use_caches_gc"), false);
- ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
- ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
- ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
+ ReadGlobalSetting(Settings::values.renderer_backend);
+ ReadGlobalSetting(Settings::values.vulkan_device);
+ ReadGlobalSetting(Settings::values.fullscreen_mode);
+ ReadGlobalSetting(Settings::values.aspect_ratio);
+ ReadGlobalSetting(Settings::values.max_anisotropy);
+ ReadGlobalSetting(Settings::values.use_frame_limit);
+ ReadGlobalSetting(Settings::values.frame_limit);
+ ReadGlobalSetting(Settings::values.use_disk_shader_cache);
+ ReadGlobalSetting(Settings::values.gpu_accuracy);
+ ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
+ ReadGlobalSetting(Settings::values.use_nvdec_emulation);
+ ReadGlobalSetting(Settings::values.accelerate_astc);
+ ReadGlobalSetting(Settings::values.use_vsync);
+ ReadGlobalSetting(Settings::values.use_assembly_shaders);
+ ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
+ ReadGlobalSetting(Settings::values.use_fast_gpu_time);
+ ReadGlobalSetting(Settings::values.use_caches_gc);
+ ReadGlobalSetting(Settings::values.bg_red);
+ ReadGlobalSetting(Settings::values.bg_green);
+ ReadGlobalSetting(Settings::values.bg_blue);
+
+ if (global) {
+ ReadBasicSetting(Settings::values.renderer_debug);
+ }
qt_config->endGroup();
}
@@ -870,15 +894,15 @@ void Config::ReadShortcutValues() {
void Config::ReadSystemValues() {
qt_config->beginGroup(QStringLiteral("System"));
- ReadSettingGlobal(Settings::values.current_user, QStringLiteral("current_user"), 0);
- Settings::values.current_user =
- std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1);
+ ReadBasicSetting(Settings::values.current_user);
+ Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
+ Service::Account::MAX_USERS - 1);
- ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"), 1);
+ ReadGlobalSetting(Settings::values.language_index);
- ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"), 1);
+ ReadGlobalSetting(Settings::values.region_index);
- ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"), 0);
+ ReadGlobalSetting(Settings::values.time_zone_index);
bool rng_seed_enabled;
ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
@@ -904,7 +928,7 @@ void Config::ReadSystemValues() {
}
}
- ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1);
+ ReadGlobalSetting(Settings::values.sound_index);
qt_config->endGroup();
}
@@ -915,10 +939,8 @@ void Config::ReadUIValues() {
UISettings::values.theme =
ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second))
.toString();
- UISettings::values.enable_discord_presence =
- ReadSetting(QStringLiteral("enable_discord_presence"), true).toBool();
- UISettings::values.select_user_on_boot =
- ReadSetting(QStringLiteral("select_user_on_boot"), false).toBool();
+ ReadBasicSetting(UISettings::values.enable_discord_presence);
+ ReadBasicSetting(UISettings::values.select_user_on_boot);
ReadUIGamelistValues();
ReadUILayoutValues();
@@ -926,24 +948,17 @@ void Config::ReadUIValues() {
ReadScreenshotValues();
ReadShortcutValues();
- UISettings::values.single_window_mode =
- ReadSetting(QStringLiteral("singleWindowMode"), true).toBool();
- UISettings::values.fullscreen = ReadSetting(QStringLiteral("fullscreen"), false).toBool();
- UISettings::values.display_titlebar =
- ReadSetting(QStringLiteral("displayTitleBars"), true).toBool();
- UISettings::values.show_filter_bar =
- ReadSetting(QStringLiteral("showFilterBar"), true).toBool();
- UISettings::values.show_status_bar =
- ReadSetting(QStringLiteral("showStatusBar"), true).toBool();
- UISettings::values.confirm_before_closing =
- ReadSetting(QStringLiteral("confirmClose"), true).toBool();
- UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool();
- UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt();
- UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool();
- UISettings::values.pause_when_in_background =
- ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool();
- UISettings::values.hide_mouse =
- ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool();
+ ReadBasicSetting(UISettings::values.single_window_mode);
+ ReadBasicSetting(UISettings::values.fullscreen);
+ ReadBasicSetting(UISettings::values.display_titlebar);
+ ReadBasicSetting(UISettings::values.show_filter_bar);
+ ReadBasicSetting(UISettings::values.show_status_bar);
+ ReadBasicSetting(UISettings::values.confirm_before_closing);
+ ReadBasicSetting(UISettings::values.first_start);
+ ReadBasicSetting(UISettings::values.callout_flags);
+ ReadBasicSetting(UISettings::values.show_console);
+ ReadBasicSetting(UISettings::values.pause_when_in_background);
+ ReadBasicSetting(UISettings::values.hide_mouse);
qt_config->endGroup();
}
@@ -951,12 +966,11 @@ void Config::ReadUIValues() {
void Config::ReadUIGamelistValues() {
qt_config->beginGroup(QStringLiteral("UIGameList"));
- UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool();
- UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt();
- UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt();
- UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt();
- UISettings::values.cache_game_list =
- ReadSetting(QStringLiteral("cache_game_list"), true).toBool();
+ ReadBasicSetting(UISettings::values.show_add_ons);
+ ReadBasicSetting(UISettings::values.icon_size);
+ ReadBasicSetting(UISettings::values.row_1_text_id);
+ ReadBasicSetting(UISettings::values.row_2_text_id);
+ ReadBasicSetting(UISettings::values.cache_game_list);
const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites"));
for (int i = 0; i < favorites_size; i++) {
qt_config->setArrayIndex(i);
@@ -979,8 +993,7 @@ void Config::ReadUILayoutValues() {
ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray();
UISettings::values.microprofile_geometry =
ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray();
- UISettings::values.microprofile_visible =
- ReadSetting(QStringLiteral("microProfileDialogVisible"), false).toBool();
+ ReadBasicSetting(UISettings::values.microprofile_visible);
qt_config->endGroup();
}
@@ -988,16 +1001,10 @@ void Config::ReadUILayoutValues() {
void Config::ReadWebServiceValues() {
qt_config->beginGroup(QStringLiteral("WebService"));
- Settings::values.enable_telemetry =
- ReadSetting(QStringLiteral("enable_telemetry"), true).toBool();
- Settings::values.web_api_url =
- ReadSetting(QStringLiteral("web_api_url"), QStringLiteral("https://api.yuzu-emu.org"))
- .toString()
- .toStdString();
- Settings::values.yuzu_username =
- ReadSetting(QStringLiteral("yuzu_username")).toString().toStdString();
- Settings::values.yuzu_token =
- ReadSetting(QStringLiteral("yuzu_token")).toString().toStdString();
+ ReadBasicSetting(Settings::values.enable_telemetry);
+ ReadBasicSetting(Settings::values.web_api_url);
+ ReadBasicSetting(Settings::values.yuzu_username);
+ ReadBasicSetting(Settings::values.yuzu_token);
qt_config->endGroup();
}
@@ -1083,7 +1090,7 @@ void Config::SavePlayerValue(std::size_t player_index) {
}
void Config::SaveDebugValues() {
- WriteSetting(QStringLiteral("debug_pad_enabled"), Settings::values.debug_pad_enabled, false);
+ WriteBasicSetting(Settings::values.debug_pad_enabled);
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
WriteSetting(QStringLiteral("debug_pad_") +
@@ -1103,7 +1110,7 @@ void Config::SaveDebugValues() {
}
void Config::SaveMouseValues() {
- WriteSetting(QStringLiteral("mouse_enabled"), Settings::values.mouse_enabled, false);
+ WriteBasicSetting(Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const std::string default_param =
@@ -1126,19 +1133,11 @@ void Config::SaveTouchscreenValues() {
}
void Config::SaveMotionTouchValues() {
- WriteSetting(QStringLiteral("motion_device"),
- QString::fromStdString(Settings::values.motion_device),
- QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
- WriteSetting(QStringLiteral("touch_device"),
- QString::fromStdString(Settings::values.touch_device),
- QStringLiteral("engine:emu_window"));
- WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button,
- false);
- WriteSetting(QStringLiteral("touch_from_button_map"),
- Settings::values.touch_from_button_map_index, 0);
- WriteSetting(QStringLiteral("udp_input_servers"),
- QString::fromStdString(Settings::values.udp_input_servers),
- QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV));
+ WriteBasicSetting(Settings::values.motion_device);
+ WriteBasicSetting(Settings::values.touch_device);
+ WriteBasicSetting(Settings::values.use_touch_from_button);
+ WriteBasicSetting(Settings::values.touch_from_button_map_index);
+ WriteBasicSetting(Settings::values.udp_input_servers);
qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
@@ -1181,15 +1180,11 @@ void Config::SaveAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
if (global) {
- WriteSetting(QStringLiteral("output_engine"),
- QString::fromStdString(Settings::values.sink_id), QStringLiteral("auto"));
- WriteSetting(QStringLiteral("output_device"),
- QString::fromStdString(Settings::values.audio_device_id),
- QStringLiteral("auto"));
+ WriteBasicSetting(Settings::values.sink_id);
+ WriteBasicSetting(Settings::values.audio_device_id);
}
- WriteSettingGlobal(QStringLiteral("enable_audio_stretching"),
- Settings::values.enable_audio_stretching, true);
- WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume, 1.0f);
+ WriteGlobalSetting(Settings::values.enable_audio_stretching);
+ WriteGlobalSetting(Settings::values.volume);
qt_config->endGroup();
}
@@ -1205,30 +1200,21 @@ void Config::SaveControlValues() {
SaveTouchscreenValues();
SaveMotionTouchValues();
- WriteSettingGlobal(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, true);
- WriteSettingGlobal(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled,
- true);
- WriteSettingGlobal(QStringLiteral("enable_accurate_vibrations"),
- Settings::values.enable_accurate_vibrations, false);
- WriteSettingGlobal(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
- WriteSetting(QStringLiteral("motion_device"),
- QString::fromStdString(Settings::values.motion_device),
- QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
- WriteSetting(QStringLiteral("touch_device"),
- QString::fromStdString(Settings::values.touch_device),
- QStringLiteral("engine:emu_window"));
- WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
- WriteSetting(QStringLiteral("emulate_analog_keyboard"),
- Settings::values.emulate_analog_keyboard, false);
- WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
- Settings::values.mouse_panning_sensitivity, 1.0f);
+ WriteGlobalSetting(Settings::values.use_docked_mode);
+ WriteGlobalSetting(Settings::values.vibration_enabled);
+ WriteGlobalSetting(Settings::values.enable_accurate_vibrations);
+ WriteGlobalSetting(Settings::values.motion_enabled);
+ WriteBasicSetting(Settings::values.keyboard_enabled);
+ WriteBasicSetting(Settings::values.emulate_analog_keyboard);
+ WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
+
qt_config->endGroup();
}
void Config::SaveCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, true);
+ WriteGlobalSetting(Settings::values.use_multi_core);
qt_config->endGroup();
}
@@ -1236,7 +1222,7 @@ void Config::SaveCoreValues() {
void Config::SaveDataStorageValues() {
qt_config->beginGroup(QStringLiteral("Data Storage"));
- WriteSetting(QStringLiteral("use_virtual_sd"), Settings::values.use_virtual_sd, true);
+ WriteBasicSetting(Settings::values.use_virtual_sd);
WriteSetting(QStringLiteral("nand_directory"),
QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)),
QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -1249,11 +1235,9 @@ void Config::SaveDataStorageValues() {
WriteSetting(QStringLiteral("dump_directory"),
QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)),
QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
- WriteSetting(QStringLiteral("gamecard_inserted"), Settings::values.gamecard_inserted, false);
- WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game,
- false);
- WriteSetting(QStringLiteral("gamecard_path"),
- QString::fromStdString(Settings::values.gamecard_path), QString{});
+ WriteBasicSetting(Settings::values.gamecard_inserted);
+ WriteBasicSetting(Settings::values.gamecard_current_game);
+ WriteBasicSetting(Settings::values.gamecard_path);
qt_config->endGroup();
}
@@ -1263,24 +1247,23 @@ void Config::SaveDebuggingValues() {
// Intentionally not using the QT default setting as this is intended to be changed in the ini
qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
- WriteSetting(QStringLiteral("program_args"),
- QString::fromStdString(Settings::values.program_args), QString{});
- WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
- WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
- WriteSetting(QStringLiteral("enable_fs_access_log"), Settings::values.enable_fs_access_log,
- false);
- WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
- WriteSetting(QStringLiteral("use_debug_asserts"), Settings::values.use_debug_asserts, false);
- WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
+ WriteBasicSetting(Settings::values.program_args);
+ WriteBasicSetting(Settings::values.dump_exefs);
+ WriteBasicSetting(Settings::values.dump_nso);
+ WriteBasicSetting(Settings::values.enable_fs_access_log);
+ WriteBasicSetting(Settings::values.quest_flag);
+ WriteBasicSetting(Settings::values.use_debug_asserts);
+ WriteBasicSetting(Settings::values.disable_macro_jit);
qt_config->endGroup();
}
void Config::SaveServiceValues() {
qt_config->beginGroup(QStringLiteral("Services"));
- WriteSetting(QStringLiteral("bcat_backend"),
- QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("none"));
- WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false);
+
+ WriteBasicSetting(Settings::values.bcat_backend);
+ WriteBasicSetting(Settings::values.bcat_boxcat_local);
+
qt_config->endGroup();
}
@@ -1306,9 +1289,8 @@ void Config::SaveDisabledAddOnValues() {
void Config::SaveMiscellaneousValues() {
qt_config->beginGroup(QStringLiteral("Miscellaneous"));
- WriteSetting(QStringLiteral("log_filter"), QString::fromStdString(Settings::values.log_filter),
- QStringLiteral("*:Info"));
- WriteSetting(QStringLiteral("use_dev_keys"), Settings::values.use_dev_keys, false);
+ WriteBasicSetting(Settings::values.log_filter);
+ WriteBasicSetting(Settings::values.use_dev_keys);
qt_config->endGroup();
}
@@ -1336,38 +1318,29 @@ void Config::SavePathValues() {
void Config::SaveCpuValues() {
qt_config->beginGroup(QStringLiteral("Cpu"));
- WriteSettingGlobal(QStringLiteral("cpu_accuracy"),
- static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
- Settings::values.cpu_accuracy.UsingGlobal(),
- static_cast<u32>(Settings::CPUAccuracy::Accurate));
-
- WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
- Settings::values.cpuopt_unsafe_unfuse_fma, true);
- WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
- Settings::values.cpuopt_unsafe_reduce_fp_error, true);
- WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"),
- Settings::values.cpuopt_unsafe_ignore_standard_fpcr, true);
- WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
- Settings::values.cpuopt_unsafe_inaccurate_nan, true);
- WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_fastmem_check"),
- Settings::values.cpuopt_unsafe_fastmem_check, true);
+ WriteBasicSetting(Settings::values.cpu_accuracy_first_time);
+ WriteSetting(QStringLiteral("cpu_accuracy"),
+ static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
+ static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()),
+ Settings::values.cpu_accuracy.UsingGlobal());
+
+ WriteGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
+ WriteGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
+ WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
+ WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
+ WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
if (global) {
- WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
- true);
- WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
- true);
- WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"),
- Settings::values.cpuopt_return_stack_buffer, true);
- WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"),
- Settings::values.cpuopt_fast_dispatcher, true);
- WriteSetting(QStringLiteral("cpuopt_context_elimination"),
- Settings::values.cpuopt_context_elimination, true);
- WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true);
- WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
- WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
- Settings::values.cpuopt_reduce_misalign_checks, true);
- WriteSetting(QStringLiteral("cpuopt_fastmem"), Settings::values.cpuopt_fastmem, true);
+ WriteBasicSetting(Settings::values.cpu_debug_mode);
+ WriteBasicSetting(Settings::values.cpuopt_page_tables);
+ WriteBasicSetting(Settings::values.cpuopt_block_linking);
+ WriteBasicSetting(Settings::values.cpuopt_return_stack_buffer);
+ WriteBasicSetting(Settings::values.cpuopt_fast_dispatcher);
+ WriteBasicSetting(Settings::values.cpuopt_context_elimination);
+ WriteBasicSetting(Settings::values.cpuopt_const_prop);
+ WriteBasicSetting(Settings::values.cpuopt_misc_ir);
+ WriteBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
+ WriteBasicSetting(Settings::values.cpuopt_fastmem);
}
qt_config->endGroup();
@@ -1376,46 +1349,36 @@ void Config::SaveCpuValues() {
void Config::SaveRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
- WriteSettingGlobal(QStringLiteral("backend"),
- static_cast<int>(Settings::values.renderer_backend.GetValue(global)),
- Settings::values.renderer_backend.UsingGlobal(), 0);
- WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
- WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
-#ifdef _WIN32
- WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0);
-#else
- // *nix platforms may have issues with the borderless windowed fullscreen mode.
- // Default to exclusive fullscreen on these platforms for now.
- WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1);
-#endif
- WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
- WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
- WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
- WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
- WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"),
- Settings::values.use_disk_shader_cache, true);
- WriteSettingGlobal(QStringLiteral("gpu_accuracy"),
- static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)),
- Settings::values.gpu_accuracy.UsingGlobal(), 1);
- WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
- Settings::values.use_asynchronous_gpu_emulation, true);
- WriteSettingGlobal(QStringLiteral("use_nvdec_emulation"), Settings::values.use_nvdec_emulation,
- true);
- WriteSettingGlobal(QStringLiteral("accelerate_astc"), Settings::values.accelerate_astc, true);
- WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
- WriteSettingGlobal(QStringLiteral("disable_fps_limit"), Settings::values.disable_fps_limit,
- false);
- WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
- Settings::values.use_assembly_shaders, false);
- WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"),
- Settings::values.use_asynchronous_shaders, false);
- WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
- true);
- WriteSettingGlobal(QStringLiteral("use_caches_gc"), Settings::values.use_caches_gc, false);
- // Cast to double because Qt's written float values are not human-readable
- WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
- WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
- WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue, 0.0);
+ WriteSetting(QString::fromStdString(Settings::values.renderer_backend.GetLabel()),
+ static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
+ static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
+ Settings::values.renderer_backend.UsingGlobal());
+ WriteGlobalSetting(Settings::values.vulkan_device);
+ WriteGlobalSetting(Settings::values.fullscreen_mode);
+ WriteGlobalSetting(Settings::values.aspect_ratio);
+ WriteGlobalSetting(Settings::values.max_anisotropy);
+ WriteGlobalSetting(Settings::values.use_frame_limit);
+ WriteGlobalSetting(Settings::values.frame_limit);
+ WriteGlobalSetting(Settings::values.use_disk_shader_cache);
+ WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
+ static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
+ static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()),
+ Settings::values.gpu_accuracy.UsingGlobal());
+ WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
+ WriteGlobalSetting(Settings::values.use_nvdec_emulation);
+ WriteGlobalSetting(Settings::values.accelerate_astc);
+ WriteGlobalSetting(Settings::values.use_vsync);
+ WriteGlobalSetting(Settings::values.use_assembly_shaders);
+ WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
+ WriteGlobalSetting(Settings::values.use_fast_gpu_time);
+ WriteGlobalSetting(Settings::values.use_caches_gc);
+ WriteGlobalSetting(Settings::values.bg_red);
+ WriteGlobalSetting(Settings::values.bg_green);
+ WriteGlobalSetting(Settings::values.bg_blue);
+
+ if (global) {
+ WriteBasicSetting(Settings::values.renderer_debug);
+ }
qt_config->endGroup();
}
@@ -1423,8 +1386,7 @@ void Config::SaveRendererValues() {
void Config::SaveScreenshotValues() {
qt_config->beginGroup(QStringLiteral("Screenshots"));
- WriteSetting(QStringLiteral("enable_screenshot_save_as"),
- UISettings::values.enable_screenshot_save_as);
+ WriteBasicSetting(UISettings::values.enable_screenshot_save_as);
WriteSetting(QStringLiteral("screenshot_path"),
QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)));
@@ -1454,17 +1416,16 @@ void Config::SaveShortcutValues() {
void Config::SaveSystemValues() {
qt_config->beginGroup(QStringLiteral("System"));
- WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
- WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index, 1);
- WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index, 1);
- WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
+ WriteBasicSetting(Settings::values.current_user);
+ WriteGlobalSetting(Settings::values.language_index);
+ WriteGlobalSetting(Settings::values.region_index);
+ WriteGlobalSetting(Settings::values.time_zone_index);
- WriteSettingGlobal(QStringLiteral("rng_seed_enabled"),
- Settings::values.rng_seed.GetValue(global).has_value(),
- Settings::values.rng_seed.UsingGlobal(), false);
- WriteSettingGlobal(QStringLiteral("rng_seed"),
- Settings::values.rng_seed.GetValue(global).value_or(0),
- Settings::values.rng_seed.UsingGlobal(), 0);
+ WriteSetting(QStringLiteral("rng_seed_enabled"),
+ Settings::values.rng_seed.GetValue(global).has_value(), false,
+ Settings::values.rng_seed.UsingGlobal());
+ WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0),
+ 0, Settings::values.rng_seed.UsingGlobal());
if (global) {
WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
@@ -1475,7 +1436,7 @@ void Config::SaveSystemValues() {
0);
}
- WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
+ WriteGlobalSetting(Settings::values.sound_index);
qt_config->endGroup();
}
@@ -1485,10 +1446,8 @@ void Config::SaveUIValues() {
WriteSetting(QStringLiteral("theme"), UISettings::values.theme,
QString::fromUtf8(UISettings::themes[0].second));
- WriteSetting(QStringLiteral("enable_discord_presence"),
- UISettings::values.enable_discord_presence, true);
- WriteSetting(QStringLiteral("select_user_on_boot"), UISettings::values.select_user_on_boot,
- false);
+ WriteBasicSetting(UISettings::values.enable_discord_presence);
+ WriteBasicSetting(UISettings::values.select_user_on_boot);
SaveUIGamelistValues();
SaveUILayoutValues();
@@ -1496,18 +1455,17 @@ void Config::SaveUIValues() {
SaveScreenshotValues();
SaveShortcutValues();
- WriteSetting(QStringLiteral("singleWindowMode"), UISettings::values.single_window_mode, true);
- WriteSetting(QStringLiteral("fullscreen"), UISettings::values.fullscreen, false);
- WriteSetting(QStringLiteral("displayTitleBars"), UISettings::values.display_titlebar, true);
- WriteSetting(QStringLiteral("showFilterBar"), UISettings::values.show_filter_bar, true);
- WriteSetting(QStringLiteral("showStatusBar"), UISettings::values.show_status_bar, true);
- WriteSetting(QStringLiteral("confirmClose"), UISettings::values.confirm_before_closing, true);
- WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true);
- WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0);
- WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false);
- WriteSetting(QStringLiteral("pauseWhenInBackground"),
- UISettings::values.pause_when_in_background, false);
- WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false);
+ WriteBasicSetting(UISettings::values.single_window_mode);
+ WriteBasicSetting(UISettings::values.fullscreen);
+ WriteBasicSetting(UISettings::values.display_titlebar);
+ WriteBasicSetting(UISettings::values.show_filter_bar);
+ WriteBasicSetting(UISettings::values.show_status_bar);
+ WriteBasicSetting(UISettings::values.confirm_before_closing);
+ WriteBasicSetting(UISettings::values.first_start);
+ WriteBasicSetting(UISettings::values.callout_flags);
+ WriteBasicSetting(UISettings::values.show_console);
+ WriteBasicSetting(UISettings::values.pause_when_in_background);
+ WriteBasicSetting(UISettings::values.hide_mouse);
qt_config->endGroup();
}
@@ -1515,11 +1473,11 @@ void Config::SaveUIValues() {
void Config::SaveUIGamelistValues() {
qt_config->beginGroup(QStringLiteral("UIGameList"));
- WriteSetting(QStringLiteral("show_add_ons"), UISettings::values.show_add_ons, true);
- WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64);
- WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3);
- WriteSetting(QStringLiteral("row_2_text_id"), UISettings::values.row_2_text_id, 2);
- WriteSetting(QStringLiteral("cache_game_list"), UISettings::values.cache_game_list, true);
+ WriteBasicSetting(UISettings::values.show_add_ons);
+ WriteBasicSetting(UISettings::values.icon_size);
+ WriteBasicSetting(UISettings::values.row_1_text_id);
+ WriteBasicSetting(UISettings::values.row_2_text_id);
+ WriteBasicSetting(UISettings::values.cache_game_list);
qt_config->beginWriteArray(QStringLiteral("favorites"));
for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
qt_config->setArrayIndex(i);
@@ -1540,8 +1498,7 @@ void Config::SaveUILayoutValues() {
WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state);
WriteSetting(QStringLiteral("microProfileDialogGeometry"),
UISettings::values.microprofile_geometry);
- WriteSetting(QStringLiteral("microProfileDialogVisible"),
- UISettings::values.microprofile_visible, false);
+ WriteBasicSetting(UISettings::values.microprofile_visible);
qt_config->endGroup();
}
@@ -1549,13 +1506,10 @@ void Config::SaveUILayoutValues() {
void Config::SaveWebServiceValues() {
qt_config->beginGroup(QStringLiteral("WebService"));
- WriteSetting(QStringLiteral("enable_telemetry"), Settings::values.enable_telemetry, true);
- WriteSetting(QStringLiteral("web_api_url"),
- QString::fromStdString(Settings::values.web_api_url),
- QStringLiteral("https://api.yuzu-emu.org"));
- WriteSetting(QStringLiteral("yuzu_username"),
- QString::fromStdString(Settings::values.yuzu_username));
- WriteSetting(QStringLiteral("yuzu_token"), QString::fromStdString(Settings::values.yuzu_token));
+ WriteBasicSetting(Settings::values.enable_telemetry);
+ WriteBasicSetting(Settings::values.web_api_url);
+ WriteBasicSetting(Settings::values.yuzu_username);
+ WriteBasicSetting(Settings::values.yuzu_token);
qt_config->endGroup();
}
@@ -1575,21 +1529,14 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
}
template <typename Type>
-void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) {
- const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
- setting.SetGlobal(use_global);
- if (global || !use_global) {
- setting.SetValue(ReadSetting(name).value<Type>());
- }
-}
-
-template <typename Type>
-void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
- const QVariant& default_value) {
+void Config::ReadGlobalSetting(Settings::Setting<Type>& setting) {
+ QString name = QString::fromStdString(setting.GetLabel());
const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
setting.SetGlobal(use_global);
if (global || !use_global) {
- setting.SetValue(ReadSetting(name, default_value).value<Type>());
+ setting.SetValue(static_cast<QVariant>(
+ ReadSetting(name, QVariant::fromValue<Type>(setting.GetDefault())))
+ .value<Type>());
}
}
@@ -1612,31 +1559,8 @@ void Config::WriteSetting(const QString& name, const QVariant& value,
qt_config->setValue(name, value);
}
-template <typename Type>
-void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting) {
- if (!global) {
- qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
- }
- if (global || !setting.UsingGlobal()) {
- qt_config->setValue(name, setting.GetValue(global));
- }
-}
-
-template <typename Type>
-void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
- const QVariant& default_value) {
- if (!global) {
- qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
- }
- if (global || !setting.UsingGlobal()) {
- qt_config->setValue(name + QStringLiteral("/default"),
- setting.GetValue(global) == default_value.value<Type>());
- qt_config->setValue(name, setting.GetValue(global));
- }
-}
-
-void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
- const QVariant& default_value) {
+void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
+ bool use_global) {
if (!global) {
qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 3c1de0ac9..96f9b6de1 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -102,28 +102,75 @@ private:
void SaveUILayoutValues();
void SaveWebServiceValues();
+ /**
+ * Reads a setting from the qt_config.
+ *
+ * @param name The setting's identifier
+ * @param default_value The value to use when the setting is not already present in the config
+ */
QVariant ReadSetting(const QString& name) const;
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
- // Templated ReadSettingGlobal functions will also look for the use_global setting and set
- // both the value and the global state properly
- template <typename Type>
- void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
- template <typename Type>
- void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
- const QVariant& default_value);
+
+ /**
+ * Only reads a setting from the qt_config if the current config is a global config, or if the
+ * current config is a custom config and the setting is overriding the global setting. Otherwise
+ * it does nothing.
+ *
+ * @param setting The variable to be modified
+ * @param name The setting's identifier
+ * @param default_value The value to use when the setting is not already present in the config
+ */
template <typename Type>
void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
- // Templated WriteSettingGlobal functions will also write the global state if needed and will
- // skip writing the actual setting if it defers to the global value
+
+ /**
+ * Writes a setting to the qt_config.
+ *
+ * @param name The setting's idetentifier
+ * @param value Value of the setting
+ * @param default_value Default of the setting if not present in qt_config
+ * @param use_global Specifies if the custom or global config should be in use, for custom
+ * configs
+ */
void WriteSetting(const QString& name, const QVariant& value);
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
+ void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
+ bool use_global);
+
+ /**
+ * Reads a value from the qt_config and applies it to the setting, using its label and default
+ * value. If the config is a custom config, this will also read the global state of the setting
+ * and apply that information to it.
+ *
+ * @param The setting
+ */
template <typename Type>
- void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting);
+ void ReadGlobalSetting(Settings::Setting<Type>& setting);
+
+ /**
+ * Sets a value to the qt_config using the setting's label and default value. If the config is a
+ * custom config, it will apply the global state, and the custom value if needed.
+ *
+ * @param The setting
+ */
+ template <typename Type>
+ void WriteGlobalSetting(const Settings::Setting<Type>& setting);
+
+ /**
+ * Reads a value from the qt_config using the setting's label and default value and applies the
+ * value to the setting.
+ *
+ * @param The setting
+ */
+ template <typename Type>
+ void ReadBasicSetting(Settings::BasicSetting<Type>& setting);
+
+ /** Sets a value from the setting in the qt_config using the setting's label and default value.
+ *
+ * @param The setting
+ */
template <typename Type>
- void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
- const QVariant& default_value);
- void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
- const QVariant& default_value);
+ void WriteBasicSetting(const Settings::BasicSetting<Type>& setting);
ConfigType type;
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 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
- <number>0</number>
+ <number>11</number>
</property>
<widget class="ConfigureGeneral" name="generalTab">
<property name="accessibleName">
@@ -107,14 +107,6 @@
<string>CPU</string>
</attribute>
</widget>
- <widget class="ConfigureCpuDebug" name="cpuDebugTab">
- <property name="accessibleName">
- <string>Debug</string>
- </property>
- <attribute name="title">
- <string>Debug</string>
- </attribute>
- </widget>
<widget class="ConfigureGraphics" name="graphicsTab">
<property name="accessibleName">
<string>Graphics</string>
@@ -139,7 +131,7 @@
<string>Audio</string>
</attribute>
</widget>
- <widget class="ConfigureDebug" name="debugTab">
+ <widget class="ConfigureDebugTab" name="debugTab">
<property name="accessibleName">
<string>Debug</string>
</property>
@@ -208,24 +200,12 @@
<container>1</container>
</customwidget>
<customwidget>
- <class>ConfigureDebug</class>
- <extends>QWidget</extends>
- <header>configuration/configure_debug.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
<class>ConfigureCpu</class>
<extends>QWidget</extends>
<header>configuration/configure_cpu.h</header>
<container>1</container>
</customwidget>
<customwidget>
- <class>ConfigureCpuDebug</class>
- <extends>QWidget</extends>
- <header>configuration/configure_cpu_debug.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
<class>ConfigureGraphics</class>
<extends>QWidget</extends>
<header>configuration/configure_graphics.h</header>
@@ -267,6 +247,12 @@
<header>configuration/configure_service.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ConfigureDebugTab</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_debug_tab.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections>
@@ -275,12 +261,32 @@
<signal>accepted()</signal>
<receiver>ConfigureDialog</receiver>
<slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ConfigureDialog</receiver>
<slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
</connection>
</connections>
</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() {
[[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box);
int new_sink_index = 0;
- const QString sink_id = QString::fromStdString(Settings::values.sink_id);
+ const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
if (ui->output_sink_combo_box->itemText(index) == sink_id) {
new_sink_index = index;
@@ -83,7 +83,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
void ConfigureAudio::SetAudioDeviceFromDeviceID() {
int new_device_index = -1;
- const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
+ const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue());
for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
if (ui->audio_device_combo_box->itemText(index) == device_id) {
new_device_index = index;
@@ -106,9 +106,9 @@ void ConfigureAudio::ApplyConfiguration() {
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
- Settings::values.audio_device_id =
+ Settings::values.audio_device_id.SetValue(
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
- .toStdString();
+ .toStdString());
// Guard if during game and set to game-specific value
if (Settings::values.volume.UsingGlobal()) {
diff --git a/src/yuzu/configuration/configure_cpu.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
SetConfiguration();
- connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
- &ConfigureCpu::AccuracyUpdated);
connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureCpu::UpdateGroup);
}
@@ -58,20 +56,6 @@ void ConfigureCpu::SetConfiguration() {
UpdateGroup(ui->accuracy->currentIndex());
}
-void ConfigureCpu::AccuracyUpdated(int index) {
- if (Settings::IsConfiguringGlobal() &&
- static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
- const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
- tr("CPU Debug Mode is only intended for developer "
- "use. Are you sure you want to enable this?"),
- QMessageBox::Yes | QMessageBox::No);
- if (result == QMessageBox::No) {
- ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
- UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate));
- }
- }
-}
-
void ConfigureCpu::UpdateGroup(int index) {
if (!Settings::IsConfiguringGlobal()) {
index -= ConfigurationShared::USE_GLOBAL_OFFSET;
@@ -134,8 +118,6 @@ void ConfigureCpu::SetupPerGameUI() {
ConfigurationShared::SetColoredComboBox(
ui->accuracy, ui->widget_accuracy,
static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
- ui->accuracy->removeItem(static_cast<u32>(Settings::CPUAccuracy::DebugMode) +
- ConfigurationShared::USE_GLOBAL_OFFSET);
ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
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:
void changeEvent(QEvent* event) override;
void RetranslateUI();
- void AccuracyUpdated(int index);
void UpdateGroup(int index);
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 @@
<rect>
<x>0</x>
<y>0</y>
- <width>400</width>
- <height>321</height>
+ <width>448</width>
+ <height>433</height>
</rect>
</property>
<property name="windowTitle">
@@ -17,7 +17,7 @@
<item>
<layout class="QVBoxLayout">
<item>
- <widget class="QGroupBox">
+ <widget class="QGroupBox" name="groupBox">
<property name="title">
<string>General</string>
</property>
@@ -36,17 +36,17 @@
<widget class="QComboBox" name="accuracy">
<item>
<property name="text">
- <string>Accurate</string>
+ <string>Auto</string>
</property>
</item>
<item>
<property name="text">
- <string>Unsafe</string>
+ <string>Accurate</string>
</property>
</item>
<item>
<property name="text">
- <string>Enable Debug Mode</string>
+ <string>Unsafe</string>
</property>
</item>
</widget>
@@ -57,7 +57,7 @@
<item>
<widget class="QLabel" name="label_recommended_accuracy">
<property name="text">
- <string>We recommend setting accuracy to &quot;Accurate&quot;.</string>
+ <string>We recommend setting accuracy to &quot;Auto&quot;.</string>
</property>
<property name="wordWrap">
<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() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->cpuopt_page_tables->setEnabled(runtime_lock);
- ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables);
+ ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue());
ui->cpuopt_block_linking->setEnabled(runtime_lock);
- ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking);
+ ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking.GetValue());
ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
- ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer);
+ ui->cpuopt_return_stack_buffer->setChecked(
+ Settings::values.cpuopt_return_stack_buffer.GetValue());
ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
- ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher);
+ ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher.GetValue());
ui->cpuopt_context_elimination->setEnabled(runtime_lock);
- ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination);
+ ui->cpuopt_context_elimination->setChecked(
+ Settings::values.cpuopt_context_elimination.GetValue());
ui->cpuopt_const_prop->setEnabled(runtime_lock);
- ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop);
+ ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop.GetValue());
ui->cpuopt_misc_ir->setEnabled(runtime_lock);
- ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
+ ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir.GetValue());
ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
- ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
+ ui->cpuopt_reduce_misalign_checks->setChecked(
+ Settings::values.cpuopt_reduce_misalign_checks.GetValue());
ui->cpuopt_fastmem->setEnabled(runtime_lock);
- ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem);
+ ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue());
}
void ConfigureCpuDebug::ApplyConfiguration() {
diff --git a/src/yuzu/configuration/configure_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 @@
#include <memory>
#include <QWidget>
-#include "common/settings.h"
namespace Ui {
class 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 @@
<rect>
<x>0</x>
<y>0</y>
- <width>400</width>
- <height>321</height>
+ <width>592</width>
+ <height>503</height>
</rect>
</property>
<property name="windowTitle">
@@ -17,140 +17,132 @@
<item>
<layout class="QVBoxLayout">
<item>
- <widget class="QGroupBox">
+ <widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Toggle CPU Optimizations</string>
</property>
<layout class="QVBoxLayout">
<item>
- <widget class="QLabel">
- <property name="wordWrap">
- <bool>1</bool>
- </property>
+ <widget class="QLabel" name="label">
<property name="text">
- <string>
- &lt;div&gt;
- &lt;b&gt;For debugging only.&lt;/b&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 Accuracy is "Debug Mode".
- &lt;/div&gt;
- </string>
+ <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>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_page_tables">
- <property name="text">
- <string>Enable inline page tables</string>
- </property>
<property name="toolTip">
<string>
- &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
- &lt;div style="white-space: nowrap"&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
- &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;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &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;
</string>
</property>
+ <property name="text">
+ <string>Enable inline page tables</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_block_linking">
- <property name="text">
- <string>Enable block linking</string>
- </property>
<property name="toolTip">
<string>
&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;
</string>
</property>
+ <property name="text">
+ <string>Enable block linking</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_return_stack_buffer">
- <property name="text">
- <string>Enable return stack buffer</string>
- </property>
<property name="toolTip">
<string>
&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;
</string>
</property>
+ <property name="text">
+ <string>Enable return stack buffer</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_fast_dispatcher">
- <property name="text">
- <string>Enable fast dispatcher</string>
- </property>
<property name="toolTip">
<string>
&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;
</string>
</property>
+ <property name="text">
+ <string>Enable fast dispatcher</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_context_elimination">
- <property name="text">
- <string>Enable context elimination</string>
- </property>
<property name="toolTip">
<string>
&lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Enable context elimination</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_const_prop">
- <property name="text">
- <string>Enable constant propagation</string>
- </property>
<property name="toolTip">
<string>
&lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Enable constant propagation</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_misc_ir">
- <property name="text">
- <string>Enable miscellaneous optimizations</string>
- </property>
<property name="toolTip">
<string>
&lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Enable miscellaneous optimizations</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_reduce_misalign_checks">
- <property name="text">
- <string>Enable misalignment check reduction</string>
- </property>
<property name="toolTip">
<string>
- &lt;div style="white-space: nowrap"&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
- &lt;div style="white-space: nowrap"&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ &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;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Enable misalignment check reduction</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_fastmem">
- <property name="text">
- <string>Enable Host MMU Emulation</string>
- </property>
<property name="toolTip">
<string>
- &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
- &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;
- &lt;div style="white-space: nowrap"&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &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;
+ &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Enable Host MMU Emulation</string>
+ </property>
</widget>
</item>
</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() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->toggle_console->setEnabled(runtime_lock);
- ui->toggle_console->setChecked(UISettings::values.show_console);
- ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
- ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
+ ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
+ ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
+ ui->homebrew_args_edit->setText(
+ QString::fromStdString(Settings::values.program_args.GetValue()));
ui->fs_access_log->setEnabled(runtime_lock);
- ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log);
- ui->reporting_services->setChecked(Settings::values.reporting_services);
- ui->quest_flag->setChecked(Settings::values.quest_flag);
- ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts);
- ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
+ ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log.GetValue());
+ ui->reporting_services->setChecked(Settings::values.reporting_services.GetValue());
+ ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue());
+ ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue());
+ ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue());
ui->enable_graphics_debugging->setEnabled(runtime_lock);
- ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
+ ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
+ ui->enable_cpu_debugging->setEnabled(runtime_lock);
+ ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue());
ui->disable_macro_jit->setEnabled(runtime_lock);
- ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit);
- ui->extended_logging->setChecked(Settings::values.extended_logging);
+ ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue());
+ ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
}
void ConfigureDebug::ApplyConfiguration() {
@@ -57,11 +60,12 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
+ Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
Settings::values.extended_logging = ui->extended_logging->isChecked();
Debugger::ToggleConsole();
Common::Log::Filter filter;
- filter.ParseFilterString(Settings::values.log_filter);
+ filter.ParseFilterString(Settings::values.log_filter.GetValue());
Common::Log::SetGlobalFilter(filter);
}
diff --git a/src/yuzu/configuration/configure_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 @@
<x>0</x>
<y>0</y>
<width>400</width>
- <height>486</height>
+ <height>777</height>
</rect>
</property>
<property name="windowTitle">
@@ -192,34 +192,41 @@
</property>
</widget>
</item>
- <item>
- <widget class="QCheckBox" name="use_debug_asserts">
- <property name="text">
- <string>Enable Debug Asserts</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="use_auto_stub">
- <property name="text">
- <string>Enable Auto-Stub</string>
- </property>
- </widget>
- </item>
<item>
- <widget class="QLabel" name="label_5">
- <property name="font">
- <font>
- <italic>true</italic>
- </font>
- </property>
- <property name="text">
- <string>This will be reset automatically when yuzu closes.</string>
- </property>
- <property name="indent">
- <number>20</number>
- </property>
- </widget>
+ <widget class="QCheckBox" name="enable_cpu_debugging">
+ <property name="text">
+ <string>Enable CPU Debugging</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="use_debug_asserts">
+ <property name="text">
+ <string>Enable Debug Asserts</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="use_auto_stub">
+ <property name="text">
+ <string>Enable Auto-Stub</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>This will be reset automatically when yuzu closes.</string>
+ </property>
+ <property name="indent">
+ <number>20</number>
+ </property>
+ </widget>
</item>
</layout>
</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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "ui_configure_debug_tab.h"
+#include "yuzu/configuration/configure_debug_tab.h"
+
+ConfigureDebugTab::ConfigureDebugTab(QWidget* parent)
+ : QWidget(parent), ui(new Ui::ConfigureDebugTab) {
+ ui->setupUi(this);
+
+ SetConfiguration();
+}
+
+ConfigureDebugTab::~ConfigureDebugTab() = default;
+
+void ConfigureDebugTab::ApplyConfiguration() {
+ ui->debugTab->ApplyConfiguration();
+ ui->cpuDebugTab->ApplyConfiguration();
+}
+
+void ConfigureDebugTab::SetCurrentIndex(int index) {
+ ui->tabWidget->setCurrentIndex(index);
+}
+
+void ConfigureDebugTab::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QWidget::changeEvent(event);
+}
+
+void ConfigureDebugTab::RetranslateUI() {
+ ui->retranslateUi(this);
+}
+
+void 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QWidget>
+
+namespace Ui {
+class ConfigureDebugTab;
+}
+
+class ConfigureDebugTab : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureDebugTab(QWidget* parent = nullptr);
+ ~ConfigureDebugTab() override;
+
+ void ApplyConfiguration();
+
+ void SetCurrentIndex(int index);
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ void SetConfiguration();
+
+ std::unique_ptr<Ui::ConfigureDebugTab> ui;
+};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureDebugTab</class>
+ <widget class="QWidget" name="ConfigureDebugTab">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="ConfigureDebug" name="debugTab">
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureCpuDebug" name="cpuDebugTab">
+ <attribute name="title">
+ <string>CPU</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ConfigureDebug</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_debug.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureCpuDebug</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_cpu_debug.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</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 @@
#include <QListWidgetItem>
#include <QPushButton>
#include <QSignalBlocker>
+#include <QTabWidget>
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure.h"
@@ -32,6 +33,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
SetConfiguration();
PopulateSelectionList();
+ connect(ui->tabWidget, &QTabWidget::currentChanged, this,
+ [this]() { ui->debugTab->SetCurrentIndex(0); });
connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs);
@@ -59,7 +62,6 @@ void ConfigureDialog::ApplyConfiguration() {
ui->inputTab->ApplyConfiguration();
ui->hotkeysTab->ApplyConfiguration(registry);
ui->cpuTab->ApplyConfiguration();
- ui->cpuDebugTab->ApplyConfiguration();
ui->graphicsTab->ApplyConfiguration();
ui->graphicsAdvancedTab->ApplyConfiguration();
ui->audioTab->ApplyConfiguration();
@@ -102,7 +104,7 @@ void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
{{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
- {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
+ {tr("CPU"), {ui->cpuTab}},
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
{tr("Audio"), {ui->audioTab}},
{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() {
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir)));
ui->sdmc_directory_edit->setText(
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::SDMCDir)));
- ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path));
+ ui->gamecard_path_edit->setText(
+ QString::fromStdString(Settings::values.gamecard_path.GetValue()));
ui->dump_path_edit->setText(
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
ui->load_path_edit->setText(
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
- ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted);
- ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game);
- ui->dump_exefs->setChecked(Settings::values.dump_exefs);
- ui->dump_nso->setChecked(Settings::values.dump_nso);
+ ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue());
+ ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue());
+ ui->dump_exefs->setChecked(Settings::values.dump_exefs.GetValue());
+ ui->dump_nso->setChecked(Settings::values.dump_nso.GetValue());
- ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
+ ui->cache_game_list->setChecked(UISettings::values.cache_game_list.GetValue());
UpdateEnabledControls();
}
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 38edb4d8d..18f25def6 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -40,10 +40,10 @@ void ConfigureGeneral::SetConfiguration() {
ui->use_multi_core->setEnabled(runtime_lock);
ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
- ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
- ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
- ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
- ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
+ ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
+ ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
+ ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
+ ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
diff --git a/src/yuzu/configuration/configure_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() {
ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
- ui->disable_fps_limit->setChecked(Settings::values.disable_fps_limit.GetValue());
ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue());
@@ -59,8 +58,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
ui->anisotropic_filtering_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.disable_fps_limit,
- ui->disable_fps_limit, disable_fps_limit);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
ui->use_assembly_shaders, use_assembly_shaders);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
@@ -103,7 +100,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
- ui->disable_fps_limit->setEnabled(Settings::values.disable_fps_limit.UsingGlobal());
ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal());
ui->use_asynchronous_shaders->setEnabled(
Settings::values.use_asynchronous_shaders.UsingGlobal());
@@ -116,8 +112,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
}
ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync);
- ConfigurationShared::SetColoredTristate(ui->disable_fps_limit,
- Settings::values.disable_fps_limit, disable_fps_limit);
ConfigurationShared::SetColoredTristate(
ui->use_assembly_shaders, Settings::values.use_assembly_shaders, use_assembly_shaders);
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:
std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
ConfigurationShared::CheckState use_vsync;
- ConfigurationShared::CheckState disable_fps_limit;
ConfigurationShared::CheckState use_assembly_shaders;
ConfigurationShared::CheckState use_asynchronous_shaders;
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 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="disable_fps_limit">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="toolTip">
- <string>
- &lt;html&gt;&lt;head/&gt;&lt;body&gt;
- &lt;p&gt;Presents guest frames as they become available, disabling the FPS limit in most titles.&lt;/p&gt;
- &lt;p&gt;NOTE: Will cause instabilities.&lt;/p&gt;
- &lt;/body&gt;&lt;/html&gt;
- </string>
- </property>
- <property name="text">
- <string>Disable framerate limit (experimental)</string>
- </property>
- </widget>
- </item>
- <item>
<widget class="QCheckBox" name="use_assembly_shaders">
<property name="toolTip">
<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() {
}
}
- ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
- ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
- ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
- ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard);
- ui->mouse_panning->setChecked(Settings::values.mouse_panning);
- ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity);
+ ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled.GetValue());
+ ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue());
+ ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue());
+ ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue());
+ ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue());
+ ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
UpdateUIEnabled();
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 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,
ConfigureMotionTouch::~ConfigureMotionTouch() = default;
void ConfigureMotionTouch::SetConfiguration() {
- const Common::ParamPackage motion_param(Settings::values.motion_device);
- const Common::ParamPackage touch_param(Settings::values.touch_device);
+ const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue());
+ const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
- ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
+ ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue());
touch_from_button_maps = Settings::values.touch_from_button_maps;
for (const auto& touch_map : touch_from_button_maps) {
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
}
- ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index);
+ ui->touch_from_button_map->setCurrentIndex(
+ Settings::values.touch_from_button_map_index.GetValue());
ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
min_x = touch_param.Get("min_x", 100);
@@ -124,7 +125,7 @@ void ConfigureMotionTouch::SetConfiguration() {
udp_server_list_model->setStringList({});
ui->udp_server_list->setModel(udp_server_list_model);
- std::stringstream ss(Settings::values.udp_input_servers);
+ std::stringstream ss(Settings::values.udp_input_servers.GetValue());
std::string token;
while (std::getline(ss, token, ',')) {
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index 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() {
void ConfigureProfileManager::UpdateCurrentUser() {
ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
- const auto& current_user = profile_manager->GetUser(Settings::values.current_user);
+ const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue());
ASSERT(current_user);
const auto username = GetAccountUsername(*profile_manager, *current_user);
@@ -245,15 +245,18 @@ void ConfigureProfileManager::DeleteUser() {
this, tr("Confirm Delete"),
tr("You are about to delete user with name \"%1\". Are you sure?").arg(username));
- if (confirm == QMessageBox::No)
+ if (confirm == QMessageBox::No) {
return;
+ }
- if (Settings::values.current_user == tree_view->currentIndex().row())
+ if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) {
Settings::values.current_user = 0;
+ }
UpdateCurrentUser();
- if (!profile_manager->RemoveUser(*uuid))
+ if (!profile_manager->RemoveUser(*uuid)) {
return;
+ }
item_model->removeRows(tree_view->currentIndex().row(), 1);
tree_view->clearSelection();
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp
index 6d954a67f..4aa424803 100644
--- a/src/yuzu/configuration/configure_service.cpp
+++ b/src/yuzu/configuration/configure_service.cpp
@@ -65,7 +65,7 @@ void ConfigureService::RetranslateUi() {
void ConfigureService::SetConfiguration() {
const int index =
- ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend));
+ ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
}
diff --git a/src/yuzu/configuration/configure_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() {
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
ui->language_combobox->setCurrentIndex(
ui->language_combobox->findData(UISettings::values.language));
- ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
+ ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
ui->icon_size_combobox->setCurrentIndex(
- ui->icon_size_combobox->findData(UISettings::values.icon_size));
+ ui->icon_size_combobox->findData(UISettings::values.icon_size.GetValue()));
- ui->enable_screenshot_save_as->setChecked(UISettings::values.enable_screenshot_save_as);
+ ui->enable_screenshot_save_as->setChecked(
+ UISettings::values.enable_screenshot_save_as.GetValue());
ui->screenshot_path_edit->setText(QString::fromStdString(
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
}
@@ -178,7 +179,7 @@ void ConfigureUi::InitializeRowComboBoxes() {
void ConfigureUi::UpdateFirstRowComboBox(bool init) {
const int currentIndex =
- init ? UISettings::values.row_1_text_id
+ init ? UISettings::values.row_1_text_id.GetValue()
: ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
ui->row_1_text_combobox->clear();
@@ -197,7 +198,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
void ConfigureUi::UpdateSecondRowComboBox(bool init) {
const int currentIndex =
- init ? UISettings::values.row_2_text_id
+ init ? UISettings::values.row_2_text_id.GetValue()
: ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
ui->row_2_text_combobox->clear();
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index f3f3b54d6..d779251b4 100644
--- a/src/yuzu/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -88,22 +88,22 @@ void ConfigureWeb::SetConfiguration() {
ui->web_signup_link->setOpenExternalLinks(true);
ui->web_token_info_link->setOpenExternalLinks(true);
- if (Settings::values.yuzu_username.empty()) {
+ if (Settings::values.yuzu_username.GetValue().empty()) {
ui->username->setText(tr("Unspecified"));
} else {
- ui->username->setText(QString::fromStdString(Settings::values.yuzu_username));
+ ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
}
- ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry);
- ui->edit_token->setText(QString::fromStdString(
- GenerateDisplayToken(Settings::values.yuzu_username, Settings::values.yuzu_token)));
+ ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry.GetValue());
+ ui->edit_token->setText(QString::fromStdString(GenerateDisplayToken(
+ Settings::values.yuzu_username.GetValue(), Settings::values.yuzu_token.GetValue())));
// Connect after setting the values, to avoid calling OnLoginChanged now
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
user_verified = true;
- ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence);
+ ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
}
void ConfigureWeb::ApplyConfiguration() {
diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp
index c11a326ac..22ca1285d 100644
--- a/src/yuzu/debugger/console.cpp
+++ b/src/yuzu/debugger/console.cpp
@@ -15,10 +15,10 @@
namespace Debugger {
void ToggleConsole() {
static bool console_shown = false;
- if (console_shown == UISettings::values.show_console) {
+ if (console_shown == UISettings::values.show_console.GetValue()) {
return;
} else {
- console_shown = UISettings::values.show_console;
+ console_shown = UISettings::values.show_console.GetValue();
}
#if defined(_WIN32) && !defined(_DEBUG)
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index e44907be8..218b4782b 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -244,7 +244,8 @@ void GameList::OnUpdateThemedIcons() {
for (int i = 0; i < item_model->invisibleRootItem()->rowCount(); i++) {
QStandardItem* child = item_model->invisibleRootItem()->child(i);
- const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+ const int icon_size =
+ std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) {
case GameListItemType::SdmcDir:
child->setData(
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 978d27325..982c0789d 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -80,7 +80,7 @@ public:
setData(qulonglong(program_id), ProgramIdRole);
setData(game_type, FileTypeRole);
- const u32 size = UISettings::values.icon_size;
+ const u32 size = UISettings::values.icon_size.GetValue();
QPixmap picture;
if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
@@ -108,8 +108,8 @@ public:
data(TitleRole).toString(),
}};
- const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
- const int row2_id = UISettings::values.row_2_text_id;
+ const auto& row1 = row_data.at(UISettings::values.row_1_text_id.GetValue());
+ const int row2_id = UISettings::values.row_2_text_id.GetValue();
if (role == SortRole) {
return row1.toLower();
@@ -233,7 +233,8 @@ public:
UISettings::GameDir* game_dir = &directory;
setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole);
- const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+ const int icon_size =
+ std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
switch (dir_type) {
case GameListItemType::SdmcDir:
setData(
@@ -294,7 +295,8 @@ public:
explicit GameListAddDir() {
setData(type(), TypeRole);
- const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+ const int icon_size =
+ std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
setData(QIcon::fromTheme(QStringLiteral("plus"))
.pixmap(icon_size)
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
@@ -316,7 +318,8 @@ public:
explicit GameListFavorites() {
setData(type(), TypeRole);
- const int icon_size = std::min(static_cast<int>(UISettings::values.icon_size), 64);
+ const int icon_size =
+ std::min(static_cast<int>(UISettings::values.icon_size.GetValue()), 64);
setData(QIcon::fromTheme(QStringLiteral("star"))
.pixmap(icon_size)
.scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f462cd072..cb9c01154 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -156,11 +156,13 @@ enum class CalloutFlag : uint32_t {
};
void GMainWindow::ShowTelemetryCallout() {
- if (UISettings::values.callout_flags & static_cast<uint32_t>(CalloutFlag::Telemetry)) {
+ if (UISettings::values.callout_flags.GetValue() &
+ static_cast<uint32_t>(CalloutFlag::Telemetry)) {
return;
}
- UISettings::values.callout_flags |= static_cast<uint32_t>(CalloutFlag::Telemetry);
+ UISettings::values.callout_flags =
+ UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
const QString telemetry_message =
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
"data is collected</a> to help improve yuzu. "
@@ -177,7 +179,7 @@ static void InitializeLogging() {
using namespace Common;
Log::Filter log_filter;
- log_filter.ParseFilterString(Settings::values.log_filter);
+ log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
Log::SetGlobalFilter(log_filter);
const auto log_dir = FS::GetYuzuPath(FS::YuzuPath::LogDir);
@@ -216,7 +218,7 @@ GMainWindow::GMainWindow()
default_theme_paths = QIcon::themeSearchPaths();
UpdateUITheme();
- SetDiscordEnabled(UISettings::values.enable_discord_presence);
+ SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
discord_rpc->Update();
RegisterMetaTypes();
@@ -1060,23 +1062,24 @@ void GMainWindow::RestoreUIState() {
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
#if MICROPROFILE_ENABLED
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
- microProfileDialog->setVisible(UISettings::values.microprofile_visible);
+ microProfileDialog->setVisible(UISettings::values.microprofile_visible.GetValue());
#endif
game_list->LoadInterfaceLayout();
- ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
+ ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue());
ToggleWindowMode();
- ui.action_Fullscreen->setChecked(UISettings::values.fullscreen);
+ ui.action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue());
- ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
+ ui.action_Display_Dock_Widget_Headers->setChecked(
+ UISettings::values.display_titlebar.GetValue());
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
- ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
+ ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue());
game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked());
- ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
+ ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
Debugger::ToggleConsole();
}
@@ -1243,13 +1246,14 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
const Core::System::ResultStatus result{
system.Load(*render_window, filename.toStdString(), program_index)};
- const auto drd_callout =
- (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
+ const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
+ static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
if (result == Core::System::ResultStatus::Success &&
system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
drd_callout) {
- UISettings::values.callout_flags |= static_cast<u32>(CalloutFlag::DRDDeprecation);
+ UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() |
+ static_cast<u32>(CalloutFlag::DRDDeprecation);
QMessageBox::warning(
this, tr("Warning Outdated Game Format"),
tr("You are using the deconstructed ROM directory format for this game, which is an "
@@ -1351,6 +1355,9 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
ConfigureVibration::SetAllVibrationDevices();
+ // Disable fps limit toggle when booting a new title
+ Settings::values.disable_fps_limit.SetValue(false);
+
// Save configurations
UpdateUISettings();
game_list->SaveInterfaceLayout();
@@ -2453,7 +2460,8 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
}
void GMainWindow::OnMenuReportCompatibility() {
- if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) {
+ if (!Settings::values.yuzu_token.GetValue().empty() &&
+ !Settings::values.yuzu_username.GetValue().empty()) {
CompatDB compatdb{this};
compatdb.exec();
} else {
@@ -2618,7 +2626,7 @@ void GMainWindow::ResetWindowSize1080() {
void GMainWindow::OnConfigure() {
const auto old_theme = UISettings::values.theme;
- const bool old_discord_presence = UISettings::values.enable_discord_presence;
+ const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get());
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
@@ -2675,8 +2683,8 @@ void GMainWindow::OnConfigure() {
if (UISettings::values.theme != old_theme) {
UpdateUITheme();
}
- if (UISettings::values.enable_discord_presence != old_discord_presence) {
- SetDiscordEnabled(UISettings::values.enable_discord_presence);
+ if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) {
+ SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
}
emit UpdateThemedIcons();
@@ -2832,7 +2840,8 @@ void GMainWindow::OnCaptureScreenshot() {
}
}
#endif
- render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename);
+ render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(),
+ filename);
OnStartGame();
}
@@ -2907,7 +2916,12 @@ void GMainWindow::UpdateStatusBar() {
} else {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
}
- game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
+ if (Settings::values.disable_fps_limit) {
+ game_fps_label->setText(
+ tr("Game: %1 FPS (Limit off)").arg(results.average_game_fps, 0, 'f', 0));
+ } else {
+ game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
+ }
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
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 @@
#include <QStringList>
#include <QVector>
#include "common/common_types.h"
+#include "common/settings.h"
namespace UISettings {
@@ -48,26 +49,26 @@ struct Values {
QByteArray gamelist_header_state;
QByteArray microprofile_geometry;
- bool microprofile_visible;
+ Settings::BasicSetting<bool> microprofile_visible{false, "microProfileDialogVisible"};
- bool single_window_mode;
- bool fullscreen;
- bool display_titlebar;
- bool show_filter_bar;
- bool show_status_bar;
+ Settings::BasicSetting<bool> single_window_mode{true, "singleWindowMode"};
+ Settings::BasicSetting<bool> fullscreen{false, "fullscreen"};
+ Settings::BasicSetting<bool> display_titlebar{true, "displayTitleBars"};
+ Settings::BasicSetting<bool> show_filter_bar{true, "showFilterBar"};
+ Settings::BasicSetting<bool> show_status_bar{true, "showStatusBar"};
- bool confirm_before_closing;
- bool first_start;
- bool pause_when_in_background;
- bool hide_mouse;
+ Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
+ Settings::BasicSetting<bool> first_start{true, "firstStart"};
+ Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
+ Settings::BasicSetting<bool> hide_mouse{false, "hideInactiveMouse"};
- bool select_user_on_boot;
+ Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};
// Discord RPC
- bool enable_discord_presence;
+ Settings::BasicSetting<bool> enable_discord_presence{true, "enable_discord_presence"};
- bool enable_screenshot_save_as;
- u16 screenshot_resolution_factor;
+ Settings::BasicSetting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
+ Settings::BasicSetting<u16> screenshot_resolution_factor{0, "screenshot_resolution_factor"};
QString roms_path;
QString symbols_path;
@@ -83,18 +84,18 @@ struct Values {
// Shortcut name <Shortcut, context>
std::vector<Shortcut> shortcuts;
- uint32_t callout_flags;
+ Settings::BasicSetting<uint32_t> callout_flags{0, "calloutFlags"};
// logging
- bool show_console;
+ Settings::BasicSetting<bool> show_console{false, "showConsole"};
// Game List
- bool show_add_ons;
- uint32_t icon_size;
- uint8_t row_1_text_id;
- uint8_t row_2_text_id;
+ Settings::BasicSetting<bool> show_add_ons{true, "show_add_ons"};
+ Settings::BasicSetting<uint32_t> icon_size{64, "icon_size"};
+ Settings::BasicSetting<uint8_t> row_1_text_id{3, "row_1_text_id"};
+ Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"};
std::atomic_bool is_game_list_reload_pending{false};
- bool cache_game_list;
+ Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"};
bool configuration_applied;
bool reset_to_defaults;
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{
SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
};
+template <>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<float>& setting) {
+ setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
+}
+template <>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
+ setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
+}
+template <>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) {
+ setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
+}
+template <typename Type>
+void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting) {
+ setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
+ static_cast<long>(setting.GetDefault())));
+}
+
void Config::ReadValues() {
// Controls
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
@@ -264,8 +282,7 @@ void Config::ReadValues() {
}
}
- Settings::values.mouse_enabled =
- sdl2_config->GetBoolean("ControlsGeneral", "mouse_enabled", false);
+ ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
Settings::values.mouse_buttons[i] = sdl2_config->Get(
@@ -275,14 +292,11 @@ void Config::ReadValues() {
Settings::values.mouse_buttons[i] = default_param;
}
- Settings::values.motion_device = sdl2_config->Get(
- "ControlsGeneral", "motion_device", "engine:motion_emu,update_period:100,sensitivity:0.01");
+ ReadSetting("ControlsGeneral", Settings::values.motion_device);
- Settings::values.keyboard_enabled =
- sdl2_config->GetBoolean("ControlsGeneral", "keyboard_enabled", false);
+ ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
- Settings::values.debug_pad_enabled =
- sdl2_config->GetBoolean("ControlsGeneral", "debug_pad_enabled", false);
+ ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
@@ -303,12 +317,9 @@ void Config::ReadValues() {
Settings::values.debug_pad_analogs[i] = default_param;
}
- Settings::values.vibration_enabled.SetValue(
- sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true));
- Settings::values.enable_accurate_vibrations.SetValue(
- sdl2_config->GetBoolean("ControlsGeneral", "enable_accurate_vibrations", false));
- Settings::values.motion_enabled.SetValue(
- sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true));
+ ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
+ ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
+ ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
Settings::values.touchscreen.enabled =
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
Settings::values.touchscreen.rotation_angle =
@@ -349,13 +360,11 @@ void Config::ReadValues() {
Settings::TouchFromButtonMap{"default", {}});
num_touch_from_button_maps = 1;
}
- Settings::values.use_touch_from_button =
- sdl2_config->GetBoolean("ControlsGeneral", "use_touch_from_button", false);
- Settings::values.touch_from_button_map_index =
- std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
+ ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button);
+ Settings::values.touch_from_button_map_index = std::clamp(
+ Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
- Settings::values.udp_input_servers =
- sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV);
+ ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
std::transform(keyboard_keys.begin(), keyboard_keys.end(),
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
@@ -367,8 +376,7 @@ void Config::ReadValues() {
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
// Data Storage
- Settings::values.use_virtual_sd =
- sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
+ ReadSetting("Data Storage", Settings::values.use_virtual_sd);
FS::SetYuzuPath(FS::YuzuPath::NANDDir,
sdl2_config->Get("Data Storage", "nand_directory",
FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -381,18 +389,16 @@ void Config::ReadValues() {
FS::SetYuzuPath(FS::YuzuPath::DumpDir,
sdl2_config->Get("Data Storage", "dump_directory",
FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
- Settings::values.gamecard_inserted =
- sdl2_config->GetBoolean("Data Storage", "gamecard_inserted", false);
- Settings::values.gamecard_current_game =
- sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
- Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
+ ReadSetting("Data Storage", Settings::values.gamecard_inserted);
+ ReadSetting("Data Storage", Settings::values.gamecard_current_game);
+ ReadSetting("Data Storage", Settings::values.gamecard_path);
// System
- Settings::values.use_docked_mode.SetValue(
- sdl2_config->GetBoolean("System", "use_docked_mode", true));
+ ReadSetting("System", Settings::values.use_docked_mode);
- Settings::values.current_user = std::clamp<int>(
- sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
+ ReadSetting("System", Settings::values.current_user);
+ Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
+ Service::Account::MAX_USERS - 1);
const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
if (rng_seed_enabled) {
@@ -409,89 +415,60 @@ void Config::ReadValues() {
Settings::values.custom_rtc = std::nullopt;
}
- Settings::values.language_index.SetValue(
- sdl2_config->GetInteger("System", "language_index", 1));
- Settings::values.time_zone_index.SetValue(
- sdl2_config->GetInteger("System", "time_zone_index", 0));
+ ReadSetting("System", Settings::values.language_index);
+ ReadSetting("System", Settings::values.time_zone_index);
// Core
- Settings::values.use_multi_core.SetValue(
- sdl2_config->GetBoolean("Core", "use_multi_core", true));
+ ReadSetting("Core", Settings::values.use_multi_core);
// Renderer
- const int renderer_backend = sdl2_config->GetInteger(
- "Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL));
- Settings::values.renderer_backend.SetValue(
- static_cast<Settings::RendererBackend>(renderer_backend));
- Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false);
- Settings::values.vulkan_device.SetValue(
- sdl2_config->GetInteger("Renderer", "vulkan_device", 0));
-
- Settings::values.aspect_ratio.SetValue(
- static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
- Settings::values.max_anisotropy.SetValue(
- static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
- Settings::values.use_frame_limit.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_frame_limit", true));
- Settings::values.frame_limit.SetValue(
- static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)));
- Settings::values.use_disk_shader_cache.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
- const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 1);
- Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
- Settings::values.use_asynchronous_gpu_emulation.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", true));
- Settings::values.use_vsync.SetValue(
- static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
- Settings::values.disable_fps_limit.SetValue(
- sdl2_config->GetBoolean("Renderer", "disable_fps_limit", false));
- Settings::values.use_assembly_shaders.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true));
- Settings::values.use_asynchronous_shaders.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false));
- Settings::values.use_nvdec_emulation.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_nvdec_emulation", true));
- Settings::values.accelerate_astc.SetValue(
- sdl2_config->GetBoolean("Renderer", "accelerate_astc", true));
- Settings::values.use_fast_gpu_time.SetValue(
- sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
-
- Settings::values.bg_red.SetValue(
- static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
- Settings::values.bg_green.SetValue(
- static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
- Settings::values.bg_blue.SetValue(
- static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
+ ReadSetting("Renderer", Settings::values.renderer_backend);
+ ReadSetting("Renderer", Settings::values.renderer_debug);
+ ReadSetting("Renderer", Settings::values.vulkan_device);
+
+ ReadSetting("Renderer", Settings::values.aspect_ratio);
+ ReadSetting("Renderer", Settings::values.max_anisotropy);
+ ReadSetting("Renderer", Settings::values.use_frame_limit);
+ ReadSetting("Renderer", Settings::values.frame_limit);
+ ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
+ ReadSetting("Renderer", Settings::values.gpu_accuracy);
+ ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
+ ReadSetting("Renderer", Settings::values.use_vsync);
+ ReadSetting("Renderer", Settings::values.disable_fps_limit);
+ ReadSetting("Renderer", Settings::values.use_assembly_shaders);
+ ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
+ ReadSetting("Renderer", Settings::values.use_nvdec_emulation);
+ ReadSetting("Renderer", Settings::values.accelerate_astc);
+ ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
+
+ ReadSetting("Renderer", Settings::values.bg_red);
+ ReadSetting("Renderer", Settings::values.bg_green);
+ ReadSetting("Renderer", Settings::values.bg_blue);
// Audio
- Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
- Settings::values.enable_audio_stretching.SetValue(
- sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true));
- Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
- Settings::values.volume.SetValue(
- static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)));
+ ReadSetting("Audio", Settings::values.sink_id);
+ ReadSetting("Audio", Settings::values.enable_audio_stretching);
+ ReadSetting("Audio", Settings::values.audio_device_id);
+ ReadSetting("Audio", Settings::values.volume);
// Miscellaneous
- Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
- Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false);
+ // log_filter has a different default here than from common
+ Settings::values.log_filter =
+ sdl2_config->Get("Miscellaneous", Settings::values.log_filter.GetLabel(), "*:Trace");
+ ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
// Debugging
Settings::values.record_frame_times =
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
- Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
- Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
- Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
- Settings::values.enable_fs_access_log =
- sdl2_config->GetBoolean("Debugging", "enable_fs_access_log", false);
- Settings::values.reporting_services =
- sdl2_config->GetBoolean("Debugging", "reporting_services", false);
- Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
- Settings::values.use_debug_asserts =
- sdl2_config->GetBoolean("Debugging", "use_debug_asserts", false);
- Settings::values.use_auto_stub = sdl2_config->GetBoolean("Debugging", "use_auto_stub", false);
-
- Settings::values.disable_macro_jit =
- sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
+ ReadSetting("Debugging", Settings::values.program_args);
+ ReadSetting("Debugging", Settings::values.dump_exefs);
+ ReadSetting("Debugging", Settings::values.dump_nso);
+ ReadSetting("Debugging", Settings::values.enable_fs_access_log);
+ ReadSetting("Debugging", Settings::values.reporting_services);
+ ReadSetting("Debugging", Settings::values.quest_flag);
+ ReadSetting("Debugging", Settings::values.use_debug_asserts);
+ ReadSetting("Debugging", Settings::values.use_auto_stub);
+ ReadSetting("Debugging", Settings::values.disable_macro_jit);
const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
std::stringstream ss(title_list);
@@ -511,17 +488,14 @@ void Config::ReadValues() {
}
// Web Service
- Settings::values.enable_telemetry =
- sdl2_config->GetBoolean("WebService", "enable_telemetry", true);
- Settings::values.web_api_url =
- sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org");
- Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", "");
- Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", "");
+ ReadSetting("WebService", Settings::values.enable_telemetry);
+ ReadSetting("WebService", Settings::values.web_api_url);
+ ReadSetting("WebService", Settings::values.yuzu_username);
+ ReadSetting("WebService", Settings::values.yuzu_token);
// Services
- Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "none");
- Settings::values.bcat_boxcat_local =
- sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false);
+ ReadSetting("Services", Settings::values.bcat_backend);
+ ReadSetting("Services", Settings::values.bcat_boxcat_local);
}
void Config::Reload() {
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index 807199278..1ee932be2 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -8,6 +8,8 @@
#include <memory>
#include <string>
+#include "common/settings.h"
+
class INIReader;
class Config {
@@ -22,4 +24,14 @@ public:
~Config();
void Reload();
+
+private:
+ /**
+ * Applies a value read from the sdl2_config to a BasicSetting.
+ *
+ * @param group The name of the INI group
+ * @param setting The yuzu setting to modify
+ */
+ template <typename Type>
+ void ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting);
};
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() {
using namespace Common;
Log::Filter log_filter(Log::Level::Debug);
- log_filter.ParseFilterString(Settings::values.log_filter);
+ log_filter.ParseFilterString(static_cast<std::string>(Settings::values.log_filter));
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());