From cae72a4c691dfa7b0708cd8c4313d6b1445cadc5 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Sat, 3 Jul 2021 11:00:06 +0200 Subject: [PATCH] early-access version 1840 --- README.md | 2 +- src/audio_core/audio_out.cpp | 3 +- src/common/settings.cpp | 16 +- src/common/settings.h | 431 ++++++++--- src/core/CMakeLists.txt | 2 + src/core/core.cpp | 6 +- src/core/frontend/applets/profile_select.cpp | 2 +- src/core/hle/kernel/hle_ipc.cpp | 3 + src/core/hle/kernel/k_auto_object.cpp | 9 + src/core/hle/kernel/k_auto_object.h | 12 +- src/core/hle/kernel/k_process.cpp | 8 +- src/core/hle/kernel/k_server_session.cpp | 5 +- src/core/hle/kernel/kernel.cpp | 97 ++- src/core/hle/kernel/kernel.h | 17 + src/core/hle/kernel/svc.cpp | 1 + src/core/hle/service/acc/profile_manager.cpp | 3 +- src/core/hle/service/am/am.cpp | 2 +- src/core/hle/service/bcat/module.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 12 +- src/core/hle/service/hid/controllers/npad.h | 8 +- src/core/hle/service/hid/hid.cpp | 14 +- src/core/hle/service/hid/hid.h | 13 +- src/core/hle/service/kernel_helpers.cpp | 64 ++ src/core/hle/service/kernel_helpers.h | 35 + src/core/hle/service/nifm/nifm.cpp | 6 +- src/core/hle/service/nvdrv/nvdrv.cpp | 10 +- src/core/hle/service/nvdrv/nvdrv.h | 3 + src/core/hle/service/service.cpp | 11 +- src/core/hle/service/service.h | 7 +- src/core/hle/service/set/set.cpp | 2 +- src/core/hle/service/sm/sm.cpp | 65 +- src/core/hle/service/sm/sm.h | 14 +- src/core/loader/nro.cpp | 4 +- src/core/loader/nso.cpp | 4 +- src/core/reporter.cpp | 2 +- src/core/telemetry_session.cpp | 10 +- src/input_common/mouse/mouse_poller.cpp | 3 +- src/input_common/touch_from_button.cpp | 2 +- src/input_common/udp/client.cpp | 4 +- src/video_core/cdma_pusher.cpp | 3 +- .../command_classes/codecs/codec.cpp | 87 ++- src/video_core/command_classes/codecs/codec.h | 12 +- .../command_classes/codecs/h264.cpp | 243 +++--- src/video_core/command_classes/codecs/h264.h | 138 +++- src/video_core/command_classes/codecs/vp9.cpp | 4 +- .../command_classes/codecs/vp9_types.h | 307 ++++---- src/video_core/command_classes/nvdec.cpp | 17 +- src/video_core/command_classes/nvdec.h | 8 +- src/video_core/command_classes/nvdec_common.h | 103 ++- .../renderer_vulkan/renderer_vulkan.cpp | 2 +- src/yuzu/configuration/config.cpp | 715 ++++++++---------- src/yuzu/configuration/config.h | 75 +- src/yuzu/configuration/configure_audio.cpp | 8 +- .../configuration/configure_cpu_debug.cpp | 21 +- src/yuzu/configuration/configure_debug.cpp | 25 +- .../configuration/configure_filesystem.cpp | 13 +- src/yuzu/configuration/configure_general.cpp | 8 +- .../configure_input_advanced.cpp | 12 +- .../configuration/configure_motion_touch.cpp | 11 +- .../configure_profile_manager.cpp | 11 +- src/yuzu/configuration/configure_service.cpp | 2 +- src/yuzu/configuration/configure_ui.cpp | 11 +- src/yuzu/configuration/configure_web.cpp | 12 +- src/yuzu/debugger/console.cpp | 4 +- src/yuzu/game_list.cpp | 3 +- src/yuzu/game_list_p.h | 15 +- src/yuzu/main.cpp | 42 +- src/yuzu/uisettings.h | 43 +- src/yuzu_cmd/config.cpp | 192 ++--- src/yuzu_cmd/config.h | 12 + src/yuzu_cmd/yuzu.cpp | 2 +- 71 files changed, 1818 insertions(+), 1257 deletions(-) create mode 100755 src/core/hle/service/kernel_helpers.cpp create mode 100755 src/core/hle/service/kernel_helpers.h diff --git a/README.md b/README.md index dc905ef8b..5a5eb80a2 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 1838. +This is the source code for early-access 1840. ## Legal Notice diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp index 20a756dce..44a899d08 100755 --- 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( diff --git a/src/common/settings.cpp b/src/common/settings.cpp index e1bb4b7ff..0061e29cc 100755 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -41,7 +41,7 @@ void LogSettings() { LOG_INFO(Config, "yuzu Configuration:"); log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue()); log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); - log_setting("System_CurrentUser", values.current_user); + log_setting("System_CurrentUser", values.current_user.GetValue()); log_setting("System_LanguageIndex", values.language_index.GetValue()); log_setting("System_RegionIndex", values.region_index.GetValue()); log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); @@ -61,18 +61,18 @@ void LogSettings() { log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue()); log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); - log_setting("Audio_OutputEngine", values.sink_id); + log_setting("Audio_OutputEngine", values.sink_id.GetValue()); log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); - log_setting("Audio_OutputDevice", values.audio_device_id); - log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); + log_setting("Audio_OutputDevice", values.audio_device_id.GetValue()); + log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue()); log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir)); log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir)); log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir)); log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir)); log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); - log_setting("Debugging_ProgramArgs", values.program_args); - log_setting("Services_BCATBackend", values.bcat_backend); - log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); + log_setting("Debugging_ProgramArgs", values.program_args.GetValue()); + log_setting("Services_BCATBackend", values.bcat_backend.GetValue()); + log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue()); } bool IsConfiguringGlobal() { @@ -94,7 +94,7 @@ bool IsGPULevelHigh() { bool IsFastmemEnabled() { if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) { - return values.cpuopt_fastmem; + return static_cast(values.cpuopt_fastmem); } return true; } diff --git a/src/common/settings.h b/src/common/settings.h index 82ec18e27..c799e6243 100755 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -10,10 +10,12 @@ #include #include #include +#include #include #include "common/common_types.h" #include "common/settings_input.h" +#include "input_common/udp/client.h" namespace Settings { @@ -34,68 +36,236 @@ enum class CPUAccuracy : u32 { DebugMode = 2, }; +/** The BasicSetting class is a simple resource manager. It defines a label and default value + * alongside the actual value of the setting for simpler and less-error prone use with frontend + * configurations. Setting a default value and label is required, though subclasses may deviate from + * this requirement. + */ template -class Setting final { +class BasicSetting { +protected: + BasicSetting() = default; + + /** + * Only sets the setting to the given initializer, leaving the other members to their default + * initializers. + * + * @param global_val Initial value of the setting + */ + explicit BasicSetting(const Type& global_val) : global{global_val} {} + public: - Setting() = default; - explicit Setting(Type val) : global{val} {} - ~Setting() = default; - void SetGlobal(bool to_global) { - use_global = to_global; - } - bool UsingGlobal() const { - return use_global; - } - Type GetValue(bool need_global = false) const { - if (use_global || need_global) { - return global; - } - return local; - } - void SetValue(const Type& value) { - if (use_global) { - global = value; - } else { - local = value; - } + /** + * 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; } -private: - bool use_global = true; - Type global{}; - Type local{}; + /** + * 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 InputSetting class allows for getting a reference to either the global or local members. + * The Setting class is a slightly more complex version of the BasicSetting class. This adds a + * custom setting to switch to when a guest application specifically requires it. The effect is that + * other components of the emulator can access the setting's intended value without any need for the + * component to ask whether the custom or global setting is needed at the moment. + * + * By default, the global setting is used. + * + * Like the BasicSetting, this requires setting a default value and label to use. + */ +template +class Setting final : public BasicSetting { +public: + /** + * Sets a default value, label, and setting value. + * + * @param default_val Intial value of the setting, and default value of the setting + * @param name Label for the setting + */ + explicit Setting(const Type& default_val, const std::string& name) + : BasicSetting(default_val, name) {} + ~Setting() = default; + + /** + * Tells this setting to represent either the global or custom setting when other member + * functions are used. Setting to_global to true means using the global setting, to false + * false for the custom setting. + * + * @param to_global Whether to use the global or custom setting. + */ + void SetGlobal(bool to_global) { + use_global = to_global; + } + + /** + * Returns whether this setting is using the global setting or not. + * + * @returns The global state + */ + [[nodiscard]] bool UsingGlobal() const { + return use_global; + } + + /** + * Returns either the global or custom setting depending on the values of this setting's global + * state or if the global value was specifically requested. + * + * @param need_global Request global value regardless of setting's state; defaults to false + * + * @returns The required value of the setting + */ + [[nodiscard]] const Type& GetValue(bool need_global = false) const { + if (use_global || need_global) { + return this->global; + } + return custom; + } + + /** + * Sets the current setting value depending on the global state. + * + * @param value The new value + */ + void SetValue(const Type& value) { + Type temp{value}; + if (use_global) { + std::swap(this->global, temp); + } else { + std::swap(custom, temp); + } + } + + /** + * Assigns the current setting value depending on the global state. + * + * @param value The new value + * + * @returns A reference to the current setting value + */ + const Type& operator=(const Type& value) { + Type temp{value}; + if (use_global) { + std::swap(this->global, temp); + return this->global; + } + std::swap(custom, temp); + return custom; + } + + /** + * Returns the current setting value depending on the global state. + * + * @returns A reference to the current setting value + */ + explicit operator const Type&() const { + if (use_global) { + return this->global; + } + return custom; + } + +private: + bool use_global{true}; ///< The setting's global state + Type custom{}; ///< The custom value of the setting +}; + +/** + * The InputSetting class allows for getting a reference to either the global or custom members. * This is required as we cannot easily modify the values of user-defined types within containers * using the SetValue() member function found in the Setting class. The primary purpose of this - * class is to store an array of 10 PlayerInput structs for both the global and local (per-game) - * setting and allows for easily accessing and modifying both settings. + * class is to store an array of 10 PlayerInput structs for both the global and custom setting and + * allows for easily accessing and modifying both settings. */ template class InputSetting final { public: InputSetting() = default; - explicit InputSetting(Type val) : global{val} {} + explicit InputSetting(Type val) : BasicSetting(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 +275,155 @@ struct TouchFromButtonMap { struct Values { // Audio - std::string audio_device_id; - std::string sink_id; - bool audio_muted; - Setting enable_audio_stretching; - Setting volume; + BasicSetting audio_device_id{"auto", "output_device"}; + BasicSetting sink_id{"auto", "output_engine"}; + BasicSetting audio_muted{false, "audio_muted"}; + Setting enable_audio_stretching{true, "enable_audio_stretching"}; + Setting volume{1.0f, "volume"}; // Core - Setting use_multi_core; + Setting use_multi_core{true, "use_multi_core"}; // Cpu - Setting cpu_accuracy; + Setting cpu_accuracy{CPUAccuracy::Accurate, "cpu_accuracy"}; - bool cpuopt_page_tables; - bool cpuopt_block_linking; - bool cpuopt_return_stack_buffer; - bool cpuopt_fast_dispatcher; - bool cpuopt_context_elimination; - bool cpuopt_const_prop; - bool cpuopt_misc_ir; - bool cpuopt_reduce_misalign_checks; - bool cpuopt_fastmem; + BasicSetting cpuopt_page_tables{true, "cpuopt_page_tables"}; + BasicSetting cpuopt_block_linking{true, "cpuopt_block_linking"}; + BasicSetting cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"}; + BasicSetting cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"}; + BasicSetting cpuopt_context_elimination{true, "cpuopt_context_elimination"}; + BasicSetting cpuopt_const_prop{true, "cpuopt_const_prop"}; + BasicSetting cpuopt_misc_ir{true, "cpuopt_misc_ir"}; + BasicSetting cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"}; + BasicSetting cpuopt_fastmem{true, "cpuopt_fastmem"}; - Setting cpuopt_unsafe_unfuse_fma; - Setting cpuopt_unsafe_reduce_fp_error; - Setting cpuopt_unsafe_ignore_standard_fpcr; - Setting cpuopt_unsafe_inaccurate_nan; - Setting cpuopt_unsafe_fastmem_check; + Setting cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"}; + Setting cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"}; + Setting cpuopt_unsafe_ignore_standard_fpcr{true, "cpuopt_unsafe_ignore_standard_fpcr"}; + Setting cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"}; + Setting cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"}; // Renderer - Setting renderer_backend; - bool renderer_debug; - Setting vulkan_device; + Setting renderer_backend{RendererBackend::OpenGL, "backend"}; + BasicSetting renderer_debug{false, "debug"}; + Setting vulkan_device{0, "vulkan_device"}; - Setting resolution_factor{1}; - Setting fullscreen_mode; - Setting aspect_ratio; - Setting max_anisotropy; - Setting use_frame_limit; - Setting frame_limit; - Setting use_disk_shader_cache; - Setting gpu_accuracy; - Setting use_asynchronous_gpu_emulation; - Setting use_nvdec_emulation; - Setting accelerate_astc; - Setting use_vsync; - Setting disable_fps_limit; - Setting use_assembly_shaders; - Setting use_asynchronous_shaders; - Setting use_fast_gpu_time; - Setting use_caches_gc; + Setting 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 fullscreen_mode{ +#ifdef _WIN32 + 0, +#else + 1, +#endif + "fullscreen_mode"}; + Setting aspect_ratio{0, "aspect_ratio"}; + Setting max_anisotropy{0, "max_anisotropy"}; + Setting use_frame_limit{true, "use_frame_limit"}; + Setting frame_limit{100, "frame_limit"}; + Setting use_disk_shader_cache{true, "use_disk_shader_cache"}; + Setting gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"}; + Setting use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; + Setting use_nvdec_emulation{true, "use_nvdec_emulation"}; + Setting accelerate_astc{true, "accelerate_astc"}; + Setting use_vsync{true, "use_vsync"}; + Setting disable_fps_limit{false, "disable_fps_limit"}; + Setting use_assembly_shaders{false, "use_assembly_shaders"}; + Setting use_asynchronous_shaders{false, "use_asynchronous_shaders"}; + Setting use_fast_gpu_time{true, "use_fast_gpu_time"}; + Setting use_caches_gc{false, "use_caches_gc"}; - Setting bg_red; - Setting bg_green; - Setting bg_blue; + Setting bg_red{0.0f, "bg_red"}; + Setting bg_green{0.0f, "bg_green"}; + Setting bg_blue{0.0f, "bg_blue"}; // System - Setting> rng_seed; + Setting> rng_seed{std::optional(), "rng_seed"}; // Measured in seconds since epoch std::optional 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 language_index; - Setting region_index; - Setting time_zone_index; - Setting sound_index; + BasicSetting current_user{0, "current_user"}; + Setting language_index{1, "language_index"}; + Setting region_index{1, "region_index"}; + Setting time_zone_index{0, "time_zone_index"}; + Setting sound_index{1, "sound_index"}; // Controls InputSetting> players; - Setting use_docked_mode; + Setting use_docked_mode{true, "use_docked_mode"}; - Setting vibration_enabled; - Setting enable_accurate_vibrations; + Setting vibration_enabled{true, "vibration_enabled"}; + Setting enable_accurate_vibrations{false, "enable_accurate_vibrations"}; - Setting motion_enabled; - std::string motion_device; - std::string udp_input_servers; + Setting motion_enabled{true, "motion_enabled"}; + BasicSetting motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01", + "motion_device"}; + BasicSetting udp_input_servers{InputCommon::CemuhookUDP::DEFAULT_SRV, + "udp_input_servers"}; - bool mouse_panning; - float mouse_panning_sensitivity; - bool mouse_enabled; + BasicSetting mouse_panning{false, "mouse_panning"}; + BasicSetting mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"}; + BasicSetting mouse_enabled{false, "mouse_enabled"}; std::string mouse_device; MouseButtonsRaw mouse_buttons; - bool emulate_analog_keyboard; - bool keyboard_enabled; + BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; + BasicSetting keyboard_enabled{false, "keyboard_enabled"}; KeyboardKeysRaw keyboard_keys; KeyboardModsRaw keyboard_mods; - bool debug_pad_enabled; + BasicSetting 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 use_touch_from_button{false, "use_touch_from_button"}; + BasicSetting touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", + "touch_device"}; + BasicSetting touch_from_button_map_index{0, "touch_from_button_map"}; std::vector 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 use_virtual_sd{true, "use_virtual_sd"}; + BasicSetting gamecard_inserted{false, "gamecard_inserted"}; + BasicSetting gamecard_current_game{false, "gamecard_current_game"}; + BasicSetting 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 use_gdbstub{false, "use_gdbstub"}; + BasicSetting gdbstub_port{0, "gdbstub_port"}; + BasicSetting program_args{std::string(), "program_args"}; + BasicSetting dump_exefs{false, "dump_exefs"}; + BasicSetting dump_nso{false, "dump_nso"}; + BasicSetting enable_fs_access_log{false, "enable_fs_access_log"}; + BasicSetting reporting_services{false, "reporting_services"}; + BasicSetting quest_flag{false, "quest_flag"}; + BasicSetting disable_macro_jit{false, "disable_macro_jit"}; + BasicSetting extended_logging{false, "extended_logging"}; + BasicSetting use_debug_asserts{false, "use_debug_asserts"}; + BasicSetting use_auto_stub{false, "use_auto_stub"}; // Miscellaneous - std::string log_filter; - bool use_dev_keys; + BasicSetting log_filter{"*:Info", "log_filter"}; + BasicSetting use_dev_keys{false, "use_dev_keys"}; // Services - std::string bcat_backend; - bool bcat_boxcat_local; + BasicSetting bcat_backend{"none", "bcat_backend"}; + BasicSetting 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 enable_telemetry{true, "enable_telemetry"}; + BasicSetting web_api_url{"https://api.yuzu-emu.org", "web_api_url"}; + BasicSetting yuzu_username{std::string(), "yuzu_username"}; + BasicSetting yuzu_token{std::string(), "yuzu_token"}; // Add-Ons std::map> disabled_addons; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 83b5b7676..80cfdf55b 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -517,6 +517,8 @@ add_library(core STATIC hle/service/psc/psc.h hle/service/ptm/psm.cpp hle/service/ptm/psm.h + hle/service/kernel_helpers.cpp + hle/service/kernel_helpers.h hle/service/service.cpp hle/service/service.h hle/service/set/set.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index e6f1aa0e7..fc6ec9512 100755 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -263,9 +263,9 @@ struct System::Impl { if (Settings::values.gamecard_inserted) { if (Settings::values.gamecard_current_game) { fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath)); - } else if (!Settings::values.gamecard_path.empty()) { - fs_controller.SetGameCard( - GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path)); + } else if (!Settings::values.gamecard_path.GetValue().empty()) { + fs_controller.SetGameCard(GetGameFileFromPath( + virtual_filesystem, static_cast(Settings::values.gamecard_path))); } } diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp index 8d960d1ca..4c58c310f 100755 --- 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)> 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/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 28ed6265a..ca68fc325 100755 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -58,6 +58,9 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co void SessionRequestHandler::ClientConnected(KServerSession* session) { session->ClientConnected(shared_from_this()); + + // Ensure our server session is tracked globally. + kernel.RegisterServerSession(session); } void SessionRequestHandler::ClientDisconnected(KServerSession* session) { diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp index dbe237f09..c99a9ebb7 100755 --- a/src/core/hle/kernel/k_auto_object.cpp +++ b/src/core/hle/kernel/k_auto_object.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/kernel.h" namespace Kernel { @@ -11,4 +12,12 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) { return obj; } +void KAutoObject::RegisterWithKernel() { + kernel.RegisterKernelObject(this); +} + +void KAutoObject::UnregisterWithKernel() { + kernel.UnregisterKernelObject(this); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 88a052f65..e4fcdbc67 100755 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -85,8 +85,12 @@ private: KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); public: - explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {} - virtual ~KAutoObject() = default; + explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) { + RegisterWithKernel(); + } + virtual ~KAutoObject() { + UnregisterWithKernel(); + } static KAutoObject* Create(KAutoObject* ptr); @@ -166,6 +170,10 @@ public: } } +private: + void RegisterWithKernel(); + void UnregisterWithKernel(); + protected: KernelCore& kernel; std::string name; diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index d1bd98051..8ead1a769 100755 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "common/settings.h" #include "core/core.h" #include "core/device_memory.h" @@ -43,6 +44,8 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); KThread* thread = KThread::Create(system.Kernel()); + SCOPE_EXIT({ thread->Close(); }); + ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, owner_process.GetIdealCoreId(), &owner_process) .IsSuccess()); @@ -162,7 +165,7 @@ void KProcess::DecrementThreadCount() { ASSERT(num_threads > 0); if (const auto count = --num_threads; count == 0) { - UNIMPLEMENTED_MSG("Process termination is not implemented!"); + LOG_WARNING(Kernel, "Process termination is not fully implemented."); } } @@ -406,6 +409,9 @@ void KProcess::Finalize() { resource_limit->Close(); } + // Finalize the handle table and close any open handles. + handle_table.Finalize(); + // Perform inherited finalization. KAutoObjectWithSlabHeapAndContainer::Finalize(); } diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 5c3c13ce6..b9f24475c 100755 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -28,7 +28,10 @@ namespace Kernel { KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} -KServerSession::~KServerSession() {} +KServerSession::~KServerSession() { + // Ensure that the global list tracking server sessions does not hold on to a reference. + kernel.UnregisterServerSession(this); +} void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, std::shared_ptr manager_) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 64bd0c494..92fbc5532 100755 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -61,6 +61,7 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { global_scheduler_context = std::make_unique(kernel); global_handle_table = std::make_unique(kernel); + global_handle_table->Initialize(KHandleTable::MaxTableSize); is_phantom_mode_for_singlecore = false; @@ -90,9 +91,39 @@ struct KernelCore::Impl { } void Shutdown() { + // Shutdown all processes. + if (current_process) { + current_process->Finalize(); + current_process->Close(); + current_process = nullptr; + } process_list.clear(); - // Ensures all service threads gracefully shutdown + // Close all open server ports. + std::unordered_set server_ports_; + { + std::lock_guard lk(server_ports_lock); + server_ports_ = server_ports; + server_ports.clear(); + } + for (auto* server_port : server_ports_) { + server_port->Close(); + } + // Close all open server sessions. + std::unordered_set server_sessions_; + { + std::lock_guard lk(server_sessions_lock); + server_sessions_ = server_sessions; + server_sessions.clear(); + } + for (auto* server_session : server_sessions_) { + server_session->Close(); + } + + // Ensure that the object list container is finalized and properly shutdown. + object_list_container.Finalize(); + + // Ensures all service threads gracefully shutdown. service_threads.clear(); next_object_id = 0; @@ -111,11 +142,7 @@ struct KernelCore::Impl { cores.clear(); - if (current_process) { - current_process->Close(); - current_process = nullptr; - } - + global_handle_table->Finalize(); global_handle_table.reset(); preemption_event = nullptr; @@ -142,6 +169,16 @@ struct KernelCore::Impl { // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others next_host_thread_id = Core::Hardware::NUM_CPU_CORES; + + // Track kernel objects that were not freed on shutdown + { + std::lock_guard lk(registered_objects_lock); + if (registered_objects.size()) { + LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!", + registered_objects.size()); + registered_objects.clear(); + } + } } void InitializePhysicalCores() { @@ -630,6 +667,21 @@ struct KernelCore::Impl { user_slab_heap_size); } + KClientPort* CreateNamedServicePort(std::string name) { + auto search = service_interface_factory.find(name); + if (search == service_interface_factory.end()) { + UNIMPLEMENTED(); + return {}; + } + + KClientPort* port = &search->second(system.ServiceManager(), system); + { + std::lock_guard lk(server_ports_lock); + server_ports.insert(&port->GetParent()->GetServerPort()); + } + return port; + } + std::atomic next_object_id{0}; std::atomic next_kernel_process_id{KProcess::InitialKIPIDMin}; std::atomic next_user_process_id{KProcess::ProcessIDMin}; @@ -656,6 +708,12 @@ struct KernelCore::Impl { /// the ConnectToPort SVC. std::unordered_map service_interface_factory; NamedPortTable named_ports; + std::unordered_set server_ports; + std::unordered_set server_sessions; + std::unordered_set registered_objects; + std::mutex server_ports_lock; + std::mutex server_sessions_lock; + std::mutex registered_objects_lock; std::unique_ptr exclusive_monitor; std::vector cores; @@ -844,12 +902,27 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory& } KClientPort* KernelCore::CreateNamedServicePort(std::string name) { - auto search = impl->service_interface_factory.find(name); - if (search == impl->service_interface_factory.end()) { - UNIMPLEMENTED(); - return {}; - } - return &search->second(impl->system.ServiceManager(), impl->system); + return impl->CreateNamedServicePort(std::move(name)); +} + +void KernelCore::RegisterServerSession(KServerSession* server_session) { + std::lock_guard lk(impl->server_sessions_lock); + impl->server_sessions.insert(server_session); +} + +void KernelCore::UnregisterServerSession(KServerSession* server_session) { + std::lock_guard lk(impl->server_sessions_lock); + impl->server_sessions.erase(server_session); +} + +void KernelCore::RegisterKernelObject(KAutoObject* object) { + std::lock_guard lk(impl->registered_objects_lock); + impl->registered_objects.insert(object); +} + +void KernelCore::UnregisterKernelObject(KAutoObject* object) { + std::lock_guard lk(impl->registered_objects_lock); + impl->registered_objects.erase(object); } bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2d01e1ae0..3a6db0b1c 100755 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -45,6 +45,7 @@ class KPort; class KProcess; class KResourceLimit; class KScheduler; +class KServerSession; class KSession; class KSharedMemory; class KThread; @@ -185,6 +186,22 @@ public: /// Opens a port to a service previously registered with RegisterNamedService. KClientPort* CreateNamedServicePort(std::string name); + /// Registers a server session with the gobal emulation state, to be freed on shutdown. This is + /// necessary because we do not emulate processes for HLE sessions. + void RegisterServerSession(KServerSession* server_session); + + /// Unregisters a server session previously registered with RegisterServerSession when it was + /// destroyed during the current emulation session. + void UnregisterServerSession(KServerSession* server_session); + + /// Registers all kernel objects with the global emulation state, this is purely for tracking + /// leaks after emulation has been shutdown. + void RegisterKernelObject(KAutoObject* object); + + /// Unregisters a kernel object previously registered with RegisterKernelObject when it was + /// destroyed during the current emulation session. + void UnregisterKernelObject(KAutoObject* object); + /// Determines whether or not the given port is a valid named port. bool IsValidNamedPort(NamedPortTable::const_iterator port) const; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8339e11a0..e1e556370 100755 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -298,6 +298,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po // Create a session. KClientSession* session{}; R_TRY(port->CreateSession(std::addressof(session))); + port->Close(); // Register the session in the table, close the extra reference. handle_table.Register(*out, session); diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index f72d5d561..24a1c9157 100755 --- 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(Settings::values.current_user, 0, MAX_USERS - 1); + auto current = + std::clamp(static_cast(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 100755 --- 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(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 100755 --- 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 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(system.GetAppletManager(), std::move(getter)); } #endif diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 1eb02aee2..dcbb13660 100755 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -18,6 +18,7 @@ #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/kernel_helpers.h" namespace Service::HID { constexpr s32 HID_JOYSTICK_MAX = 0x7fff; @@ -147,7 +148,9 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { device_handle.device_index < DeviceIndex::MaxDeviceIndex; } -Controller_NPad::Controller_NPad(Core::System& system_) : ControllerBase{system_} { +Controller_NPad::Controller_NPad(Core::System& system_, + KernelHelpers::ServiceContext& service_context_) + : ControllerBase{system_}, service_context{service_context_} { latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); } @@ -253,8 +256,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { void Controller_NPad::OnInit() { auto& kernel = system.Kernel(); for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - styleset_changed_events[i] = Kernel::KEvent::Create(kernel); - styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i)); + styleset_changed_events[i] = + service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); } if (!IsControllerActivated()) { @@ -344,8 +347,7 @@ void Controller_NPad::OnRelease() { } for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { - styleset_changed_events[i]->Close(); - styleset_changed_events[i] = nullptr; + service_context.CloseEvent(styleset_changed_events[i]); } } diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 1409d82a2..4fcc6f93a 100755 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -20,6 +20,10 @@ class KEvent; class KReadableEvent; } // namespace Kernel +namespace Service::KernelHelpers { +class ServiceContext; +} + namespace Service::HID { constexpr u32 NPAD_HANDHELD = 32; @@ -27,7 +31,8 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? class Controller_NPad final : public ControllerBase { public: - explicit Controller_NPad(Core::System& system_); + explicit Controller_NPad(Core::System& system_, + KernelHelpers::ServiceContext& service_context_); ~Controller_NPad() override; // Called when the controller is initialized @@ -566,6 +571,7 @@ private: std::array, Settings::NativeMotion::NUM_MOTIONS_HID>, 10>; + KernelHelpers::ServiceContext& service_context; std::mutex mutex; ButtonArray buttons; StickArray sticks; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d68b023d0..b8b80570d 100755 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -46,8 +46,9 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; -IAppletResource::IAppletResource(Core::System& system_) - : ServiceFramework{system_, "IAppletResource"} { +IAppletResource::IAppletResource(Core::System& system_, + KernelHelpers::ServiceContext& service_context_) + : ServiceFramework{system_, "IAppletResource"}, service_context{service_context_} { static const FunctionInfo functions[] = { {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, }; @@ -63,7 +64,7 @@ IAppletResource::IAppletResource(Core::System& system_) MakeController(HidController::CaptureButton); MakeController(HidController::InputDetector); MakeController(HidController::UniquePad); - MakeController(HidController::NPad); + MakeControllerWithServiceContext(HidController::NPad); MakeController(HidController::Gesture); MakeController(HidController::ConsoleSixAxisSensor); @@ -191,13 +192,14 @@ private: std::shared_ptr Hid::GetAppletResource() { if (applet_resource == nullptr) { - applet_resource = std::make_shared(system); + applet_resource = std::make_shared(system, service_context); } return applet_resource; } -Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} { +Hid::Hid(Core::System& system_) + : ServiceFramework{system_, "hid"}, service_context{system_, service_name} { // clang-format off static const FunctionInfo functions[] = { {0, &Hid::CreateAppletResource, "CreateAppletResource"}, @@ -347,7 +349,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); if (applet_resource == nullptr) { - applet_resource = std::make_shared(system); + applet_resource = std::make_shared(system, service_context); } IPC::ResponseBuilder rb{ctx, 2, 0, 1}; diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 83fc2ea1d..9c5c7f252 100755 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -7,6 +7,7 @@ #include #include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" namespace Core::Timing { @@ -39,7 +40,8 @@ enum class HidController : std::size_t { class IAppletResource final : public ServiceFramework { public: - explicit IAppletResource(Core::System& system_); + explicit IAppletResource(Core::System& system_, + KernelHelpers::ServiceContext& service_context_); ~IAppletResource() override; void ActivateController(HidController controller); @@ -60,11 +62,18 @@ private: void MakeController(HidController controller) { controllers[static_cast(controller)] = std::make_unique(system); } + template + void MakeControllerWithServiceContext(HidController controller) { + controllers[static_cast(controller)] = + std::make_unique(system, service_context); + } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); + KernelHelpers::ServiceContext& service_context; + std::shared_ptr pad_update_event; std::shared_ptr motion_update_event; @@ -176,6 +185,8 @@ private: static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); std::shared_ptr applet_resource; + + KernelHelpers::ServiceContext service_context; }; /// Reload input devices. Used when input configuration changed diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp new file mode 100755 index 000000000..895294c9f --- /dev/null +++ b/src/core/hle/service/kernel_helpers.cpp @@ -0,0 +1,64 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/service/kernel_helpers.h" + +namespace Service::KernelHelpers { + +ServiceContext::ServiceContext(Core::System& system_, std::string name_) + : kernel(system_.Kernel()) { + process = Kernel::KProcess::Create(kernel); + ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_), + Kernel::KProcess::ProcessType::Userland) + .IsSuccess()); +} + +ServiceContext::~ServiceContext() { + process->Close(); + process = nullptr; +} + +Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) { + // Reserve a new event from the process resource limit + Kernel::KScopedResourceReservation event_reservation(process, + Kernel::LimitableResource::Events); + if (!event_reservation.Succeeded()) { + LOG_CRITICAL(Service, "Resource limit reached!"); + return {}; + } + + // Create a new event. + auto* event = Kernel::KEvent::Create(kernel); + if (!event) { + LOG_CRITICAL(Service, "Unable to create event!"); + return {}; + } + + // Initialize the event. + event->Initialize(std::move(name)); + + // Commit the thread reservation. + event_reservation.Commit(); + + // Register the event. + Kernel::KEvent::Register(kernel, event); + + return event; +} + +void ServiceContext::CloseEvent(Kernel::KEvent* event) { + event->GetReadableEvent().Close(); + event->GetWritableEvent().Close(); +} + +} // namespace Service::KernelHelpers diff --git a/src/core/hle/service/kernel_helpers.h b/src/core/hle/service/kernel_helpers.h new file mode 100755 index 000000000..4f3e95f67 --- /dev/null +++ b/src/core/hle/service/kernel_helpers.h @@ -0,0 +1,35 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace Core { +class System; +} + +namespace Kernel { +class KernelCore; +class KEvent; +class KProcess; +} // namespace Kernel + +namespace Service::KernelHelpers { + +class ServiceContext { +public: + ServiceContext(Core::System& system_, std::string name_); + ~ServiceContext(); + + Kernel::KEvent* CreateEvent(std::string&& name); + + void CloseEvent(Kernel::KEvent* event); + +private: + Kernel::KernelCore& kernel; + Kernel::KProcess* process{}; +}; + +} // namespace Service::KernelHelpers diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index f03b2666a..e742db48f 100755 --- 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(0); } else { rb.Push(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(0); } else { rb.Push(1); diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 74796dce1..8d3841cf7 100755 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -39,11 +39,12 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger nvflinger.SetNVDrvInstance(module_); } -Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { +Module::Module(Core::System& system) + : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} { auto& kernel = system.Kernel(); for (u32 i = 0; i < MaxNvEvents; i++) { - events_interface.events[i].event = Kernel::KEvent::Create(kernel); - events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i)); + events_interface.events[i].event = + service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i)); events_interface.status[i] = EventState::Free; events_interface.registered[i] = false; } @@ -65,8 +66,7 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { Module::~Module() { for (u32 i = 0; i < MaxNvEvents; i++) { - events_interface.events[i].event->Close(); - events_interface.events[i].event = nullptr; + service_context.CloseEvent(events_interface.events[i].event); } } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index a43ceb7ae..e2a1dde5b 100755 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -9,6 +9,7 @@ #include #include "common/common_types.h" +#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/hle/service/service.h" @@ -154,6 +155,8 @@ private: std::unordered_map> devices; EventInterface events_interface; + + KernelHelpers::ServiceContext service_context; }; /// Registers all NVDRV services with the specified service manager. diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 663b83cd3..98360e7c3 100755 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -104,23 +104,22 @@ ServiceFrameworkBase::~ServiceFrameworkBase() { void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { const auto guard = LockService(); - ASSERT(!port_installed); + ASSERT(!service_registered); - auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); - port->SetSessionHandler(shared_from_this()); - port_installed = true; + service_manager.RegisterService(service_name, max_sessions, shared_from_this()); + service_registered = true; } Kernel::KClientPort& ServiceFrameworkBase::CreatePort() { const auto guard = LockService(); - ASSERT(!port_installed); + ASSERT(!service_registered); auto* port = Kernel::KPort::Create(kernel); port->Initialize(max_sessions, false, service_name); port->GetServerPort().SetSessionHandler(shared_from_this()); - port_installed = true; + service_registered = true; return port->GetClientPort(); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index e078ac176..c9d6b879d 100755 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -96,6 +96,9 @@ protected: /// System context that the service operates under. Core::System& system; + /// Identifier string used to connect to the service. + std::string service_name; + private: template friend class ServiceFramework; @@ -117,14 +120,12 @@ private: void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n); void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); - /// Identifier string used to connect to the service. - std::string service_name; /// Maximum number of concurrent sessions that this service can handle. u32 max_sessions; /// Flag to store if a port was already create/installed to detect multiple install attempts, /// which is not supported. - bool port_installed = false; + bool service_registered = false; /// Function used to safely up-cast pointers to the derived class before invoking a handler. InvokerFn* handler_invoker; diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index ece2a74c6..522a604a5 100755 --- 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(Settings::values.quest_flag)); + rb.Push(static_cast(Settings::values.quest_flag.GetValue())); } void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index c7828c3bd..e94258ff3 100755 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -4,6 +4,7 @@ #include #include "common/assert.h" +#include "common/scope_exit.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_client_port.h" @@ -40,17 +41,13 @@ static ResultCode ValidateServiceName(const std::string& name) { } Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { - ASSERT(self.sm_interface.expired()); - - auto sm = std::make_shared(self, system); - self.sm_interface = sm; + self.sm_interface = std::make_shared(self, system); self.controller_interface = std::make_unique(system); - - return sm->CreatePort(); + return self.sm_interface->CreatePort(); } -ResultVal ServiceManager::RegisterService(std::string name, - u32 max_sessions) { +ResultCode ServiceManager::RegisterService(std::string name, u32 max_sessions, + Kernel::SessionRequestHandlerPtr handler) { CASCADE_CODE(ValidateServiceName(name)); @@ -59,12 +56,9 @@ ResultVal ServiceManager::RegisterService(std::string name return ERR_ALREADY_REGISTERED; } - auto* port = Kernel::KPort::Create(kernel); - port->Initialize(max_sessions, false, name); + registered_services.emplace(std::move(name), handler); - registered_services.emplace(std::move(name), port); - - return MakeResult(&port->GetServerPort()); + return ResultSuccess; } ResultCode ServiceManager::UnregisterService(const std::string& name) { @@ -76,14 +70,11 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) { return ERR_SERVICE_NOT_REGISTERED; } - iter->second->Close(); - registered_services.erase(iter); return ResultSuccess; } ResultVal ServiceManager::GetServicePort(const std::string& name) { - CASCADE_CODE(ValidateServiceName(name)); auto it = registered_services.find(name); if (it == registered_services.end()) { @@ -91,10 +82,13 @@ ResultVal ServiceManager::GetServicePort(const std::string& name return ERR_SERVICE_NOT_REGISTERED; } - return MakeResult(it->second); -} + auto* port = Kernel::KPort::Create(kernel); + port->Initialize(ServerSessionCountMax, false, name); + auto handler = it->second; + port->GetServerPort().SetSessionHandler(std::move(handler)); -SM::~SM() = default; + return MakeResult(port); +} /** * SM::Initialize service function @@ -156,11 +150,15 @@ ResultVal SM::GetServiceImpl(Kernel::HLERequestContext& LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); return port_result.Code(); } - auto& port = port_result.Unwrap()->GetClientPort(); + auto& port = port_result.Unwrap(); + SCOPE_EXIT({ port->GetClientPort().Close(); }); + + server_ports.emplace_back(&port->GetServerPort()); // Create a new session. Kernel::KClientSession* session{}; - if (const auto result = port.CreateSession(std::addressof(session)); result.IsError()) { + if (const auto result = port->GetClientPort().CreateSession(std::addressof(session)); + result.IsError()) { LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); return result; } @@ -180,20 +178,21 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, max_session_count, is_light); - auto handle = service_manager.RegisterService(name, max_session_count); - if (handle.Failed()) { - LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", - handle.Code().raw); + if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr); + result.IsError()) { + LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(handle.Code()); + rb.Push(result); return; } - IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; - rb.Push(handle.Code()); + auto* port = Kernel::KPort::Create(kernel); + port->Initialize(ServerSessionCountMax, is_light, name); + SCOPE_EXIT({ port->GetClientPort().Close(); }); - auto server_port = handle.Unwrap(); - rb.PushMoveObjects(server_port); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(ResultSuccess); + rb.PushMoveObjects(port->GetServerPort()); } void SM::UnregisterService(Kernel::HLERequestContext& ctx) { @@ -225,4 +224,10 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_) }); } +SM::~SM() { + for (auto& server_port : server_ports) { + server_port->Close(); + } +} + } // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index ea37f11d4..068c78588 100755 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -49,6 +49,7 @@ private: ServiceManager& service_manager; bool is_initialized{}; Kernel::KernelCore& kernel; + std::vector server_ports; }; class ServiceManager { @@ -58,7 +59,8 @@ public: explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); - ResultVal RegisterService(std::string name, u32 max_sessions); + ResultCode RegisterService(std::string name, u32 max_sessions, + Kernel::SessionRequestHandlerPtr handler); ResultCode UnregisterService(const std::string& name); ResultVal GetServicePort(const std::string& name); @@ -69,21 +71,17 @@ public: LOG_DEBUG(Service, "Can't find service: {}", service_name); return nullptr; } - auto* port = service->second; - if (port == nullptr) { - return nullptr; - } - return std::static_pointer_cast(port->GetServerPort().GetSessionRequestHandler()); + return std::static_pointer_cast(service->second); } void InvokeControlRequest(Kernel::HLERequestContext& context); private: - std::weak_ptr sm_interface; + std::shared_ptr sm_interface; std::unique_ptr controller_interface; /// Map of registered services, retrieved using GetServicePort. - std::unordered_map registered_services; + std::unordered_map registered_services; /// Kernel context Kernel::KernelCore& kernel; diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 618555202..951ea966e 100755 --- 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& 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(arg_data.size()), {}}; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 0f5cfda68..4a2224c02 100755 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -104,8 +104,8 @@ std::optional 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 100755 --- 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 100755 --- 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( - 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(); #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( - 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..4861a131e 100755 --- 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(mouse_input->GetMouseState(button).axis.at(axis)); - return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range); + return axis_value * Settings::values.mouse_panning_sensitivity.GetValue() / + (100.0f * range); } std::pair 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 100755 --- 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(Settings::values.touch_from_button_map_index); + static_cast(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 100755 --- 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(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 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(touch_param.Get("min_x", 100)); const u16 min_y = static_cast(touch_param.Get("min_y", 50)); const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp index a3fda1094..8b86ad050 100755 --- a/src/video_core/cdma_pusher.cpp +++ b/src/video_core/cdma_pusher.cpp @@ -103,8 +103,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) { case ThiMethod::SetMethod1: LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}", static_cast(nvdec_thi_state.method_0)); - nvdec_processor->ProcessMethod(static_cast(nvdec_thi_state.method_0), - data); + nvdec_processor->ProcessMethod(nvdec_thi_state.method_0, data); break; default: break; diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index d02dc6260..1b4bbc8ac 100755 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -23,8 +23,8 @@ void AVFrameDeleter(AVFrame* ptr) { av_free(ptr); } -Codec::Codec(GPU& gpu_) - : gpu(gpu_), h264_decoder(std::make_unique(gpu)), +Codec::Codec(GPU& gpu_, const NvdecCommon::NvdecRegisters& regs) + : gpu(gpu_), state{regs}, h264_decoder(std::make_unique(gpu)), vp9_decoder(std::make_unique(gpu)) {} Codec::~Codec() { @@ -43,46 +43,48 @@ Codec::~Codec() { avcodec_close(av_codec_ctx); } -void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) { - if (current_codec != codec) { - LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", static_cast(codec)); - current_codec = codec; +void Codec::Initialize() { + AVCodecID codec{AV_CODEC_ID_NONE}; + switch (current_codec) { + case NvdecCommon::VideoCodec::H264: + codec = AV_CODEC_ID_H264; + break; + case NvdecCommon::VideoCodec::Vp9: + codec = AV_CODEC_ID_VP9; + break; + default: + return; } + av_codec = avcodec_find_decoder(codec); + av_codec_ctx = avcodec_alloc_context3(av_codec); + av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); + + // TODO(ameerj): libavcodec gpu hw acceleration + + const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr); + if (av_error < 0) { + LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed."); + avcodec_close(av_codec_ctx); + return; + } + initialized = true; + return; } -void Codec::StateWrite(u32 offset, u64 arguments) { - u8* const state_offset = reinterpret_cast(&state) + offset * sizeof(u64); - std::memcpy(state_offset, &arguments, sizeof(u64)); +void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) { + if (current_codec != codec) { + current_codec = codec; + LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", GetCurrentCodecName()); + } } void Codec::Decode() { - bool is_first_frame = false; + const bool is_first_frame = !initialized; if (!initialized) { - if (current_codec == NvdecCommon::VideoCodec::H264) { - av_codec = avcodec_find_decoder(AV_CODEC_ID_H264); - } else if (current_codec == NvdecCommon::VideoCodec::Vp9) { - av_codec = avcodec_find_decoder(AV_CODEC_ID_VP9); - } else { - LOG_ERROR(Service_NVDRV, "Unknown video codec {}", current_codec); - return; - } - - av_codec_ctx = avcodec_alloc_context3(av_codec); - av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); - - // TODO(ameerj): libavcodec gpu hw acceleration - - const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr); - if (av_error < 0) { - LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed."); - avcodec_close(av_codec_ctx); - return; - } - initialized = true; - is_first_frame = true; + Initialize(); } - bool vp9_hidden_frame = false; + bool vp9_hidden_frame = false; AVPacket packet{}; av_init_packet(&packet); std::vector frame_data; @@ -95,7 +97,7 @@ void Codec::Decode() { } packet.data = frame_data.data(); - packet.size = static_cast(frame_data.size()); + packet.size = static_cast(frame_data.size()); avcodec_send_packet(av_codec_ctx, &packet); @@ -127,4 +129,21 @@ NvdecCommon::VideoCodec Codec::GetCurrentCodec() const { return current_codec; } +std::string_view Codec::GetCurrentCodecName() const { + switch (current_codec) { + case NvdecCommon::VideoCodec::None: + return "None"; + case NvdecCommon::VideoCodec::H264: + return "H264"; + case NvdecCommon::VideoCodec::Vp8: + return "VP8"; + case NvdecCommon::VideoCodec::H265: + return "H265"; + case NvdecCommon::VideoCodec::Vp9: + return "VP9"; + default: + return "Unknown"; + } +}; + } // namespace Tegra diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h index 3e135a2a6..f2aef1699 100755 --- a/src/video_core/command_classes/codecs/codec.h +++ b/src/video_core/command_classes/codecs/codec.h @@ -42,15 +42,15 @@ class VP9; class Codec { public: - explicit Codec(GPU& gpu); + explicit Codec(GPU& gpu, const NvdecCommon::NvdecRegisters& regs); ~Codec(); + /// Initialize the codec, returning success or failure + void Initialize(); + /// Sets NVDEC video stream codec void SetTargetCodec(NvdecCommon::VideoCodec codec); - /// Populate NvdecRegisters state with argument value at the provided offset - void StateWrite(u32 offset, u64 arguments); - /// Call decoders to construct headers, decode AVFrame with ffmpeg void Decode(); @@ -59,6 +59,8 @@ public: /// Returns the value of current_codec [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const; + /// Return name of the current codec + [[nodiscard]] std::string_view GetCurrentCodecName() const; private: bool initialized{}; @@ -68,10 +70,10 @@ private: AVCodecContext* av_codec_ctx{nullptr}; GPU& gpu; + const NvdecCommon::NvdecRegisters& state; std::unique_ptr h264_decoder; std::unique_ptr vp9_decoder; - NvdecCommon::NvdecRegisters state{}; std::queue av_frames{}; }; diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp index fea6aed98..5fb6d45ee 100755 --- a/src/video_core/command_classes/codecs/h264.cpp +++ b/src/video_core/command_classes/codecs/h264.cpp @@ -45,135 +45,130 @@ H264::~H264() = default; const std::vector& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state, bool is_first_frame) { - H264DecoderContext context{}; + H264DecoderContext context; gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext)); - const s32 frame_number = static_cast((context.h264_parameter_set.flags >> 46) & 0x1ffff); + const s64 frame_number = context.h264_parameter_set.frame_number.Value(); if (!is_first_frame && frame_number != 0) { - frame.resize(context.frame_data_size); - + frame.resize(context.stream_len); gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size()); - } else { - /// Encode header - H264BitWriter writer{}; - writer.WriteU(1, 24); - writer.WriteU(0, 1); - writer.WriteU(3, 2); - writer.WriteU(7, 5); - writer.WriteU(100, 8); - writer.WriteU(0, 8); - writer.WriteU(31, 8); - writer.WriteUe(0); - const auto chroma_format_idc = - static_cast((context.h264_parameter_set.flags >> 12) & 3); - writer.WriteUe(chroma_format_idc); - if (chroma_format_idc == 3) { - writer.WriteBit(false); - } - - writer.WriteUe(0); - writer.WriteUe(0); - writer.WriteBit(false); // QpprimeYZeroTransformBypassFlag - writer.WriteBit(false); // Scaling matrix present flag - - const auto order_cnt_type = static_cast((context.h264_parameter_set.flags >> 14) & 3); - writer.WriteUe(static_cast((context.h264_parameter_set.flags >> 8) & 0xf)); - writer.WriteUe(order_cnt_type); - if (order_cnt_type == 0) { - writer.WriteUe(context.h264_parameter_set.log2_max_pic_order_cnt); - } else if (order_cnt_type == 1) { - writer.WriteBit(context.h264_parameter_set.delta_pic_order_always_zero_flag != 0); - - writer.WriteSe(0); - writer.WriteSe(0); - writer.WriteUe(0); - } - - const s32 pic_height = context.h264_parameter_set.pic_height_in_map_units / - (context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2); - - writer.WriteUe(16); - writer.WriteBit(false); - writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1); - writer.WriteUe(pic_height - 1); - writer.WriteBit(context.h264_parameter_set.frame_mbs_only_flag != 0); - - if (!context.h264_parameter_set.frame_mbs_only_flag) { - writer.WriteBit(((context.h264_parameter_set.flags >> 0) & 1) != 0); - } - - writer.WriteBit(((context.h264_parameter_set.flags >> 1) & 1) != 0); - writer.WriteBit(false); // Frame cropping flag - writer.WriteBit(false); // VUI parameter present flag - - writer.End(); - - // H264 PPS - writer.WriteU(1, 24); - writer.WriteU(0, 1); - writer.WriteU(3, 2); - writer.WriteU(8, 5); - - writer.WriteUe(0); - writer.WriteUe(0); - - writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0); - writer.WriteBit(false); - writer.WriteUe(0); - writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active); - writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active); - writer.WriteBit(((context.h264_parameter_set.flags >> 2) & 1) != 0); - writer.WriteU(static_cast((context.h264_parameter_set.flags >> 32) & 0x3), 2); - s32 pic_init_qp = static_cast((context.h264_parameter_set.flags >> 16) & 0x3f); - pic_init_qp = (pic_init_qp << 26) >> 26; - writer.WriteSe(pic_init_qp); - writer.WriteSe(0); - s32 chroma_qp_index_offset = - static_cast((context.h264_parameter_set.flags >> 22) & 0x1f); - chroma_qp_index_offset = (chroma_qp_index_offset << 27) >> 27; - - writer.WriteSe(chroma_qp_index_offset); - writer.WriteBit(context.h264_parameter_set.deblocking_filter_control_flag != 0); - writer.WriteBit(((context.h264_parameter_set.flags >> 3) & 1) != 0); - writer.WriteBit(context.h264_parameter_set.redundant_pic_count_flag != 0); - writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0); - - writer.WriteBit(true); - - for (s32 index = 0; index < 6; index++) { - writer.WriteBit(true); - const auto matrix_x4 = - std::vector(context.scaling_matrix_4.begin(), context.scaling_matrix_4.end()); - writer.WriteScalingList(matrix_x4, index * 16, 16); - } - - if (context.h264_parameter_set.transform_8x8_mode_flag) { - for (s32 index = 0; index < 2; index++) { - writer.WriteBit(true); - const auto matrix_x8 = std::vector(context.scaling_matrix_8.begin(), - context.scaling_matrix_8.end()); - - writer.WriteScalingList(matrix_x8, index * 64, 64); - } - } - - s32 chroma_qp_index_offset2 = - static_cast((context.h264_parameter_set.flags >> 27) & 0x1f); - chroma_qp_index_offset2 = (chroma_qp_index_offset2 << 27) >> 27; - - writer.WriteSe(chroma_qp_index_offset2); - - writer.End(); - - const auto& encoded_header = writer.GetByteArray(); - frame.resize(encoded_header.size() + context.frame_data_size); - std::memcpy(frame.data(), encoded_header.data(), encoded_header.size()); - - gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, - frame.data() + encoded_header.size(), - context.frame_data_size); + return frame; } + // Encode header + H264BitWriter writer{}; + writer.WriteU(1, 24); + writer.WriteU(0, 1); + writer.WriteU(3, 2); + writer.WriteU(7, 5); + writer.WriteU(100, 8); + writer.WriteU(0, 8); + writer.WriteU(31, 8); + writer.WriteUe(0); + const u32 chroma_format_idc = + static_cast(context.h264_parameter_set.chroma_format_idc.Value()); + writer.WriteUe(chroma_format_idc); + if (chroma_format_idc == 3) { + writer.WriteBit(false); + } + + writer.WriteUe(0); + writer.WriteUe(0); + writer.WriteBit(false); // QpprimeYZeroTransformBypassFlag + writer.WriteBit(false); // Scaling matrix present flag + + writer.WriteUe(static_cast(context.h264_parameter_set.log2_max_frame_num_minus4.Value())); + + const auto order_cnt_type = + static_cast(context.h264_parameter_set.pic_order_cnt_type.Value()); + writer.WriteUe(order_cnt_type); + if (order_cnt_type == 0) { + writer.WriteUe(context.h264_parameter_set.log2_max_pic_order_cnt_lsb_minus4); + } else if (order_cnt_type == 1) { + writer.WriteBit(context.h264_parameter_set.delta_pic_order_always_zero_flag != 0); + + writer.WriteSe(0); + writer.WriteSe(0); + writer.WriteUe(0); + } + + const s32 pic_height = context.h264_parameter_set.frame_height_in_map_units / + (context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2); + + writer.WriteUe(16); + writer.WriteBit(false); + writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1); + writer.WriteUe(pic_height - 1); + writer.WriteBit(context.h264_parameter_set.frame_mbs_only_flag != 0); + + if (!context.h264_parameter_set.frame_mbs_only_flag) { + writer.WriteBit(context.h264_parameter_set.flags.mbaff_frame.Value() != 0); + } + + writer.WriteBit(context.h264_parameter_set.flags.direct_8x8_inference.Value() != 0); + writer.WriteBit(false); // Frame cropping flag + writer.WriteBit(false); // VUI parameter present flag + + writer.End(); + + // H264 PPS + writer.WriteU(1, 24); + writer.WriteU(0, 1); + writer.WriteU(3, 2); + writer.WriteU(8, 5); + + writer.WriteUe(0); + writer.WriteUe(0); + + writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0); + writer.WriteBit(false); + writer.WriteUe(0); + writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active); + writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active); + writer.WriteBit(context.h264_parameter_set.flags.weighted_pred.Value() != 0); + writer.WriteU(static_cast(context.h264_parameter_set.weighted_bipred_idc.Value()), 2); + s32 pic_init_qp = static_cast(context.h264_parameter_set.pic_init_qp_minus26.Value()); + writer.WriteSe(pic_init_qp); + writer.WriteSe(0); + s32 chroma_qp_index_offset = + static_cast(context.h264_parameter_set.chroma_qp_index_offset.Value()); + + writer.WriteSe(chroma_qp_index_offset); + writer.WriteBit(context.h264_parameter_set.deblocking_filter_control_present_flag != 0); + writer.WriteBit(context.h264_parameter_set.flags.constrained_intra_pred.Value() != 0); + writer.WriteBit(context.h264_parameter_set.redundant_pic_cnt_present_flag != 0); + writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0); + + writer.WriteBit(true); + + for (s32 index = 0; index < 6; index++) { + writer.WriteBit(true); + std::span matrix{context.weight_scale}; + writer.WriteScalingList(matrix, index * 16, 16); + } + + if (context.h264_parameter_set.transform_8x8_mode_flag) { + for (s32 index = 0; index < 2; index++) { + writer.WriteBit(true); + std::span matrix{context.weight_scale_8x8}; + writer.WriteScalingList(matrix, index * 64, 64); + } + } + + s32 chroma_qp_index_offset2 = + static_cast(context.h264_parameter_set.second_chroma_qp_index_offset.Value()); + + writer.WriteSe(chroma_qp_index_offset2); + + writer.End(); + + const auto& encoded_header = writer.GetByteArray(); + frame.resize(encoded_header.size() + context.stream_len); + std::memcpy(frame.data(), encoded_header.data(), encoded_header.size()); + + gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, + frame.data() + encoded_header.size(), context.stream_len); + return frame; } @@ -202,7 +197,7 @@ void H264BitWriter::WriteBit(bool state) { WriteBits(state ? 1 : 0, 1); } -void H264BitWriter::WriteScalingList(const std::vector& list, s32 start, s32 count) { +void H264BitWriter::WriteScalingList(std::span list, s32 start, s32 count) { std::vector scan(count); if (count == 16) { std::memcpy(scan.data(), zig_zag_scan.data(), scan.size()); diff --git a/src/video_core/command_classes/codecs/h264.h b/src/video_core/command_classes/codecs/h264.h index 0f3a1d9f3..bfe84a472 100755 --- a/src/video_core/command_classes/codecs/h264.h +++ b/src/video_core/command_classes/codecs/h264.h @@ -20,7 +20,9 @@ #pragma once +#include #include +#include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "video_core/command_classes/nvdec_common.h" @@ -48,7 +50,7 @@ public: /// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification /// Writes the scaling matrices of the sream - void WriteScalingList(const std::vector& list, s32 start, s32 count); + void WriteScalingList(std::span list, s32 start, s32 count); /// Return the bitstream as a vector. [[nodiscard]] std::vector& GetByteArray(); @@ -78,40 +80,110 @@ public: const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false); private: - struct H264ParameterSet { - u32 log2_max_pic_order_cnt{}; - u32 delta_pic_order_always_zero_flag{}; - u32 frame_mbs_only_flag{}; - u32 pic_width_in_mbs{}; - u32 pic_height_in_map_units{}; - INSERT_PADDING_WORDS(1); - u32 entropy_coding_mode_flag{}; - u32 bottom_field_pic_order_flag{}; - u32 num_refidx_l0_default_active{}; - u32 num_refidx_l1_default_active{}; - u32 deblocking_filter_control_flag{}; - u32 redundant_pic_count_flag{}; - u32 transform_8x8_mode_flag{}; - INSERT_PADDING_WORDS(9); - u64 flags{}; - u32 frame_number{}; - u32 frame_number2{}; - }; - static_assert(sizeof(H264ParameterSet) == 0x68, "H264ParameterSet is an invalid size"); - - struct H264DecoderContext { - INSERT_PADDING_BYTES(0x48); - u32 frame_data_size{}; - INSERT_PADDING_BYTES(0xc); - H264ParameterSet h264_parameter_set{}; - INSERT_PADDING_BYTES(0x100); - std::array scaling_matrix_4; - std::array scaling_matrix_8; - }; - static_assert(sizeof(H264DecoderContext) == 0x2a0, "H264DecoderContext is an invalid size"); - std::vector frame; GPU& gpu; + + struct H264ParameterSet { + s32 log2_max_pic_order_cnt_lsb_minus4; ///< 0x00 + s32 delta_pic_order_always_zero_flag; ///< 0x04 + s32 frame_mbs_only_flag; ///< 0x08 + u32 pic_width_in_mbs; ///< 0x0C + u32 frame_height_in_map_units; ///< 0x10 + union { ///< 0x14 + BitField<0, 2, u32> tile_format; + BitField<2, 3, u32> gob_height; + }; + u32 entropy_coding_mode_flag; ///< 0x18 + s32 pic_order_present_flag; ///< 0x1C + s32 num_refidx_l0_default_active; ///< 0x20 + s32 num_refidx_l1_default_active; ///< 0x24 + s32 deblocking_filter_control_present_flag; ///< 0x28 + s32 redundant_pic_cnt_present_flag; ///< 0x2C + u32 transform_8x8_mode_flag; ///< 0x30 + u32 pitch_luma; ///< 0x34 + u32 pitch_chroma; ///< 0x38 + u32 luma_top_offset; ///< 0x3C + u32 luma_bot_offset; ///< 0x40 + u32 luma_frame_offset; ///< 0x44 + u32 chroma_top_offset; ///< 0x48 + u32 chroma_bot_offset; ///< 0x4C + u32 chroma_frame_offset; ///< 0x50 + u32 hist_buffer_size; ///< 0x54 + union { ///< 0x58 + union { + BitField<0, 1, u64> mbaff_frame; + BitField<1, 1, u64> direct_8x8_inference; + BitField<2, 1, u64> weighted_pred; + BitField<3, 1, u64> constrained_intra_pred; + BitField<4, 1, u64> ref_pic; + BitField<5, 1, u64> field_pic; + BitField<6, 1, u64> bottom_field; + BitField<7, 1, u64> second_field; + } flags; + BitField<8, 4, u64> log2_max_frame_num_minus4; + BitField<12, 2, u64> chroma_format_idc; + BitField<14, 2, u64> pic_order_cnt_type; + BitField<16, 6, s64> pic_init_qp_minus26; + BitField<22, 5, s64> chroma_qp_index_offset; + BitField<27, 5, s64> second_chroma_qp_index_offset; + BitField<32, 2, u64> weighted_bipred_idc; + BitField<34, 7, u64> curr_pic_idx; + BitField<41, 5, u64> curr_col_idx; + BitField<46, 16, u64> frame_number; + BitField<62, 1, u64> frame_surfaces; + BitField<63, 1, u64> output_memory_layout; + }; + }; + static_assert(sizeof(H264ParameterSet) == 0x60, "H264ParameterSet is an invalid size"); + + struct H264DecoderContext { + INSERT_PADDING_WORDS_NOINIT(18); ///< 0x0000 + u32 stream_len; ///< 0x0048 + INSERT_PADDING_WORDS_NOINIT(3); ///< 0x004C + H264ParameterSet h264_parameter_set; ///< 0x0058 + INSERT_PADDING_WORDS_NOINIT(66); ///< 0x00B8 + std::array weight_scale; ///< 0x01C0 + std::array weight_scale_8x8; ///< 0x0220 + }; + static_assert(sizeof(H264DecoderContext) == 0x2A0, "H264DecoderContext is an invalid size"); + +#define ASSERT_POSITION(field_name, position) \ + static_assert(offsetof(H264ParameterSet, field_name) == position, \ + "Field " #field_name " has invalid position") + + ASSERT_POSITION(log2_max_pic_order_cnt_lsb_minus4, 0x00); + ASSERT_POSITION(delta_pic_order_always_zero_flag, 0x04); + ASSERT_POSITION(frame_mbs_only_flag, 0x08); + ASSERT_POSITION(pic_width_in_mbs, 0x0C); + ASSERT_POSITION(frame_height_in_map_units, 0x10); + ASSERT_POSITION(tile_format, 0x14); + ASSERT_POSITION(entropy_coding_mode_flag, 0x18); + ASSERT_POSITION(pic_order_present_flag, 0x1C); + ASSERT_POSITION(num_refidx_l0_default_active, 0x20); + ASSERT_POSITION(num_refidx_l1_default_active, 0x24); + ASSERT_POSITION(deblocking_filter_control_present_flag, 0x28); + ASSERT_POSITION(redundant_pic_cnt_present_flag, 0x2C); + ASSERT_POSITION(transform_8x8_mode_flag, 0x30); + ASSERT_POSITION(pitch_luma, 0x34); + ASSERT_POSITION(pitch_chroma, 0x38); + ASSERT_POSITION(luma_top_offset, 0x3C); + ASSERT_POSITION(luma_bot_offset, 0x40); + ASSERT_POSITION(luma_frame_offset, 0x44); + ASSERT_POSITION(chroma_top_offset, 0x48); + ASSERT_POSITION(chroma_bot_offset, 0x4C); + ASSERT_POSITION(chroma_frame_offset, 0x50); + ASSERT_POSITION(hist_buffer_size, 0x54); + ASSERT_POSITION(flags, 0x58); +#undef ASSERT_POSITION + +#define ASSERT_POSITION(field_name, position) \ + static_assert(offsetof(H264DecoderContext, field_name) == position, \ + "Field " #field_name " has invalid position") + + ASSERT_POSITION(stream_len, 0x48); + ASSERT_POSITION(h264_parameter_set, 0x58); + ASSERT_POSITION(weight_scale, 0x1C0); +#undef ASSERT_POSITION }; } // namespace Decoder diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp index 29bb31418..902bc2a98 100755 --- a/src/video_core/command_classes/codecs/vp9.cpp +++ b/src/video_core/command_classes/codecs/vp9.cpp @@ -354,7 +354,7 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_ } Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) { - PictureInfo picture_info{}; + PictureInfo picture_info; gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo)); Vp9PictureInfo vp9_info = picture_info.Convert(); @@ -370,7 +370,7 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) } void VP9::InsertEntropy(u64 offset, Vp9EntropyProbs& dst) { - EntropyProbs entropy{}; + EntropyProbs entropy; gpu.MemoryManager().ReadBlock(offset, &entropy, sizeof(EntropyProbs)); entropy.Convert(dst); } diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h index 139501a1c..2da14f3ca 100755 --- a/src/video_core/command_classes/codecs/vp9_types.h +++ b/src/video_core/command_classes/codecs/vp9_types.h @@ -15,10 +15,10 @@ class GPU; namespace Decoder { struct Vp9FrameDimensions { - s16 width{}; - s16 height{}; - s16 luma_pitch{}; - s16 chroma_pitch{}; + s16 width; + s16 height; + s16 luma_pitch; + s16 chroma_pitch; }; static_assert(sizeof(Vp9FrameDimensions) == 0x8, "Vp9 Vp9FrameDimensions is an invalid size"); @@ -49,87 +49,87 @@ enum class TxMode { }; struct Segmentation { - u8 enabled{}; - u8 update_map{}; - u8 temporal_update{}; - u8 abs_delta{}; - std::array feature_mask{}; - std::array, 8> feature_data{}; + u8 enabled; + u8 update_map; + u8 temporal_update; + u8 abs_delta; + std::array feature_mask; + std::array, 8> feature_data; }; static_assert(sizeof(Segmentation) == 0x64, "Segmentation is an invalid size"); struct LoopFilter { - u8 mode_ref_delta_enabled{}; - std::array ref_deltas{}; - std::array mode_deltas{}; + u8 mode_ref_delta_enabled; + std::array ref_deltas; + std::array mode_deltas; }; static_assert(sizeof(LoopFilter) == 0x7, "LoopFilter is an invalid size"); struct Vp9EntropyProbs { - std::array y_mode_prob{}; - std::array partition_prob{}; - std::array coef_probs{}; - std::array switchable_interp_prob{}; - std::array inter_mode_prob{}; - std::array intra_inter_prob{}; - std::array comp_inter_prob{}; - std::array single_ref_prob{}; - std::array comp_ref_prob{}; - std::array tx_32x32_prob{}; - std::array tx_16x16_prob{}; - std::array tx_8x8_prob{}; - std::array skip_probs{}; - std::array joints{}; - std::array sign{}; - std::array classes{}; - std::array class_0{}; - std::array prob_bits{}; - std::array class_0_fr{}; - std::array fr{}; - std::array class_0_hp{}; - std::array high_precision{}; + std::array y_mode_prob; ///< 0x0000 + std::array partition_prob; ///< 0x0024 + std::array coef_probs; ///< 0x0064 + std::array switchable_interp_prob; ///< 0x0724 + std::array inter_mode_prob; ///< 0x072C + std::array intra_inter_prob; ///< 0x0748 + std::array comp_inter_prob; ///< 0x074C + std::array single_ref_prob; ///< 0x0751 + std::array comp_ref_prob; ///< 0x075B + std::array tx_32x32_prob; ///< 0x0760 + std::array tx_16x16_prob; ///< 0x0766 + std::array tx_8x8_prob; ///< 0x076A + std::array skip_probs; ///< 0x076C + std::array joints; ///< 0x076F + std::array sign; ///< 0x0772 + std::array classes; ///< 0x0774 + std::array class_0; ///< 0x0788 + std::array prob_bits; ///< 0x078A + std::array class_0_fr; ///< 0x079E + std::array fr; ///< 0x07AA + std::array class_0_hp; ///< 0x07B0 + std::array high_precision; ///< 0x07B2 }; static_assert(sizeof(Vp9EntropyProbs) == 0x7B4, "Vp9EntropyProbs is an invalid size"); struct Vp9PictureInfo { - bool is_key_frame{}; - bool intra_only{}; - bool last_frame_was_key{}; - bool frame_size_changed{}; - bool error_resilient_mode{}; - bool last_frame_shown{}; - bool show_frame{}; - std::array ref_frame_sign_bias{}; - s32 base_q_index{}; - s32 y_dc_delta_q{}; - s32 uv_dc_delta_q{}; - s32 uv_ac_delta_q{}; - bool lossless{}; - s32 transform_mode{}; - bool allow_high_precision_mv{}; - s32 interp_filter{}; - s32 reference_mode{}; - s8 comp_fixed_ref{}; - std::array comp_var_ref{}; - s32 log2_tile_cols{}; - s32 log2_tile_rows{}; - bool segment_enabled{}; - bool segment_map_update{}; - bool segment_map_temporal_update{}; - s32 segment_abs_delta{}; - std::array segment_feature_enable{}; - std::array, 8> segment_feature_data{}; - bool mode_ref_delta_enabled{}; - bool use_prev_in_find_mv_refs{}; - std::array ref_deltas{}; - std::array mode_deltas{}; - Vp9EntropyProbs entropy{}; - Vp9FrameDimensions frame_size{}; - u8 first_level{}; - u8 sharpness_level{}; - u32 bitstream_size{}; - std::array frame_offsets{}; - std::array refresh_frame{}; + bool is_key_frame; + bool intra_only; + bool last_frame_was_key; + bool frame_size_changed; + bool error_resilient_mode; + bool last_frame_shown; + bool show_frame; + std::array ref_frame_sign_bias; + s32 base_q_index; + s32 y_dc_delta_q; + s32 uv_dc_delta_q; + s32 uv_ac_delta_q; + bool lossless; + s32 transform_mode; + bool allow_high_precision_mv; + s32 interp_filter; + s32 reference_mode; + s8 comp_fixed_ref; + std::array comp_var_ref; + s32 log2_tile_cols; + s32 log2_tile_rows; + bool segment_enabled; + bool segment_map_update; + bool segment_map_temporal_update; + s32 segment_abs_delta; + std::array segment_feature_enable; + std::array, 8> segment_feature_data; + bool mode_ref_delta_enabled; + bool use_prev_in_find_mv_refs; + std::array ref_deltas; + std::array mode_deltas; + Vp9EntropyProbs entropy; + Vp9FrameDimensions frame_size; + u8 first_level; + u8 sharpness_level; + u32 bitstream_size; + std::array frame_offsets; + std::array refresh_frame; }; struct Vp9FrameContainer { @@ -138,35 +138,35 @@ struct Vp9FrameContainer { }; struct PictureInfo { - INSERT_PADDING_WORDS(12); - u32 bitstream_size{}; - INSERT_PADDING_WORDS(5); - Vp9FrameDimensions last_frame_size{}; - Vp9FrameDimensions golden_frame_size{}; - Vp9FrameDimensions alt_frame_size{}; - Vp9FrameDimensions current_frame_size{}; - u32 vp9_flags{}; - std::array ref_frame_sign_bias{}; - u8 first_level{}; - u8 sharpness_level{}; - u8 base_q_index{}; - u8 y_dc_delta_q{}; - u8 uv_ac_delta_q{}; - u8 uv_dc_delta_q{}; - u8 lossless{}; - u8 tx_mode{}; - u8 allow_high_precision_mv{}; - u8 interp_filter{}; - u8 reference_mode{}; - s8 comp_fixed_ref{}; - std::array comp_var_ref{}; - u8 log2_tile_cols{}; - u8 log2_tile_rows{}; - Segmentation segmentation{}; - LoopFilter loop_filter{}; - INSERT_PADDING_BYTES(5); - u32 surface_params{}; - INSERT_PADDING_WORDS(3); + INSERT_PADDING_WORDS_NOINIT(12); ///< 0x00 + u32 bitstream_size; ///< 0x30 + INSERT_PADDING_WORDS_NOINIT(5); ///< 0x34 + Vp9FrameDimensions last_frame_size; ///< 0x48 + Vp9FrameDimensions golden_frame_size; ///< 0x50 + Vp9FrameDimensions alt_frame_size; ///< 0x58 + Vp9FrameDimensions current_frame_size; ///< 0x60 + u32 vp9_flags; ///< 0x68 + std::array ref_frame_sign_bias; ///< 0x6C + u8 first_level; ///< 0x70 + u8 sharpness_level; ///< 0x71 + u8 base_q_index; ///< 0x72 + u8 y_dc_delta_q; ///< 0x73 + u8 uv_ac_delta_q; ///< 0x74 + u8 uv_dc_delta_q; ///< 0x75 + u8 lossless; ///< 0x76 + u8 tx_mode; ///< 0x77 + u8 allow_high_precision_mv; ///< 0x78 + u8 interp_filter; ///< 0x79 + u8 reference_mode; ///< 0x7A + s8 comp_fixed_ref; ///< 0x7B + std::array comp_var_ref; ///< 0x7C + u8 log2_tile_cols; ///< 0x7E + u8 log2_tile_rows; ///< 0x7F + Segmentation segmentation; ///< 0x80 + LoopFilter loop_filter; ///< 0xE4 + INSERT_PADDING_BYTES_NOINIT(5); ///< 0xEB + u32 surface_params; ///< 0xF0 + INSERT_PADDING_WORDS_NOINIT(3); ///< 0xF4 [[nodiscard]] Vp9PictureInfo Convert() const { return { @@ -176,6 +176,7 @@ struct PictureInfo { .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0, .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0, .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0, + .show_frame = false, .ref_frame_sign_bias = ref_frame_sign_bias, .base_q_index = base_q_index, .y_dc_delta_q = y_dc_delta_q, @@ -204,45 +205,48 @@ struct PictureInfo { !(vp9_flags == (FrameFlags::LastFrameIsKeyFrame)), .ref_deltas = loop_filter.ref_deltas, .mode_deltas = loop_filter.mode_deltas, + .entropy{}, .frame_size = current_frame_size, .first_level = first_level, .sharpness_level = sharpness_level, .bitstream_size = bitstream_size, + .frame_offsets{}, + .refresh_frame{}, }; } }; static_assert(sizeof(PictureInfo) == 0x100, "PictureInfo is an invalid size"); struct EntropyProbs { - INSERT_PADDING_BYTES(1024); - std::array inter_mode_prob{}; - std::array intra_inter_prob{}; - INSERT_PADDING_BYTES(80); - std::array tx_8x8_prob{}; - std::array tx_16x16_prob{}; - std::array tx_32x32_prob{}; - std::array y_mode_prob_e8{}; - std::array, 4> y_mode_prob_e0e7{}; - INSERT_PADDING_BYTES(64); - std::array partition_prob{}; - INSERT_PADDING_BYTES(10); - std::array switchable_interp_prob{}; - std::array comp_inter_prob{}; - std::array skip_probs{}; - INSERT_PADDING_BYTES(1); - std::array joints{}; - std::array sign{}; - std::array class_0{}; - std::array fr{}; - std::array class_0_hp{}; - std::array high_precision{}; - std::array classes{}; - std::array class_0_fr{}; - std::array pred_bits{}; - std::array single_ref_prob{}; - std::array comp_ref_prob{}; - INSERT_PADDING_BYTES(17); - std::array coef_probs{}; + INSERT_PADDING_BYTES_NOINIT(1024); ///< 0x0000 + std::array inter_mode_prob; ///< 0x0400 + std::array intra_inter_prob; ///< 0x041C + INSERT_PADDING_BYTES_NOINIT(80); ///< 0x0420 + std::array tx_8x8_prob; ///< 0x0470 + std::array tx_16x16_prob; ///< 0x0472 + std::array tx_32x32_prob; ///< 0x0476 + std::array y_mode_prob_e8; ///< 0x047C + std::array, 4> y_mode_prob_e0e7; ///< 0x0480 + INSERT_PADDING_BYTES_NOINIT(64); ///< 0x04A0 + std::array partition_prob; ///< 0x04E0 + INSERT_PADDING_BYTES_NOINIT(10); ///< 0x0520 + std::array switchable_interp_prob; ///< 0x052A + std::array comp_inter_prob; ///< 0x0532 + std::array skip_probs; ///< 0x0537 + INSERT_PADDING_BYTES_NOINIT(1); ///< 0x053A + std::array joints; ///< 0x053B + std::array sign; ///< 0x053E + std::array class_0; ///< 0x0540 + std::array fr; ///< 0x0542 + std::array class_0_hp; ///< 0x0548 + std::array high_precision; ///< 0x054A + std::array classes; ///< 0x054C + std::array class_0_fr; ///< 0x0560 + std::array pred_bits; ///< 0x056C + std::array single_ref_prob; ///< 0x0580 + std::array comp_ref_prob; ///< 0x058A + INSERT_PADDING_BYTES_NOINIT(17); ///< 0x058F + std::array coef_probs; ///< 0x05A0 void Convert(Vp9EntropyProbs& fc) { fc.inter_mode_prob = inter_mode_prob; @@ -293,10 +297,45 @@ struct RefPoolElement { }; struct FrameContexts { - s64 from{}; - bool adapted{}; - Vp9EntropyProbs probs{}; + s64 from; + bool adapted; + Vp9EntropyProbs probs; }; +#define ASSERT_POSITION(field_name, position) \ + static_assert(offsetof(Vp9EntropyProbs, field_name) == position, \ + "Field " #field_name " has invalid position") + +ASSERT_POSITION(partition_prob, 0x0024); +ASSERT_POSITION(switchable_interp_prob, 0x0724); +ASSERT_POSITION(sign, 0x0772); +ASSERT_POSITION(class_0_fr, 0x079E); +ASSERT_POSITION(high_precision, 0x07B2); +#undef ASSERT_POSITION + +#define ASSERT_POSITION(field_name, position) \ + static_assert(offsetof(PictureInfo, field_name) == position, \ + "Field " #field_name " has invalid position") + +ASSERT_POSITION(bitstream_size, 0x30); +ASSERT_POSITION(last_frame_size, 0x48); +ASSERT_POSITION(first_level, 0x70); +ASSERT_POSITION(segmentation, 0x80); +ASSERT_POSITION(loop_filter, 0xE4); +ASSERT_POSITION(surface_params, 0xF0); +#undef ASSERT_POSITION + +#define ASSERT_POSITION(field_name, position) \ + static_assert(offsetof(EntropyProbs, field_name) == position, \ + "Field " #field_name " has invalid position") + +ASSERT_POSITION(inter_mode_prob, 0x400); +ASSERT_POSITION(tx_8x8_prob, 0x470); +ASSERT_POSITION(partition_prob, 0x4E0); +ASSERT_POSITION(class_0, 0x540); +ASSERT_POSITION(class_0_fr, 0x560); +ASSERT_POSITION(coef_probs, 0x5A0); +#undef ASSERT_POSITION + }; // namespace Decoder }; // namespace Tegra diff --git a/src/video_core/command_classes/nvdec.cpp b/src/video_core/command_classes/nvdec.cpp index e4f919afd..b5e3b70fc 100755 --- a/src/video_core/command_classes/nvdec.cpp +++ b/src/video_core/command_classes/nvdec.cpp @@ -8,22 +8,21 @@ namespace Tegra { -Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), codec(std::make_unique(gpu)) {} +#define NVDEC_REG_INDEX(field_name) \ + (offsetof(NvdecCommon::NvdecRegisters, field_name) / sizeof(u64)) + +Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), state{}, codec(std::make_unique(gpu, state)) {} Nvdec::~Nvdec() = default; -void Nvdec::ProcessMethod(Method method, u32 argument) { - if (method == Method::SetVideoCodec) { - codec->StateWrite(static_cast(method), argument); - } else { - codec->StateWrite(static_cast(method), static_cast(argument) << 8); - } +void Nvdec::ProcessMethod(u32 method, u32 argument) { + state.reg_array[method] = static_cast(argument) << 8; switch (method) { - case Method::SetVideoCodec: + case NVDEC_REG_INDEX(set_codec_id): codec->SetTargetCodec(static_cast(argument)); break; - case Method::Execute: + case NVDEC_REG_INDEX(execute): Execute(); break; } diff --git a/src/video_core/command_classes/nvdec.h b/src/video_core/command_classes/nvdec.h index e66be80b8..6e1da0b04 100755 --- a/src/video_core/command_classes/nvdec.h +++ b/src/video_core/command_classes/nvdec.h @@ -14,16 +14,11 @@ class GPU; class Nvdec { public: - enum class Method : u32 { - SetVideoCodec = 0x80, - Execute = 0xc0, - }; - explicit Nvdec(GPU& gpu); ~Nvdec(); /// Writes the method into the state, Invoke Execute() if encountered - void ProcessMethod(Method method, u32 argument); + void ProcessMethod(u32 method, u32 argument); /// Return most recently decoded frame [[nodiscard]] AVFramePtr GetFrame(); @@ -33,6 +28,7 @@ private: void Execute(); GPU& gpu; + NvdecCommon::NvdecRegisters state; std::unique_ptr codec; }; } // namespace Tegra diff --git a/src/video_core/command_classes/nvdec_common.h b/src/video_core/command_classes/nvdec_common.h index 01b5e086d..6a24e00a0 100755 --- a/src/video_core/command_classes/nvdec_common.h +++ b/src/video_core/command_classes/nvdec_common.h @@ -4,40 +4,13 @@ #pragma once +#include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" namespace Tegra::NvdecCommon { -struct NvdecRegisters { - INSERT_PADDING_WORDS(256); - u64 set_codec_id{}; - INSERT_PADDING_WORDS(254); - u64 set_platform_id{}; - u64 picture_info_offset{}; - u64 frame_bitstream_offset{}; - u64 frame_number{}; - u64 h264_slice_data_offsets{}; - u64 h264_mv_dump_offset{}; - INSERT_PADDING_WORDS(6); - u64 frame_stats_offset{}; - u64 h264_last_surface_luma_offset{}; - u64 h264_last_surface_chroma_offset{}; - std::array surface_luma_offset{}; - std::array surface_chroma_offset{}; - INSERT_PADDING_WORDS(132); - u64 vp9_entropy_probs_offset{}; - u64 vp9_backward_updates_offset{}; - u64 vp9_last_frame_segmap_offset{}; - u64 vp9_curr_frame_segmap_offset{}; - INSERT_PADDING_WORDS(2); - u64 vp9_last_frame_mvs_offset{}; - u64 vp9_curr_frame_mvs_offset{}; - INSERT_PADDING_WORDS(2); -}; -static_assert(sizeof(NvdecRegisters) == (0xBC0), "NvdecRegisters is incorrect size"); - -enum class VideoCodec : u32 { +enum class VideoCodec : u64 { None = 0x0, H264 = 0x3, Vp8 = 0x5, @@ -45,4 +18,76 @@ enum class VideoCodec : u32 { Vp9 = 0x9, }; +// NVDEC should use a 32-bit address space, but is mapped to 64-bit, +// doubling the sizes here is compensating for that. +struct NvdecRegisters { + static constexpr std::size_t NUM_REGS = 0x178; + + union { + struct { + INSERT_PADDING_WORDS_NOINIT(256); ///< 0x0000 + VideoCodec set_codec_id; ///< 0x0400 + INSERT_PADDING_WORDS_NOINIT(126); ///< 0x0408 + u64 execute; ///< 0x0600 + INSERT_PADDING_WORDS_NOINIT(126); ///< 0x0608 + struct { ///< 0x0800 + union { + BitField<0, 3, VideoCodec> codec; + BitField<4, 1, u64> gp_timer_on; + BitField<13, 1, u64> mb_timer_on; + BitField<14, 1, u64> intra_frame_pslc; + BitField<17, 1, u64> all_intra_frame; + }; + } control_params; + u64 picture_info_offset; ///< 0x0808 + u64 frame_bitstream_offset; ///< 0x0810 + u64 frame_number; ///< 0x0818 + u64 h264_slice_data_offsets; ///< 0x0820 + u64 h264_mv_dump_offset; ///< 0x0828 + INSERT_PADDING_WORDS_NOINIT(6); ///< 0x0830 + u64 frame_stats_offset; ///< 0x0848 + u64 h264_last_surface_luma_offset; ///< 0x0850 + u64 h264_last_surface_chroma_offset; ///< 0x0858 + std::array surface_luma_offset; ///< 0x0860 + std::array surface_chroma_offset; ///< 0x08E8 + INSERT_PADDING_WORDS_NOINIT(132); ///< 0x0970 + u64 vp9_entropy_probs_offset; ///< 0x0B80 + u64 vp9_backward_updates_offset; ///< 0x0B88 + u64 vp9_last_frame_segmap_offset; ///< 0x0B90 + u64 vp9_curr_frame_segmap_offset; ///< 0x0B98 + INSERT_PADDING_WORDS_NOINIT(2); ///< 0x0BA0 + u64 vp9_last_frame_mvs_offset; ///< 0x0BA8 + u64 vp9_curr_frame_mvs_offset; ///< 0x0BB0 + INSERT_PADDING_WORDS_NOINIT(2); ///< 0x0BB8 + }; + std::array reg_array; + }; +}; +static_assert(sizeof(NvdecRegisters) == (0xBC0), "NvdecRegisters is incorrect size"); + +#define ASSERT_REG_POSITION(field_name, position) \ + static_assert(offsetof(NvdecRegisters, field_name) == position * sizeof(u64), \ + "Field " #field_name " has invalid position") + +ASSERT_REG_POSITION(set_codec_id, 0x80); +ASSERT_REG_POSITION(execute, 0xC0); +ASSERT_REG_POSITION(control_params, 0x100); +ASSERT_REG_POSITION(picture_info_offset, 0x101); +ASSERT_REG_POSITION(frame_bitstream_offset, 0x102); +ASSERT_REG_POSITION(frame_number, 0x103); +ASSERT_REG_POSITION(h264_slice_data_offsets, 0x104); +ASSERT_REG_POSITION(frame_stats_offset, 0x109); +ASSERT_REG_POSITION(h264_last_surface_luma_offset, 0x10A); +ASSERT_REG_POSITION(h264_last_surface_chroma_offset, 0x10B); +ASSERT_REG_POSITION(surface_luma_offset, 0x10C); +ASSERT_REG_POSITION(surface_chroma_offset, 0x11D); +ASSERT_REG_POSITION(vp9_entropy_probs_offset, 0x170); +ASSERT_REG_POSITION(vp9_backward_updates_offset, 0x171); +ASSERT_REG_POSITION(vp9_last_frame_segmap_offset, 0x172); +ASSERT_REG_POSITION(vp9_curr_frame_segmap_offset, 0x173); +ASSERT_REG_POSITION(vp9_last_frame_mvs_offset, 0x175); +ASSERT_REG_POSITION(vp9_curr_frame_mvs_offset, 0x176); + +#undef ASSERT_REG_POSITION + } // namespace Tegra::NvdecCommon diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 3986eb172..bec3a81d9 100755 --- 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/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 62bafc453..e21f15c72 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -272,6 +272,87 @@ 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& setting) { + const QString name = QString::fromStdString(setting.GetLabel()); + if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { + setting.SetValue(setting.GetDefault()); + } else { + setting.SetValue(qt_config->value(name, QString::fromStdString(setting.GetDefault())) + .toString() + .toStdString()); + } +} +template +void Config::ReadBasicSetting(Settings::BasicSetting& setting) { + const QString name = QString::fromStdString(setting.GetLabel()); + if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { + setting.SetValue(setting.GetDefault()); + } else { + setting.SetValue( + static_cast(qt_config->value(name, setting.GetDefault())).value()); + } +} + +// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant +template <> +void Config::WriteBasicSetting(const Settings::BasicSetting& setting) { + const QString name = QString::fromStdString(setting.GetLabel()); + qt_config->setValue(name + QStringLiteral("/default"), + setting.GetValue() == setting.GetDefault()); + qt_config->setValue(name, QString::fromStdString(setting.GetValue())); +} +// Explicit float definition: use a double as Qt doesn't write legible floats to config files +template <> +void Config::WriteBasicSetting(const Settings::BasicSetting& 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 +void Config::WriteBasicSetting(const Settings::BasicSetting& setting) { + const QString name = QString::fromStdString(setting.GetLabel()); + qt_config->setValue(name + QStringLiteral("/default"), + setting.GetValue() == setting.GetDefault()); + qt_config->setValue(name, setting.GetValue()); +} + +// Explicit float definition: use a double as Qt doesn't write legible floats to config files +template <> +void Config::WriteGlobalSetting(const Settings::Setting& 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 +void Config::WriteGlobalSetting(const Settings::Setting& setting) { + QString name = QString::fromStdString(setting.GetLabel()); + if (!global) { + qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal()); + } + if (global || !setting.UsingGlobal()) { + qt_config->setValue(name + QStringLiteral("/default"), + setting.GetValue(global) == setting.GetDefault()); + qt_config->setValue(name, setting.GetValue(global)); + } +} + void Config::ReadPlayerValue(std::size_t player_index) { const QString player_prefix = [this, player_index] { if (type == ConfigType::InputProfile) { @@ -395,8 +476,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 +512,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 +525,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 +560,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 +581,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 +593,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 +633,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 +653,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 +682,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 +695,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 +738,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 +789,24 @@ void Config::ReadPathValues() { void Config::ReadCpuValues() { qt_config->beginGroup(QStringLiteral("Cpu")); - ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0); + 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.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 +815,28 @@ 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); + ReadBasicSetting(Settings::values.renderer_debug); + ReadGlobalSetting(Settings::values.vulkan_device); + ReadGlobalSetting(Settings::values.fullscreen_mode); + ReadGlobalSetting(Settings::values.aspect_ratio); + ReadGlobalSetting(Settings::values.max_anisotropy); + ReadGlobalSetting(Settings::values.use_frame_limit); + ReadGlobalSetting(Settings::values.frame_limit); + ReadGlobalSetting(Settings::values.use_disk_shader_cache); + ReadGlobalSetting(Settings::values.gpu_accuracy); + ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); + ReadGlobalSetting(Settings::values.use_nvdec_emulation); + ReadGlobalSetting(Settings::values.accelerate_astc); + ReadGlobalSetting(Settings::values.use_vsync); + ReadGlobalSetting(Settings::values.disable_fps_limit); + ReadGlobalSetting(Settings::values.use_assembly_shaders); + ReadGlobalSetting(Settings::values.use_asynchronous_shaders); + ReadGlobalSetting(Settings::values.use_fast_gpu_time); + ReadGlobalSetting(Settings::values.use_caches_gc); + ReadGlobalSetting(Settings::values.bg_red); + ReadGlobalSetting(Settings::values.bg_green); + ReadGlobalSetting(Settings::values.bg_blue); qt_config->endGroup(); } @@ -870,15 +881,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(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1); + ReadBasicSetting(Settings::values.current_user); + Settings::values.current_user = std::clamp(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 +915,7 @@ void Config::ReadSystemValues() { } } - ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1); + ReadGlobalSetting(Settings::values.sound_index); qt_config->endGroup(); } @@ -915,10 +926,8 @@ void Config::ReadUIValues() { UISettings::values.theme = ReadSetting(QStringLiteral("theme"), QString::fromUtf8(UISettings::themes[0].second)) .toString(); - UISettings::values.enable_discord_presence = - ReadSetting(QStringLiteral("enable_discord_presence"), true).toBool(); - UISettings::values.select_user_on_boot = - ReadSetting(QStringLiteral("select_user_on_boot"), false).toBool(); + ReadBasicSetting(UISettings::values.enable_discord_presence); + ReadBasicSetting(UISettings::values.select_user_on_boot); ReadUIGamelistValues(); ReadUILayoutValues(); @@ -926,24 +935,17 @@ void Config::ReadUIValues() { ReadScreenshotValues(); ReadShortcutValues(); - UISettings::values.single_window_mode = - ReadSetting(QStringLiteral("singleWindowMode"), true).toBool(); - UISettings::values.fullscreen = ReadSetting(QStringLiteral("fullscreen"), false).toBool(); - UISettings::values.display_titlebar = - ReadSetting(QStringLiteral("displayTitleBars"), true).toBool(); - UISettings::values.show_filter_bar = - ReadSetting(QStringLiteral("showFilterBar"), true).toBool(); - UISettings::values.show_status_bar = - ReadSetting(QStringLiteral("showStatusBar"), true).toBool(); - UISettings::values.confirm_before_closing = - ReadSetting(QStringLiteral("confirmClose"), true).toBool(); - UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool(); - UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt(); - UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool(); - UISettings::values.pause_when_in_background = - ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool(); - UISettings::values.hide_mouse = - ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool(); + ReadBasicSetting(UISettings::values.single_window_mode); + ReadBasicSetting(UISettings::values.fullscreen); + ReadBasicSetting(UISettings::values.display_titlebar); + ReadBasicSetting(UISettings::values.show_filter_bar); + ReadBasicSetting(UISettings::values.show_status_bar); + ReadBasicSetting(UISettings::values.confirm_before_closing); + ReadBasicSetting(UISettings::values.first_start); + ReadBasicSetting(UISettings::values.callout_flags); + ReadBasicSetting(UISettings::values.show_console); + ReadBasicSetting(UISettings::values.pause_when_in_background); + ReadBasicSetting(UISettings::values.hide_mouse); qt_config->endGroup(); } @@ -951,12 +953,11 @@ void Config::ReadUIValues() { void Config::ReadUIGamelistValues() { qt_config->beginGroup(QStringLiteral("UIGameList")); - UISettings::values.show_add_ons = ReadSetting(QStringLiteral("show_add_ons"), true).toBool(); - UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt(); - UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt(); - UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt(); - UISettings::values.cache_game_list = - ReadSetting(QStringLiteral("cache_game_list"), true).toBool(); + ReadBasicSetting(UISettings::values.show_add_ons); + ReadBasicSetting(UISettings::values.icon_size); + ReadBasicSetting(UISettings::values.row_1_text_id); + ReadBasicSetting(UISettings::values.row_2_text_id); + ReadBasicSetting(UISettings::values.cache_game_list); const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); for (int i = 0; i < favorites_size; i++) { qt_config->setArrayIndex(i); @@ -979,8 +980,7 @@ void Config::ReadUILayoutValues() { ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray(); UISettings::values.microprofile_geometry = ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray(); - UISettings::values.microprofile_visible = - ReadSetting(QStringLiteral("microProfileDialogVisible"), false).toBool(); + ReadBasicSetting(UISettings::values.microprofile_visible); qt_config->endGroup(); } @@ -988,16 +988,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 +1077,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 +1097,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 +1120,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 +1167,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 +1187,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 +1209,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 +1222,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 +1234,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 +1276,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 +1305,27 @@ void Config::SavePathValues() { void Config::SaveCpuValues() { qt_config->beginGroup(QStringLiteral("Cpu")); - WriteSettingGlobal(QStringLiteral("cpu_accuracy"), - static_cast(Settings::values.cpu_accuracy.GetValue(global)), - Settings::values.cpu_accuracy.UsingGlobal(), - static_cast(Settings::CPUAccuracy::Accurate)); + WriteSetting(QStringLiteral("cpu_accuracy"), + static_cast(Settings::values.cpu_accuracy.GetValue(global)), + static_cast(Settings::values.cpu_accuracy.GetDefault()), + Settings::values.cpu_accuracy.UsingGlobal()); - 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); + WriteGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma); + WriteGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error); + WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr); + WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan); + WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check); if (global) { - WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables, - true); - WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking, - true); - WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"), - Settings::values.cpuopt_return_stack_buffer, true); - WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"), - Settings::values.cpuopt_fast_dispatcher, true); - WriteSetting(QStringLiteral("cpuopt_context_elimination"), - Settings::values.cpuopt_context_elimination, true); - WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true); - WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); - WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), - Settings::values.cpuopt_reduce_misalign_checks, true); - WriteSetting(QStringLiteral("cpuopt_fastmem"), Settings::values.cpuopt_fastmem, true); + WriteBasicSetting(Settings::values.cpuopt_page_tables); + WriteBasicSetting(Settings::values.cpuopt_block_linking); + WriteBasicSetting(Settings::values.cpuopt_return_stack_buffer); + WriteBasicSetting(Settings::values.cpuopt_fast_dispatcher); + WriteBasicSetting(Settings::values.cpuopt_context_elimination); + WriteBasicSetting(Settings::values.cpuopt_const_prop); + WriteBasicSetting(Settings::values.cpuopt_misc_ir); + WriteBasicSetting(Settings::values.cpuopt_reduce_misalign_checks); + WriteBasicSetting(Settings::values.cpuopt_fastmem); } qt_config->endGroup(); @@ -1376,46 +1334,34 @@ void Config::SaveCpuValues() { void Config::SaveRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); - WriteSettingGlobal(QStringLiteral("backend"), - static_cast(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(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(Settings::values.renderer_backend.GetValue(global)), + static_cast(Settings::values.renderer_backend.GetDefault()), + Settings::values.renderer_backend.UsingGlobal()); + WriteBasicSetting(Settings::values.renderer_debug); + WriteGlobalSetting(Settings::values.vulkan_device); + WriteGlobalSetting(Settings::values.fullscreen_mode); + WriteGlobalSetting(Settings::values.aspect_ratio); + WriteGlobalSetting(Settings::values.max_anisotropy); + WriteGlobalSetting(Settings::values.use_frame_limit); + WriteGlobalSetting(Settings::values.frame_limit); + WriteGlobalSetting(Settings::values.use_disk_shader_cache); + WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()), + static_cast(Settings::values.gpu_accuracy.GetValue(global)), + static_cast(Settings::values.gpu_accuracy.GetDefault()), + Settings::values.gpu_accuracy.UsingGlobal()); + WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); + WriteGlobalSetting(Settings::values.use_nvdec_emulation); + WriteGlobalSetting(Settings::values.accelerate_astc); + WriteGlobalSetting(Settings::values.use_vsync); + WriteGlobalSetting(Settings::values.disable_fps_limit); + WriteGlobalSetting(Settings::values.use_assembly_shaders); + WriteGlobalSetting(Settings::values.use_asynchronous_shaders); + WriteGlobalSetting(Settings::values.use_fast_gpu_time); + WriteGlobalSetting(Settings::values.use_caches_gc); + WriteGlobalSetting(Settings::values.bg_red); + WriteGlobalSetting(Settings::values.bg_green); + WriteGlobalSetting(Settings::values.bg_blue); qt_config->endGroup(); } @@ -1423,8 +1369,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 +1399,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 +1419,7 @@ void Config::SaveSystemValues() { 0); } - WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1); + WriteGlobalSetting(Settings::values.sound_index); qt_config->endGroup(); } @@ -1485,10 +1429,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 +1438,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 +1456,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 +1481,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 +1489,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 +1512,14 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) } template -void Config::ReadSettingGlobal(Settings::Setting& setting, const QString& name) { +void Config::ReadGlobalSetting(Settings::Setting& 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).value()); - } -} - -template -void Config::ReadSettingGlobal(Settings::Setting& setting, const QString& name, - const QVariant& default_value) { - const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); - setting.SetGlobal(use_global); - if (global || !use_global) { - setting.SetValue(ReadSetting(name, default_value).value()); + setting.SetValue(static_cast( + ReadSetting(name, QVariant::fromValue(setting.GetDefault()))) + .value()); } } @@ -1612,31 +1542,8 @@ void Config::WriteSetting(const QString& name, const QVariant& value, qt_config->setValue(name, value); } -template -void Config::WriteSettingGlobal(const QString& name, const Settings::Setting& setting) { - if (!global) { - qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal()); - } - if (global || !setting.UsingGlobal()) { - qt_config->setValue(name, setting.GetValue(global)); - } -} - -template -void Config::WriteSettingGlobal(const QString& name, const Settings::Setting& 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()); - 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 100755 --- 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 - void ReadSettingGlobal(Settings::Setting& setting, const QString& name); - template - void ReadSettingGlobal(Settings::Setting& 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 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 - void WriteSettingGlobal(const QString& name, const Settings::Setting& setting); + void ReadGlobalSetting(Settings::Setting& 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 - void WriteSettingGlobal(const QString& name, const Settings::Setting& setting, - const QVariant& default_value); - void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global, - const QVariant& default_value); + void WriteGlobalSetting(const Settings::Setting& 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 + void ReadBasicSetting(Settings::BasicSetting& setting); + + /** Sets a value from the setting in the qt_config using the setting's label and default value. + * + * @param The setting + */ + template + void WriteBasicSetting(const Settings::BasicSetting& setting); ConfigType type; std::unique_ptr qt_config; diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index fc0191432..5aba1a3b2 100755 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -69,7 +69,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() { [[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box); int new_sink_index = 0; - const QString sink_id = QString::fromStdString(Settings::values.sink_id); + const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue()); for (int index = 0; index < ui->output_sink_combo_box->count(); index++) { if (ui->output_sink_combo_box->itemText(index) == sink_id) { new_sink_index = index; @@ -83,7 +83,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() { void ConfigureAudio::SetAudioDeviceFromDeviceID() { int new_device_index = -1; - const QString device_id = QString::fromStdString(Settings::values.audio_device_id); + const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue()); for (int index = 0; index < ui->audio_device_combo_box->count(); index++) { if (ui->audio_device_combo_box->itemText(index) == device_id) { new_device_index = index; @@ -106,9 +106,9 @@ void ConfigureAudio::ApplyConfiguration() { Settings::values.sink_id = ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) .toStdString(); - Settings::values.audio_device_id = + Settings::values.audio_device_id.SetValue( ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex()) - .toStdString(); + .toStdString()); // Guard if during game and set to game-specific value if (Settings::values.volume.UsingGlobal()) { diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp index e25c52baf..98e2d2be5 100755 --- a/src/yuzu/configuration/configure_cpu_debug.cpp +++ b/src/yuzu/configuration/configure_cpu_debug.cpp @@ -24,23 +24,26 @@ void ConfigureCpuDebug::SetConfiguration() { const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); ui->cpuopt_page_tables->setEnabled(runtime_lock); - ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables); + ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue()); ui->cpuopt_block_linking->setEnabled(runtime_lock); - ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking); + ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking.GetValue()); ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock); - ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer); + ui->cpuopt_return_stack_buffer->setChecked( + Settings::values.cpuopt_return_stack_buffer.GetValue()); ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock); - ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher); + ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher.GetValue()); ui->cpuopt_context_elimination->setEnabled(runtime_lock); - ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination); + ui->cpuopt_context_elimination->setChecked( + Settings::values.cpuopt_context_elimination.GetValue()); ui->cpuopt_const_prop->setEnabled(runtime_lock); - ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop); + ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop.GetValue()); ui->cpuopt_misc_ir->setEnabled(runtime_lock); - ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir); + ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir.GetValue()); ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock); - ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks); + ui->cpuopt_reduce_misalign_checks->setChecked( + Settings::values.cpuopt_reduce_misalign_checks.GetValue()); ui->cpuopt_fastmem->setEnabled(runtime_lock); - ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem); + ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem.GetValue()); } void ConfigureCpuDebug::ApplyConfiguration() { diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 15d6a5ad7..cbe45a305 100755 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -31,20 +31,21 @@ 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->disable_macro_jit->setEnabled(runtime_lock); - ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit); - ui->extended_logging->setChecked(Settings::values.extended_logging); + ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); + ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); } void ConfigureDebug::ApplyConfiguration() { @@ -61,7 +62,7 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.extended_logging = ui->extended_logging->isChecked(); Debugger::ToggleConsole(); Common::Log::Filter filter; - filter.ParseFilterString(Settings::values.log_filter); + filter.ParseFilterString(Settings::values.log_filter.GetValue()); Common::Log::SetGlobalFilter(filter); } diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index d223c40ea..9cb317822 100755 --- 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 100755 --- 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_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index d8d3b83dc..2f1419b5b 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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(UISettings::values.icon_size), 64); + const int icon_size = + std::min(static_cast(UISettings::values.icon_size.GetValue()), 64); switch (child->data(GameListItem::TypeRole).value()) { case GameListItemType::SdmcDir: child->setData( diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 978d27325..982c0789d 100755 --- 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(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(UISettings::values.icon_size), 64); + const int icon_size = + std::min(static_cast(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(UISettings::values.icon_size), 64); + const int icon_size = + std::min(static_cast(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(UISettings::values.icon_size), 64); + const int icon_size = + std::min(static_cast(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..5ed3b90b8 100755 --- 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(CalloutFlag::Telemetry)) { + if (UISettings::values.callout_flags.GetValue() & + static_cast(CalloutFlag::Telemetry)) { return; } - UISettings::values.callout_flags |= static_cast(CalloutFlag::Telemetry); + UISettings::values.callout_flags = + UISettings::values.callout_flags.GetValue() | static_cast(CalloutFlag::Telemetry); const QString telemetry_message = tr("Anonymous " "data is collected 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(CalloutFlag::DRDDeprecation)) == 0; + const auto drd_callout = (UISettings::values.callout_flags.GetValue() & + static_cast(CalloutFlag::DRDDeprecation)) == 0; if (result == Core::System::ResultStatus::Success && system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && drd_callout) { - UISettings::values.callout_flags |= static_cast(CalloutFlag::DRDDeprecation); + UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() | + static_cast(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 " @@ -2453,7 +2457,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 +2623,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 +2680,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 +2837,8 @@ void GMainWindow::OnCaptureScreenshot() { } } #endif - render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename); + render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(), + filename); OnStartGame(); } diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index cdcb83f9f..7b9d2dd53 100755 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -13,6 +13,7 @@ #include #include #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 microprofile_visible{false, "microProfileDialogVisible"}; - bool single_window_mode; - bool fullscreen; - bool display_titlebar; - bool show_filter_bar; - bool show_status_bar; + Settings::BasicSetting single_window_mode{true, "singleWindowMode"}; + Settings::BasicSetting fullscreen{false, "fullscreen"}; + Settings::BasicSetting display_titlebar{true, "displayTitleBars"}; + Settings::BasicSetting show_filter_bar{true, "showFilterBar"}; + Settings::BasicSetting show_status_bar{true, "showStatusBar"}; - bool confirm_before_closing; - bool first_start; - bool pause_when_in_background; - bool hide_mouse; + Settings::BasicSetting confirm_before_closing{true, "confirmClose"}; + Settings::BasicSetting first_start{true, "firstStart"}; + Settings::BasicSetting pause_when_in_background{false, "pauseWhenInBackground"}; + Settings::BasicSetting hide_mouse{false, "hideInactiveMouse"}; - bool select_user_on_boot; + Settings::BasicSetting select_user_on_boot{false, "select_user_on_boot"}; // Discord RPC - bool enable_discord_presence; + Settings::BasicSetting enable_discord_presence{true, "enable_discord_presence"}; - bool enable_screenshot_save_as; - u16 screenshot_resolution_factor; + Settings::BasicSetting enable_screenshot_save_as{true, "enable_screenshot_save_as"}; + Settings::BasicSetting screenshot_resolution_factor{0, "screenshot_resolution_factor"}; QString roms_path; QString symbols_path; @@ -83,18 +84,18 @@ struct Values { // Shortcut name std::vector shortcuts; - uint32_t callout_flags; + Settings::BasicSetting callout_flags{0, "calloutFlags"}; // logging - bool show_console; + Settings::BasicSetting 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 show_add_ons{true, "show_add_ons"}; + Settings::BasicSetting icon_size{64, "icon_size"}; + Settings::BasicSetting row_1_text_id{3, "row_1_text_id"}; + Settings::BasicSetting row_2_text_id{2, "row_2_text_id"}; std::atomic_bool is_game_list_reload_pending{false}; - bool cache_game_list; + Settings::BasicSetting 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 100755 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -241,6 +241,24 @@ static const std::array keyboard_mods{ SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI, }; +template <> +void Config::ReadSetting(const std::string& group, Settings::BasicSetting& setting) { + setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault()); +} +template <> +void Config::ReadSetting(const std::string& group, Settings::BasicSetting& setting) { + setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); +} +template <> +void Config::ReadSetting(const std::string& group, Settings::BasicSetting& setting) { + setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); +} +template +void Config::ReadSetting(const std::string& group, Settings::BasicSetting& setting) { + setting = static_cast(sdl2_config->GetInteger(group, setting.GetLabel(), + static_cast(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( - 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(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(Settings::RendererBackend::OpenGL)); - Settings::values.renderer_backend.SetValue( - static_cast(renderer_backend)); - Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false); - Settings::values.vulkan_device.SetValue( - sdl2_config->GetInteger("Renderer", "vulkan_device", 0)); + ReadSetting("Renderer", Settings::values.renderer_backend); + ReadSetting("Renderer", Settings::values.renderer_debug); + ReadSetting("Renderer", Settings::values.vulkan_device); - Settings::values.aspect_ratio.SetValue( - static_cast(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0))); - Settings::values.max_anisotropy.SetValue( - static_cast(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(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(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(sdl2_config->GetInteger("Renderer", "use_vsync", 1))); - Settings::values.disable_fps_limit.SetValue( - sdl2_config->GetBoolean("Renderer", "disable_fps_limit", false)); - Settings::values.use_assembly_shaders.SetValue( - sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true)); - Settings::values.use_asynchronous_shaders.SetValue( - sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false)); - Settings::values.use_nvdec_emulation.SetValue( - sdl2_config->GetBoolean("Renderer", "use_nvdec_emulation", true)); - Settings::values.accelerate_astc.SetValue( - sdl2_config->GetBoolean("Renderer", "accelerate_astc", true)); - Settings::values.use_fast_gpu_time.SetValue( - sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true)); + ReadSetting("Renderer", Settings::values.aspect_ratio); + ReadSetting("Renderer", Settings::values.max_anisotropy); + ReadSetting("Renderer", Settings::values.use_frame_limit); + ReadSetting("Renderer", Settings::values.frame_limit); + ReadSetting("Renderer", Settings::values.use_disk_shader_cache); + ReadSetting("Renderer", Settings::values.gpu_accuracy); + ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); + ReadSetting("Renderer", Settings::values.use_vsync); + ReadSetting("Renderer", Settings::values.disable_fps_limit); + ReadSetting("Renderer", Settings::values.use_assembly_shaders); + ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); + ReadSetting("Renderer", Settings::values.use_nvdec_emulation); + ReadSetting("Renderer", Settings::values.accelerate_astc); + ReadSetting("Renderer", Settings::values.use_fast_gpu_time); - Settings::values.bg_red.SetValue( - static_cast(sdl2_config->GetReal("Renderer", "bg_red", 0.0))); - Settings::values.bg_green.SetValue( - static_cast(sdl2_config->GetReal("Renderer", "bg_green", 0.0))); - Settings::values.bg_blue.SetValue( - static_cast(sdl2_config->GetReal("Renderer", "bg_blue", 0.0))); + ReadSetting("Renderer", Settings::values.bg_red); + ReadSetting("Renderer", Settings::values.bg_green); + ReadSetting("Renderer", Settings::values.bg_blue); // Audio - Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); - Settings::values.enable_audio_stretching.SetValue( - sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true)); - Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); - Settings::values.volume.SetValue( - static_cast(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 100755 --- a/src/yuzu_cmd/config.h +++ b/src/yuzu_cmd/config.h @@ -8,6 +8,8 @@ #include #include +#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 + void ReadSetting(const std::string& group, Settings::BasicSetting& setting); }; diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 50e388312..9607cdcb1 100755 --- 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(Settings::values.log_filter)); Log::SetGlobalFilter(log_filter); Log::AddBackend(std::make_unique());