diff options
Diffstat (limited to '')
39 files changed, 339 insertions, 107 deletions
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss index 12e681648..79960ee0c 100644 --- a/dist/qt_themes/default/style.qss +++ b/dist/qt_themes/default/style.qss @@ -78,6 +78,11 @@ QPushButton#buttonRefreshDevices { max-height: 21px; } +QPushButton#button_reset_defaults { + min-width: 57px; + padding: 4px 8px; +} + QWidget#bottomPerGameInput, QWidget#topControllerApplet, QWidget#bottomControllerApplet, diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss index 49b05c8ba..0c53115f6 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss @@ -2228,6 +2228,10 @@ QPushButton#buttonRefreshDevices { padding: 0px 0px; } +QPushButton#button_reset_defaults { + padding: 3px 6px; +} + QSpinBox#spinboxLStickRange, QSpinBox#spinboxRStickRange, QSpinBox#vibrationSpinPlayer1, diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 1f7cd598e..82a6da9fd 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -42,6 +42,11 @@ endif() # mbedtls add_subdirectory(mbedtls) target_include_directories(mbedtls PUBLIC ./mbedtls/include) +if (NOT MSVC) + target_compile_options(mbedcrypto PRIVATE + -Wno-unused-but-set-variable + -Wno-string-concatenation) +endif() # MicroProfile add_library(microprofile INTERFACE) @@ -94,6 +99,12 @@ if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb) set(BUILD_TOOLS OFF) add_subdirectory(cubeb) add_library(cubeb::cubeb ALIAS cubeb) + if (NOT MSVC) + if (TARGET speex) + target_compile_options(speex PRIVATE -Wno-sign-compare) + endif() + target_compile_options(cubeb PRIVATE -Wno-implicit-const-int-float-conversion) + endif() endif() # DiscordRPC @@ -151,6 +162,9 @@ endif() if (NOT TARGET LLVM::Demangle) add_library(demangle demangle/ItaniumDemangle.cpp) target_include_directories(demangle PUBLIC ./demangle) + if (NOT MSVC) + target_compile_options(demangle PRIVATE -Wno-deprecated-declarations) # std::is_pod + endif() add_library(LLVM::Demangle ALIAS demangle) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7bb88c8ea..6068c7a1f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,16 +114,19 @@ else() -Wno-attributes -Wno-invalid-offsetof -Wno-unused-parameter - - $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init> - $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field> - $<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local> - $<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough> - $<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits> - $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init> - $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field> ) + if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang + add_compile_options( + -Wno-braced-scalar-init + -Wno-unused-private-field + -Wno-nullability-completeness + -Werror=shadow-uncaptured-local + -Werror=implicit-fallthrough + -Werror=type-limits + ) + endif() + if (ARCHITECTURE_x86_64) add_compile_options("-mcx16") add_compile_options("-fwrapv") diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 5e1f10f99..9de9bd93e 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/hle/service/acc/profile_manager.h" #include "input_common/main.h" #include "jni/config.h" @@ -144,7 +145,9 @@ void Config::ReadValues() { Service::Account::MAX_USERS - 1); // Disable docked mode by default on Android - Settings::values.use_docked_mode = config->GetBoolean("System", "use_docked_mode", false); + Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false) + ? Settings::ConsoleMode::Docked + : Settings::ConsoleMode::Handheld); const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); if (rng_seed_enabled) { diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 8b99d1d6e..7e17833a0 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -420,7 +420,7 @@ public: return false; } - return !Settings::values.use_docked_mode.GetValue(); + return !Settings::IsDockedMode(); } void SetDeviceType([[maybe_unused]] int index, int type) { diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp index 9a0801888..04d98a865 100644 --- a/src/audio_core/sink/cubeb_sink.cpp +++ b/src/audio_core/sink/cubeb_sink.cpp @@ -8,6 +8,7 @@ #include "audio_core/sink/cubeb_sink.h" #include "audio_core/sink/sink_stream.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "core/core.h" #ifdef _WIN32 @@ -332,25 +333,38 @@ std::vector<std::string> ListCubebSinkDevices(bool capture) { return device_list; } -u32 GetCubebLatency() { - cubeb* ctx; +namespace { +static long TmpDataCallback(cubeb_stream*, void*, const void*, void*, long) { + return TargetSampleCount; +} +static void TmpStateCallback(cubeb_stream*, void*, cubeb_state) {} +} // namespace + +bool IsCubebSuitable() { +#if !defined(HAVE_CUBEB) + return false; +#else + cubeb* ctx{nullptr}; #ifdef _WIN32 auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED); #endif + // Init cubeb if (cubeb_init(&ctx, "yuzu Latency Getter", nullptr) != CUBEB_OK) { - LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); - // Return a large latency so we choose SDL instead. - return 10000u; + LOG_ERROR(Audio_Sink, "Cubeb failed to init, it is not suitable."); + return false; } + SCOPE_EXIT({ cubeb_destroy(ctx); }); + #ifdef _WIN32 if (SUCCEEDED(com_init_result)) { CoUninitialize(); } #endif + // Test min latency cubeb_stream_params params{}; params.rate = TargetSampleRate; params.channels = 2; @@ -361,12 +375,32 @@ u32 GetCubebLatency() { u32 latency{0}; const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &latency); if (latency_error != CUBEB_OK) { - LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error); - latency = TargetSampleCount * 2; + LOG_ERROR(Audio_Sink, "Cubeb could not get min latency, it is not suitable."); + return false; } latency = std::max(latency, TargetSampleCount * 2); - cubeb_destroy(ctx); - return latency; + + if (latency > TargetSampleCount * 3) { + LOG_ERROR(Audio_Sink, "Cubeb latency is too high, it is not suitable."); + return false; + } + + // Test opening a device with standard parameters + cubeb_devid output_device{0}; + cubeb_devid input_device{0}; + std::string name{"Yuzu test"}; + cubeb_stream* stream{nullptr}; + + if (cubeb_stream_init(ctx, &stream, name.c_str(), input_device, nullptr, output_device, ¶ms, + latency, &TmpDataCallback, &TmpStateCallback, nullptr) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Cubeb could not open a device, it is not suitable."); + return false; + } + + cubeb_stream_stop(stream); + cubeb_stream_destroy(stream); + return true; +#endif } } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/cubeb_sink.h b/src/audio_core/sink/cubeb_sink.h index 3302cb98d..f49a6fdaa 100644 --- a/src/audio_core/sink/cubeb_sink.h +++ b/src/audio_core/sink/cubeb_sink.h @@ -97,10 +97,11 @@ private: std::vector<std::string> ListCubebSinkDevices(bool capture); /** - * Get the reported latency for this sink. + * Check if this backend is suitable for use. + * Checks if enabled, its latency, whether it opens successfully, etc. * - * @return Minimum latency for this sink. + * @return True is this backend is suitable, false otherwise. */ -u32 GetCubebLatency(); +bool IsCubebSuitable(); } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp index c1529d1f9..7b89151de 100644 --- a/src/audio_core/sink/sdl2_sink.cpp +++ b/src/audio_core/sink/sdl2_sink.cpp @@ -9,6 +9,7 @@ #include "audio_core/sink/sdl2_sink.h" #include "audio_core/sink/sink_stream.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "core/core.h" namespace AudioCore::Sink { @@ -84,6 +85,7 @@ public: } Stop(); + SDL_ClearQueuedAudio(device); SDL_CloseAudioDevice(device); } @@ -227,8 +229,42 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) { return device_list; } -u32 GetSDLLatency() { - return TargetSampleCount * 2; +bool IsSDLSuitable() { +#if !defined(HAVE_SDL2) + return false; +#else + // Check SDL can init + if (!SDL_WasInit(SDL_INIT_AUDIO)) { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}", + SDL_GetError()); + return false; + } + } + + // We can set any latency frequency we want with SDL, so no need to check that. + + // Check we can open a device with standard parameters + SDL_AudioSpec spec; + spec.freq = TargetSampleRate; + spec.channels = 2u; + spec.format = AUDIO_S16SYS; + spec.samples = TargetSampleCount * 2; + spec.callback = nullptr; + spec.userdata = nullptr; + + SDL_AudioSpec obtained; + auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false); + + if (device == 0) { + LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}", + SDL_GetError()); + return false; + } + + SDL_CloseAudioDevice(device); + return true; +#endif } } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sdl2_sink.h b/src/audio_core/sink/sdl2_sink.h index 27ed1ab94..9211d2e97 100644 --- a/src/audio_core/sink/sdl2_sink.h +++ b/src/audio_core/sink/sdl2_sink.h @@ -88,10 +88,11 @@ private: std::vector<std::string> ListSDLSinkDevices(bool capture); /** - * Get the reported latency for this sink. + * Check if this backend is suitable for use. + * Checks if enabled, its latency, whether it opens successfully, etc. * - * @return Minimum latency for this sink. + * @return True is this backend is suitable, false otherwise. */ -u32 GetSDLLatency(); +bool IsSDLSuitable(); } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sink_details.cpp b/src/audio_core/sink/sink_details.cpp index 027bfa517..6bec8ee7c 100644 --- a/src/audio_core/sink/sink_details.cpp +++ b/src/audio_core/sink/sink_details.cpp @@ -22,7 +22,7 @@ namespace { struct SinkDetails { using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view); using ListDevicesFn = std::vector<std::string> (*)(bool); - using LatencyFn = u32 (*)(); + using SuitableFn = bool (*)(); /// Name for this sink. Settings::AudioEngine id; @@ -30,8 +30,8 @@ struct SinkDetails { FactoryFn factory; /// A method to call to list available devices. ListDevicesFn list_devices; - /// Method to get the latency of this backend. - LatencyFn latency; + /// Check whether this backend is suitable to be used. + SuitableFn is_suitable; }; // sink_details is ordered in terms of desirability, with the best choice at the top. @@ -43,7 +43,7 @@ constexpr SinkDetails sink_details[] = { return std::make_unique<CubebSink>(device_id); }, &ListCubebSinkDevices, - &GetCubebLatency, + &IsCubebSuitable, }, #endif #ifdef HAVE_SDL2 @@ -53,14 +53,17 @@ constexpr SinkDetails sink_details[] = { return std::make_unique<SDLSink>(device_id); }, &ListSDLSinkDevices, - &GetSDLLatency, + &IsSDLSuitable, }, #endif - SinkDetails{Settings::AudioEngine::Null, - [](std::string_view device_id) -> std::unique_ptr<Sink> { - return std::make_unique<NullSink>(device_id); - }, - [](bool capture) { return std::vector<std::string>{"null"}; }, []() { return 0u; }}, + SinkDetails{ + Settings::AudioEngine::Null, + [](std::string_view device_id) -> std::unique_ptr<Sink> { + return std::make_unique<NullSink>(device_id); + }, + [](bool capture) { return std::vector<std::string>{"null"}; }, + []() { return true; }, + }, }; const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) { @@ -72,18 +75,22 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) { auto iter = find_backend(sink_id); if (sink_id == Settings::AudioEngine::Auto) { - // Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which - // causes audio issues, in that case go with SDL. -#if defined(HAVE_CUBEB) && defined(HAVE_SDL2) - iter = find_backend(Settings::AudioEngine::Cubeb); - if (iter->latency() > TargetSampleCount * 3) { - iter = find_backend(Settings::AudioEngine::Sdl2); + // Auto-select a backend. Use the sink details ordering, preferring cubeb first, checking + // that the backend is available and suitable to use. + for (auto& details : sink_details) { + if (details.is_suitable()) { + iter = &details; + break; + } + } + LOG_ERROR(Service_Audio, "Auto-selecting the {} backend", + Settings::CanonicalizeEnum(iter->id)); + } else { + if (iter != std::end(sink_details) && !iter->is_suitable()) { + LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null", + Settings::CanonicalizeEnum(iter->id)); + iter = find_backend(Settings::AudioEngine::Null); } -#else - iter = std::begin(sink_details); -#endif - LOG_INFO(Service_Audio, "Auto-selecting the {} backend", - Settings::CanonicalizeEnum(iter->id)); } if (iter == std::end(sink_details)) { diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 16a58a750..524056841 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <version> +#include "common/settings_enums.h" #if __cpp_lib_chrono >= 201907L #include <chrono> #include <exception> @@ -145,6 +146,10 @@ bool IsFastmemEnabled() { return true; } +bool IsDockedMode() { + return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked; +} + float Volume() { if (values.audio_muted) { return 0.0f; diff --git a/src/common/settings.h b/src/common/settings.h index 4407c1e6d..b15213bd7 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -379,7 +379,13 @@ struct Values { Setting<s32> current_user{linkage, 0, "current_user", Category::System}; - SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System}; + SwitchableSetting<ConsoleMode> use_docked_mode{linkage, + ConsoleMode::Docked, + "use_docked_mode", + Category::System, + Specialization::Radio, + true, + true}; // Controls InputSetting<std::array<PlayerInput, 10>> players; @@ -519,6 +525,8 @@ bool IsGPULevelHigh(); bool IsFastmemEnabled(); +bool IsDockedMode(); + float Volume(); std::string GetTimeZoneString(TimeZone time_zone); diff --git a/src/common/settings_common.h b/src/common/settings_common.h index 2efb329b0..3082e0ce1 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h @@ -56,6 +56,7 @@ enum Specialization : u8 { Scalar = 5, // Values are continuous Countable = 6, // Can be stepped through Paired = 7, // Another setting is associated with this setting + Radio = 8, // Setting should be presented in a radio group Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage }; diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index e7cb59ea5..815cafe15 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -146,6 +146,8 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); +ENUM(ConsoleMode, Handheld, Docked); + template <typename Type> inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata<Type>::Canonicalizations(); diff --git a/src/common/swap.h b/src/common/swap.h index 085baaf9a..fde343e45 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -460,11 +460,6 @@ S operator&(const S& i, const swap_struct_t<T, F> v) { return i & v.swap(); } -template <typename S, typename T, typename F> -S operator&(const swap_struct_t<T, F> v, const S& i) { - return static_cast<S>(v.swap() & i); -} - // Comparison template <typename S, typename T, typename F> bool operator<(const S& p, const swap_struct_t<T, F> v) { diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 3300d4f79..27755cb58 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -3,6 +3,8 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/settings.h" +#include "common/settings_enums.h" #include "core/frontend/applets/controller.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" @@ -62,7 +64,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac controller->Connect(true); } } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && - !Settings::values.use_docked_mode.GetValue()) { + !Settings::IsDockedMode()) { // We should *never* reach here under any normal circumstances. controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); controller->Connect(true); diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index b4081fc39..2590b20da 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/frontend/framebuffer_layout.h" namespace Layout { @@ -49,7 +50,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { } FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale) { - const bool is_docked = Settings::values.use_docked_mode.GetValue(); + const bool is_docked = Settings::IsDockedMode(); const u32 screen_width = is_docked ? ScreenDocked::Width : ScreenUndocked::Width; const u32 screen_height = is_docked ? ScreenDocked::Height : ScreenUndocked::Height; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 8d057b3a8..da33f0e44 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -6,6 +6,7 @@ #include <cinttypes> #include <cstring> #include "common/settings.h" +#include "common/settings_enums.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" @@ -833,7 +834,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); } else { @@ -921,7 +922,7 @@ void IStorage::Open(HLERequestContext& ctx) { } void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { - const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()}; + const bool use_docked_mode{Settings::IsDockedMode()}; LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp index 227fdd0cf..4f1aa5cc2 100644 --- a/src/core/hle/service/apm/apm_controller.cpp +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/core_timing.h" #include "core/hle/service/apm/apm_controller.h" @@ -67,8 +68,7 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { } PerformanceMode Controller::GetCurrentPerformanceMode() const { - return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Boost - : PerformanceMode::Normal; + return Settings::IsDockedMode() ? PerformanceMode::Boost : PerformanceMode::Normal; } PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 03432f7cb..63eecd42b 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -331,7 +331,7 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() }; // Hack: There is no touch in docked but games still allow it - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { gesture.points[id] = { .x = static_cast<s32>(active_x * Layout::ScreenDocked::Width), .y = static_cast<s32>(active_y * Layout::ScreenDocked::Height), diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 28818c813..3b349b4c4 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -1518,7 +1518,7 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller return false; } // Handheld shouldn't be supported in docked mode - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { return false; } diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 6bb02393c..2eb978379 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -217,7 +217,7 @@ private: IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); } else { diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 62b3f6636..c26179e03 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -14,6 +14,7 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" @@ -275,7 +276,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, static_cast<u32>(Settings::values.shader_backend.GetValue())); AddField(field_type, "Renderer_UseAsynchronousShaders", Settings::values.use_asynchronous_shaders.GetValue()); - AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue()); + AddField(field_type, "System_UseDockedMode", Settings::IsDockedMode()); } bool TelemetrySession::SubmitTestcase() { diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 870e76ab0..188e862d7 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -835,15 +835,15 @@ public: return input_engine->SupportsNfc(identifier); } - Common::Input::NfcState StartNfcPolling() { + Common::Input::NfcState StartNfcPolling() override { return input_engine->StartNfcPolling(identifier); } - Common::Input::NfcState StopNfcPolling() { + Common::Input::NfcState StopNfcPolling() override { return input_engine->StopNfcPolling(identifier); } - Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) { + Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) override { return input_engine->ReadAmiiboData(identifier, out_data); } @@ -852,11 +852,11 @@ public: } Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request, - Common::Input::MifareRequest& out_data) { + Common::Input::MifareRequest& out_data) override { return input_engine->ReadMifareData(identifier, request, out_data); } - Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) { + Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) override { return input_engine->WriteMifareData(identifier, request); } diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index 905505ca1..5d0bb9cc4 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp @@ -27,14 +27,24 @@ MICROPROFILE_DEFINE(MacroHLE, "GPU", "Execute macro HLE", MP_RGB(128, 192, 192)) namespace Tegra { -static void Dump(u64 hash, std::span<const u32> code) { +static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) { const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)}; const auto macro_dir{base_dir / "macros"}; if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) { LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories"); return; } - const auto name{macro_dir / fmt::format("{:016x}.macro", hash)}; + auto name{macro_dir / fmt::format("{:016x}.macro", hash)}; + + if (decompiled) { + auto new_name{macro_dir / fmt::format("decompiled_{:016x}.macro", hash)}; + if (Common::FS::Exists(name)) { + (void)Common::FS::RenameFile(name, new_name); + return; + } + name = new_name; + } + std::fstream macro_file(name, std::ios::out | std::ios::binary); if (!macro_file) { LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}", @@ -90,9 +100,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { if (!mid_method.has_value()) { cache_info.lle_program = Compile(macro_code->second); cache_info.hash = Common::HashValue(macro_code->second); - if (Settings::values.dump_macros) { - Dump(cache_info.hash, macro_code->second); - } } else { const auto& macro_cached = uploaded_macro_code[mid_method.value()]; const auto rebased_method = method - mid_method.value(); @@ -102,9 +109,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { code.size() * sizeof(u32)); cache_info.hash = Common::HashValue(code); cache_info.lle_program = Compile(code); - if (Settings::values.dump_macros) { - Dump(cache_info.hash, code); - } } auto hle_program = hle_macros->GetHLEProgram(cache_info.hash); @@ -117,6 +121,10 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { MICROPROFILE_SCOPE(MacroHLE); cache_info.hle_program->Execute(parameters, method); } + + if (Settings::values.dump_macros) { + Dump(cache_info.hash, macro_code->second, cache_info.has_hle_program); + } } } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index c1314ca99..fe432dfe1 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -611,9 +611,6 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); - if (Settings::values.dump_shaders) { - env.Dump(hash, key.unique_hashes[index]); - } if (!uses_vertex_a || index != 1) { // Normal path programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info); @@ -624,6 +621,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); } + if (Settings::values.dump_shaders) { + env.Dump(hash, key.unique_hashes[index]); + } + if (programs[index].info.requires_layer_emulation) { layer_source_program = &programs[index]; } diff --git a/src/web_service/verify_user_jwt.cpp b/src/web_service/verify_user_jwt.cpp index 129eb1968..f88f67620 100644 --- a/src/web_service/verify_user_jwt.cpp +++ b/src/web_service/verify_user_jwt.cpp @@ -4,6 +4,7 @@ #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // for deprecated OpenSSL functions #endif #include <jwt/jwt.hpp> #if defined(__GNUC__) || defined(__clang__) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 00aafb8f8..d15559518 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -5,6 +5,8 @@ #include <thread> #include "common/assert.h" +#include "common/settings.h" +#include "common/settings_enums.h" #include "common/string_util.h" #include "core/core.h" #include "core/hid/emulated_controller.h" @@ -226,9 +228,11 @@ int QtControllerSelectorDialog::exec() { } void QtControllerSelectorDialog::ApplyConfiguration() { - const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); - Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); - OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system); + const bool pre_docked_mode = Settings::IsDockedMode(); + const bool docked_mode_selected = ui->radioDocked->isChecked(); + Settings::values.use_docked_mode.SetValue( + docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld); + OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system); Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); @@ -616,8 +620,8 @@ void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) { ui->radioDocked->setEnabled(!is_handheld); ui->radioUndocked->setEnabled(!is_handheld); - ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue()); - ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue()); + ui->radioDocked->setChecked(Settings::IsDockedMode()); + ui->radioUndocked->setChecked(!Settings::IsDockedMode()); // Also force into undocked mode if the controller type is handheld. if (is_handheld) { diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 407988b8f..2afa72140 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -928,8 +928,8 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { const Layout::FramebufferLayout layout{[]() { u32 height = UISettings::values.screenshot_height.GetValue(); if (height == 0) { - height = Settings::values.use_docked_mode.GetValue() ? Layout::ScreenDocked::Height - : Layout::ScreenUndocked::Height; + height = Settings::IsDockedMode() ? Layout::ScreenDocked::Height + : Layout::ScreenUndocked::Height; height *= Settings::values.resolution_info.up_factor; } const u32 width = diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index b22c83303..1de093447 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -9,6 +9,7 @@ #include "common/fs/path_util.h" #include "common/settings.h" #include "common/settings_common.h" +#include "common/settings_enums.h" #include "core/core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" @@ -85,9 +86,9 @@ const std::map<Settings::ScalingFilter, QString> Config::scaling_filter_texts_ma {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, }; -const std::map<bool, QString> Config::use_docked_mode_texts_map = { - {true, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, - {false, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, +const std::map<Settings::ConsoleMode, QString> Config::use_docked_mode_texts_map = { + {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, + {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, }; const std::map<Settings::GpuAccuracy, QString> Config::gpu_accuracy_texts_map = { @@ -376,7 +377,7 @@ void Config::ReadControlValues() { const auto controller_type = Settings::values.players.GetValue()[0].controller_type; if (controller_type == Settings::ControllerType::Handheld) { Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); - Settings::values.use_docked_mode.SetValue(false); + Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); } if (IsCustomConfig()) { diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 0ac74c8e7..727feebfb 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -9,6 +9,7 @@ #include <QMetaType> #include <QVariant> #include "common/settings.h" +#include "common/settings_enums.h" #include "yuzu/uisettings.h" class QSettings; @@ -51,7 +52,7 @@ public: static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map; static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map; - static const std::map<bool, QString> use_docked_mode_texts_map; + static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map; static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map; static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map; static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map; diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 7fce85bca..e8f9ebfd8 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -4,6 +4,8 @@ #include <memory> #include <thread> +#include "common/settings.h" +#include "common/settings_enums.h" #include "core/core.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" @@ -197,9 +199,11 @@ void ConfigureInput::ApplyConfiguration() { advanced->ApplyConfiguration(); - const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); - Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); - OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system); + const bool pre_docked_mode = Settings::IsDockedMode(); + const bool docked_mode_selected = ui->radioDocked->isChecked(); + Settings::values.use_docked_mode.SetValue( + docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld); + OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system); Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); @@ -267,8 +271,8 @@ void ConfigureInput::UpdateDockedState(bool is_handheld) { ui->radioDocked->setEnabled(!is_handheld); ui->radioUndocked->setEnabled(!is_handheld); - ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue()); - ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue()); + ui->radioDocked->setChecked(Settings::IsDockedMode()); + ui->radioUndocked->setChecked(!Settings::IsDockedMode()); // Also force into undocked mode if the controller type is handheld. if (is_handheld) { diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 4f9e8db08..b91d6ad4a 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -18,6 +18,7 @@ #include "common/fs/fs_util.h" #include "common/settings_enums.h" +#include "common/settings_input.h" #include "configuration/shared_widget.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" @@ -98,6 +99,12 @@ void ConfigurePerGame::ApplyConfiguration() { addons_tab->ApplyConfiguration(); input_tab->ApplyConfiguration(); + if (Settings::IsDockedMode() && Settings::values.players.GetValue()[0].controller_type == + Settings::ControllerType::Handheld) { + Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); + Settings::values.use_docked_mode.SetGlobal(true); + } + system.ApplySettings(); Settings::LogSettings(); diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index c4833f4e7..0c8e5c8b4 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -106,6 +106,11 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) { push(Settings::values.linkage.by_category[Settings::Category::System]); for (auto setting : settings) { + if (setting->Id() == Settings::values.use_docked_mode.Id() && + Settings::IsConfiguringGlobal()) { + continue; + } + ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs); if (widget == nullptr) { diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 335810788..276bdbaba 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -135,7 +135,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { INSERT(Settings, region_index, "Region:", ""); INSERT(Settings, time_zone_index, "Time Zone:", ""); INSERT(Settings, sound_index, "Sound Output Mode:", ""); - INSERT(Settings, use_docked_mode, "", ""); + INSERT(Settings, use_docked_mode, "Console Mode:", ""); INSERT(Settings, current_user, "", ""); // Controls @@ -379,6 +379,9 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) { PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"), PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"), }}); + translations->insert( + {Settings::EnumMetadata<Settings::ConsoleMode>::Index(), + {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}}); #undef PAIR #undef CTX_PAIR diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index 4e45bc844..7721e58f9 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -23,6 +23,7 @@ #include <QLineEdit> #include <QObject> #include <QPushButton> +#include <QRadioButton> #include <QRegularExpression> #include <QSizePolicy> #include <QSlider> @@ -171,6 +172,65 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer, return combobox; } +QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer, + std::function<void()>& restore_func, + const std::function<void()>& touch) { + const auto type = setting.EnumIndex(); + + QWidget* group = new QWidget(this); + QHBoxLayout* layout = new QHBoxLayout(group); + layout->setContentsMargins(0, 0, 0, 0); + group->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + const ComboboxTranslations* enumeration{nullptr}; + if (combobox_enumerations.contains(type)) { + enumeration = &combobox_enumerations.at(type); + for (const auto& [id, name] : *enumeration) { + QRadioButton* radio_button = new QRadioButton(name, group); + layout->addWidget(radio_button); + radio_buttons.push_back({id, radio_button}); + } + } else { + return group; + } + + const auto get_selected = [=]() -> u32 { + for (const auto& [id, button] : radio_buttons) { + if (button->isChecked()) { + return id; + } + } + return -1; + }; + + const auto set_index = [=](u32 value) { + for (const auto& [id, button] : radio_buttons) { + button->setChecked(id == value); + } + }; + + const u32 setting_value = std::stoi(setting.ToString()); + set_index(setting_value); + + serializer = [get_selected]() { + int current = get_selected(); + return std::to_string(current); + }; + + restore_func = [this, set_index]() { + const u32 global_value = std::stoi(RelevantDefault(setting)); + set_index(global_value); + }; + + if (!Settings::IsConfiguringGlobal()) { + for (const auto& [id, button] : radio_buttons) { + QObject::connect(button, &QAbstractButton::clicked, [touch]() { touch(); }); + } + } + + return group; +} + QWidget* Widget::CreateLineEdit(std::function<std::string()>& serializer, std::function<void()>& restore_func, const std::function<void()>& touch, bool managed) { @@ -411,6 +471,8 @@ void Widget::SetupComponent(const QString& label, std::function<void()>& load_fu return RequestType::Slider; case Settings::Specialization::Countable: return RequestType::SpinBox; + case Settings::Specialization::Radio: + return RequestType::RadioGroup; default: break; } @@ -439,7 +501,11 @@ void Widget::SetupComponent(const QString& label, std::function<void()>& load_fu if (setting.TypeId() == typeid(bool)) { data_component = CreateCheckBox(&setting, label, serializer, restore_func, touch); } else if (setting.IsEnum()) { - data_component = CreateCombobox(serializer, restore_func, touch); + if (request == RequestType::RadioGroup) { + data_component = CreateRadioGroup(serializer, restore_func, touch); + } else { + data_component = CreateCombobox(serializer, restore_func, touch); + } } else if (type == typeid(u32) || type == typeid(int) || type == typeid(u16) || type == typeid(s64) || type == typeid(u8)) { switch (request) { diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index e64693bab..5303dd898 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -22,6 +22,7 @@ class QObject; class QPushButton; class QSlider; class QSpinBox; +class QRadioButton; namespace Settings { class BasicSetting; @@ -38,6 +39,7 @@ enum class RequestType { LineEdit, HexEdit, DateTimeEdit, + RadioGroup, MaxEnum, }; @@ -91,6 +93,7 @@ public: QSlider* slider{}; QComboBox* combobox{}; QDateTimeEdit* date_time_edit{}; + std::vector<std::pair<u32, QRadioButton*>> radio_buttons{}; private: void SetupComponent(const QString& label, std::function<void()>& load_func, bool managed, @@ -106,6 +109,9 @@ private: QWidget* CreateCombobox(std::function<std::string()>& serializer, std::function<void()>& restore_func, const std::function<void()>& touch); + QWidget* CreateRadioGroup(std::function<std::string()>& serializer, + std::function<void()>& restore_func, + const std::function<void()>& touch); QWidget* CreateLineEdit(std::function<std::string()>& serializer, std::function<void()>& restore_func, const std::function<void()>& touch, bool managed = true); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 8e933af64..33c9fd0af 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1158,9 +1158,9 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& docked_mode_pair : Config::use_docked_mode_texts_map) { - context_menu.addAction(docked_mode_pair.second, [this, docked_mode_pair] { - if (docked_mode_pair.first != Settings::values.use_docked_mode.GetValue()) { + for (auto const& pair : Config::use_docked_mode_texts_map) { + context_menu.addAction(pair.second, [this, &pair] { + if (pair.first != Settings::values.use_docked_mode.GetValue()) { OnToggleDockedMode(); } }); @@ -3674,7 +3674,7 @@ void GMainWindow::OnTasReset() { } void GMainWindow::OnToggleDockedMode() { - const bool is_docked = Settings::values.use_docked_mode.GetValue(); + const bool is_docked = Settings::IsDockedMode(); auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); @@ -3688,7 +3688,8 @@ void GMainWindow::OnToggleDockedMode() { controller_dialog->refreshConfiguration(); } - Settings::values.use_docked_mode.SetValue(!is_docked); + Settings::values.use_docked_mode.SetValue(is_docked ? Settings::ConsoleMode::Handheld + : Settings::ConsoleMode::Docked); UpdateDockedButton(); OnDockedModeChanged(is_docked, !is_docked, *system); } @@ -4118,10 +4119,10 @@ void GMainWindow::UpdateGPUAccuracyButton() { } void GMainWindow::UpdateDockedButton() { - const bool is_docked = Settings::values.use_docked_mode.GetValue(); - dock_status_button->setChecked(is_docked); + const auto console_mode = Settings::values.use_docked_mode.GetValue(); + dock_status_button->setChecked(Settings::IsDockedMode()); dock_status_button->setText( - Config::use_docked_mode_texts_map.find(is_docked)->second.toUpper()); + Config::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); } void GMainWindow::UpdateAPIText() { |