From 41e99d8880f4946256344d06b732412ca16c9a13 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 7 Nov 2018 18:01:33 +1100 Subject: [PATCH] Ability to switch between docked and undocked mode in-game Started implementation of the AM message queue mainly used in state getters. Added the ability to switch docked mode whilst in game without stopping emulation. Also removed some things which shouldn't be labelled as stubs as they're implemented correctly --- src/core/hle/service/am/am.cpp | 77 ++++++++++++++++---- src/core/hle/service/am/am.h | 29 +++++++- src/core/hle/service/am/applet_ae.cpp | 34 ++++++--- src/core/hle/service/am/applet_ae.h | 6 +- src/core/hle/service/am/applet_oe.cpp | 21 ++++-- src/core/hle/service/am/applet_oe.h | 6 +- src/yuzu/configuration/configure_general.cpp | 26 ++++++- 7 files changed, 163 insertions(+), 36 deletions(-) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index ac3ff9f20c..0477ce66e0 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -338,7 +338,54 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c LOG_WARNING(Service_AM, "(STUBBED) called"); } -ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { +AppletMessageQueue::AppletMessageQueue() { + auto& kernel = Core::System::GetInstance().Kernel(); + on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, + "AMMessageQueue:OnMessageRecieved"); + on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "AMMessageQueue:OperationModeChanged"); +} + +AppletMessageQueue::~AppletMessageQueue() = default; + +const Kernel::SharedPtr& AppletMessageQueue::GetMesssageRecieveEvent() const { + return on_new_message; +} + +const Kernel::SharedPtr& AppletMessageQueue::GetOperationModeChangedEvent() const { + return on_operation_mode_changed; +} + +void AppletMessageQueue::PushMessage(AppletMessage msg) { + messages.push(msg); + on_new_message->Signal(); +} + +AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { + if (messages.empty()) { + on_new_message->Clear(); + return AppletMessage::NoMessage; + } + auto msg = messages.front(); + messages.pop(); + if (messages.empty()) { + on_new_message->Clear(); + } + return msg; +} + +std::size_t AppletMessageQueue::GetMessageCount() const { + return messages.size(); +} + +void AppletMessageQueue::OperationModeChanged() { + PushMessage(AppletMessage::OperationModeChanged); + PushMessage(AppletMessage::PerformanceModeChanged); + on_operation_mode_changed->Signal(); +} + +ICommonStateGetter::ICommonStateGetter(std::shared_ptr msg_queue) + : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) { // clang-format off static const FunctionInfo functions[] = { {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, @@ -388,21 +435,19 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { - event->Signal(); - IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event); + rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(15); + rb.PushEnum(msg_queue->PopMessage()); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { @@ -414,13 +459,11 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { - event->Signal(); - IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event); + rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { @@ -444,7 +487,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); rb.Push(static_cast(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { @@ -454,7 +497,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { rb.Push(static_cast(use_docked_mode ? APM::PerformanceMode::Docked : APM::PerformanceMode::Handheld)); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } class IStorageAccessor final : public ServiceFramework { @@ -840,8 +883,12 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr nvflinger) { - std::make_shared(nvflinger)->InstallAsService(service_manager); - std::make_shared(nvflinger)->InstallAsService(service_manager); + auto message_queue = std::make_shared(); + message_queue->PushMessage( + AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot + + std::make_shared(nvflinger, message_queue)->InstallAsService(service_manager); + std::make_shared(nvflinger, message_queue)->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 095f948511..4b650ee0ba 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "core/hle/service/service.h" namespace Kernel { @@ -39,6 +40,31 @@ enum SystemLanguage { TraditionalChinese = 16, }; +class AppletMessageQueue { +public: + enum class AppletMessage : u32 { + NoMessage = 0, + FocusStateChanged = 15, + OperationModeChanged = 30, + PerformanceModeChanged = 31, + }; + + AppletMessageQueue(); + ~AppletMessageQueue(); + + const Kernel::SharedPtr& GetMesssageRecieveEvent() const; + const Kernel::SharedPtr& GetOperationModeChangedEvent() const; + void PushMessage(AppletMessage msg); + AppletMessage PopMessage(); + std::size_t GetMessageCount() const; + void OperationModeChanged(); + +private: + std::queue messages{}; + Kernel::SharedPtr on_new_message; + Kernel::SharedPtr on_operation_mode_changed; +}; + class IWindowController final : public ServiceFramework { public: IWindowController(); @@ -102,7 +128,7 @@ private: class ICommonStateGetter final : public ServiceFramework { public: - ICommonStateGetter(); + explicit ICommonStateGetter(std::shared_ptr msg_queue); ~ICommonStateGetter() override; private: @@ -126,6 +152,7 @@ private: void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); Kernel::SharedPtr event; + std::shared_ptr msg_queue; }; class ILibraryAppletCreator final : public ServiceFramework { diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 68ea778e80..ec93e35298 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -12,8 +12,10 @@ namespace Service::AM { class ILibraryAppletProxy final : public ServiceFramework { public: - explicit ILibraryAppletProxy(std::shared_ptr nvflinger) - : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) { + explicit ILibraryAppletProxy(std::shared_ptr nvflinger, + std::shared_ptr msg_queue) + : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { static const FunctionInfo functions[] = { {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, @@ -32,7 +34,7 @@ private: void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(msg_queue); LOG_DEBUG(Service_AM, "called"); } @@ -93,12 +95,15 @@ private: } std::shared_ptr nvflinger; + std::shared_ptr msg_queue; }; class ISystemAppletProxy final : public ServiceFramework { public: - explicit ISystemAppletProxy(std::shared_ptr nvflinger) - : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) { + explicit ISystemAppletProxy(std::shared_ptr nvflinger, + std::shared_ptr msg_queue) + : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { static const FunctionInfo functions[] = { {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, @@ -119,7 +124,7 @@ private: void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(msg_queue); LOG_DEBUG(Service_AM, "called"); } @@ -186,31 +191,34 @@ private: LOG_DEBUG(Service_AM, "called"); } std::shared_ptr nvflinger; + std::shared_ptr msg_queue; }; void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger); + rb.PushIpcInterface(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger); + rb.PushIpcInterface(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger); + rb.PushIpcInterface(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } -AppletAE::AppletAE(std::shared_ptr nvflinger) - : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) { +AppletAE::AppletAE(std::shared_ptr nvflinger, + std::shared_ptr msg_queue) + : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { // clang-format off static const FunctionInfo functions[] = { {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, @@ -228,4 +236,8 @@ AppletAE::AppletAE(std::shared_ptr nvflinger) AppletAE::~AppletAE() = default; +const std::shared_ptr& AppletAE::GetMessageQueue() const { + return msg_queue; +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 1ed77baa47..902db26658 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -17,15 +17,19 @@ namespace AM { class AppletAE final : public ServiceFramework { public: - explicit AppletAE(std::shared_ptr nvflinger); + explicit AppletAE(std::shared_ptr nvflinger, + std::shared_ptr msg_queue); ~AppletAE() override; + const std::shared_ptr& GetMessageQueue() const; + private: void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); std::shared_ptr nvflinger; + std::shared_ptr msg_queue; }; } // namespace AM diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 60717afd97..20c8d5fff6 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -12,8 +12,10 @@ namespace Service::AM { class IApplicationProxy final : public ServiceFramework { public: - explicit IApplicationProxy(std::shared_ptr nvflinger) - : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) { + explicit IApplicationProxy(std::shared_ptr nvflinger, + std::shared_ptr msg_queue) + : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { // clang-format off static const FunctionInfo functions[] = { {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -70,7 +72,7 @@ private: void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(msg_queue); LOG_DEBUG(Service_AM, "called"); } @@ -89,17 +91,20 @@ private: } std::shared_ptr nvflinger; + std::shared_ptr msg_queue; }; void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger); + rb.PushIpcInterface(nvflinger, msg_queue); LOG_DEBUG(Service_AM, "called"); } -AppletOE::AppletOE(std::shared_ptr nvflinger) - : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) { +AppletOE::AppletOE(std::shared_ptr nvflinger, + std::shared_ptr msg_queue) + : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), + msg_queue(std::move(msg_queue)) { static const FunctionInfo functions[] = { {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; @@ -108,4 +113,8 @@ AppletOE::AppletOE(std::shared_ptr nvflinger) AppletOE::~AppletOE() = default; +const std::shared_ptr& AppletOE::GetMessageQueue() const { + return msg_queue; +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 60cfdfd9d7..bbd0108eff 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -17,13 +17,17 @@ namespace AM { class AppletOE final : public ServiceFramework { public: - explicit AppletOE(std::shared_ptr nvflinger); + explicit AppletOE(std::shared_ptr nvflinger, + std::shared_ptr msg_queue); ~AppletOE() override; + const std::shared_ptr& GetMessageQueue() const; + private: void OpenApplicationProxy(Kernel::HLERequestContext& ctx); std::shared_ptr nvflinger; + std::shared_ptr msg_queue; }; } // namespace AM diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 537d6e576e..9b429c3460 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -3,6 +3,10 @@ // Refer to the license.txt file included. #include "core/core.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applet_ae.h" +#include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/sm/sm.h" #include "core/settings.h" #include "ui_configure_general.h" #include "yuzu/configuration/configure_general.h" @@ -20,7 +24,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) this->setConfiguration(); ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); - ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn()); } ConfigureGeneral::~ConfigureGeneral() = default; @@ -45,6 +48,27 @@ void ConfigureGeneral::applyConfiguration() { ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); + const bool pre_docked_mode = Settings::values.use_docked_mode; Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); + + if (pre_docked_mode != Settings::values.use_docked_mode) { + Core::System& system{Core::System::GetInstance()}; + Service::SM::ServiceManager& sm = system.ServiceManager(); + + // Message queue is shared between these services, we just need to signal an operation + // change to one and it will handle both automatically + auto applet_oe = sm.GetService("appletOE"); + auto applet_ae = sm.GetService("appletAE"); + bool has_signalled = false; + + if (applet_oe != nullptr) { + applet_oe->GetMessageQueue()->OperationModeChanged(); + has_signalled = true; + } + + if (applet_ae != nullptr && !has_signalled) { + applet_ae->GetMessageQueue()->OperationModeChanged(); + } + } Settings::values.enable_nfc = ui->enable_nfc->isChecked(); }