From 725d5eea7879fa152c51f15fd76003d3c6bc44ed Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 27 May 2015 15:21:06 -0500 Subject: [PATCH] Applets: Reworked how the Applet update event is handled. Applets are now cleaned up in AppletUpdateEvent after calling their respective Update method. --- src/core/hle/applets/applet.cpp | 36 +++++++++++++++++++++++--------- src/core/hle/applets/applet.h | 21 ++++++++++++------- src/core/hle/applets/swkbd.cpp | 13 ++++++------ src/core/hle/applets/swkbd.h | 18 +++++++++------- src/core/hle/service/apt/apt.cpp | 4 ++-- src/core/hle/service/apt/apt.h | 2 +- src/core/hle/service/gsp_gpu.h | 2 +- 7 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 689f5adc8..4dcce729a 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -31,9 +31,8 @@ namespace Applets { static std::unordered_map> applets; static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback. -/// The interval at which the Applet update callback will be called. -static const u64 applet_update_interval_microseconds = 16666; -std::shared_ptr g_current_applet = nullptr; ///< The applet that is currently executing +/// The interval at which the Applet update callback will be called, 16.6ms +static const u64 applet_update_interval_us = 16666; ResultCode Applet::Create(Service::APT::AppletId id) { switch (id) { @@ -57,21 +56,38 @@ std::shared_ptr Applet::Get(Service::APT::AppletId id) { } /// Handles updating the current Applet every time it's called. -static void AppletUpdateEvent(u64, int cycles_late) { - if (g_current_applet && g_current_applet->IsRunning()) - g_current_applet->Update(); +static void AppletUpdateEvent(u64 applet_id, int cycles_late) { + Service::APT::AppletId id = static_cast(applet_id); + std::shared_ptr applet = Applet::Get(id); + ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); - CoreTiming::ScheduleEvent(usToCycles(applet_update_interval) - cycles_late, - applet_update_event); + applet->Update(); + + // If the applet is still running after the last update, reschedule the event + if (applet->IsRunning()) { + CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, + applet_update_event, applet_id); + } else { + // Otherwise the applet has terminated, in which case we should clean it up + applets[id] = nullptr; + } +} + +ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { + ResultCode result = StartImpl(parameter); + if (result.IsError()) + return result; + // Schedule the update event + CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast(id)); + return result; } void Init() { + // Register the applet update callback applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); - CoreTiming::ScheduleEvent(usToCycles(applet_update_interval), applet_update_event); } void Shutdown() { - CoreTiming::UnscheduleEvent(applet_update_event, 0); } } diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h index f50f7d604..fe537e70d 100644 --- a/src/core/hle/applets/applet.h +++ b/src/core/hle/applets/applet.h @@ -12,10 +12,10 @@ namespace HLE { namespace Applets { -class Applet : public std::enable_shared_from_this { +class Applet { public: - virtual ~Applet() {}; - Applet(Service::APT::AppletId id) : id(id) {}; + virtual ~Applet() { } + Applet(Service::APT::AppletId id) : id(id) { } /** * Creates an instance of the Applet subclass identified by the parameter. @@ -37,25 +37,33 @@ public: * @param parameter Parameter data to handle. * @returns ResultCode Whether the operation was successful or not. */ - virtual ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) = 0; + virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; /** * Handles the Applet start event, triggered from the application. * @param parameter Parameter data to handle. * @returns ResultCode Whether the operation was successful or not. */ - virtual ResultCode Start(Service::APT::AppletStartupParameter const& parameter) = 0; + ResultCode Start(const Service::APT::AppletStartupParameter& parameter); /** * Whether the applet is currently executing instead of the host application or not. */ - virtual bool IsRunning() = 0; + virtual bool IsRunning() const = 0; /** * Handles an update tick for the Applet, lets it update the screen, send commands, etc. */ virtual void Update() = 0; +protected: + /** + * Handles the Applet start event, triggered from the application. + * @param parameter Parameter data to handle. + * @returns ResultCode Whether the operation was successful or not. + */ + virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; + Service::APT::AppletId id; ///< Id of this Applet }; @@ -65,6 +73,5 @@ void Init(); /// Shuts down the HLE applets void Shutdown(); -extern std::shared_ptr g_current_applet; ///< Applet that is currently executing } } // namespace diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index b800e0eb4..7431ebcf8 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -4,6 +4,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "core/hle/applets/swkbd.h" #include "core/hle/service/hid/hid.h" @@ -33,7 +34,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con Service::APT::MessageParameter result; // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo result.signal = static_cast(Service::APT::SignalType::LibAppFinished); - result.data = nullptr; + result.data = nullptr; result.buffer_size = 0; result.destination_id = static_cast(Service::APT::AppletId::Application); result.sender_id = static_cast(id); @@ -43,7 +44,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con return RESULT_SUCCESS; } -ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& parameter) { +ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { + ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); + memcpy(&config, parameter.data, parameter.buffer_size); text_memory = boost::static_pointer_cast(parameter.object); @@ -52,9 +55,7 @@ ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& p DrawScreenKeyboard(); - // Update the current applet so we can get update events started = true; - g_current_applet = shared_from_this(); return RESULT_SUCCESS; } @@ -72,7 +73,7 @@ void SoftwareKeyboard::Update() { config.text_length = 6; config.text_offset = 0; - // TODO(Subv): We're finalizing the applet immediately after it's started, + // TODO(Subv): We're finalizing the applet immediately after it's started, // but we should defer this call until after all the input has been collected. Finalize(); } @@ -98,8 +99,6 @@ void SoftwareKeyboard::Finalize() { Service::APT::SendParameter(message); started = false; - // Unset the current applet, we are not running anymore - g_current_applet = nullptr; } } diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h index 5970390c6..98e81c48a 100644 --- a/src/core/hle/applets/swkbd.h +++ b/src/core/hle/applets/swkbd.h @@ -42,17 +42,21 @@ struct SoftwareKeyboardConfig { INSERT_PADDING_BYTES(0x2B6); }; +/** + * The size of this structure (0x400) has been verified via reverse engineering of multiple games + * that use the software keyboard. + */ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); -class SoftwareKeyboard : public Applet { +class SoftwareKeyboard final : public Applet { public: SoftwareKeyboard(Service::APT::AppletId id); ~SoftwareKeyboard() {} - ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) override; - ResultCode Start(Service::APT::AppletStartupParameter const& parameter) override; + ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; + ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; void Update() override; - bool IsRunning() override { return started; } + bool IsRunning() const override { return started; } /** * Draws a keyboard to the current bottom screen framebuffer. @@ -65,13 +69,13 @@ public: */ void Finalize(); - /// TODO(Subv): Find out what this is actually used for. - // It is believed that the application stores the current screen image here. + /// TODO(Subv): Find out what this is actually used for. + /// It is believed that the application stores the current screen image here. Kernel::SharedPtr framebuffer_memory; /// SharedMemory where the output text will be stored Kernel::SharedPtr text_memory; - + /// Configuration of this instance of the SoftwareKeyboard, as received from the application SoftwareKeyboardConfig config; diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 783fad7ca..b364beed9 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -44,7 +44,7 @@ static u32 cpu_percent; ///< CPU time available to the running application /// Parameter data to be returned in the next call to Glance/ReceiveParameter static MessageParameter next_parameter; -void SendParameter(MessageParameter const& parameter) { +void SendParameter(const MessageParameter& parameter) { next_parameter = parameter; // Signal the event to let the application know that a new parameter is ready to be read parameter_event->Signal(); @@ -338,7 +338,7 @@ void StartLibraryApplet(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); AppletId applet_id = static_cast(cmd_buff[1]); std::shared_ptr applet = HLE::Applets::Applet::Get(applet_id); - + LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); if (applet == nullptr) { diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 510193cc8..9f0802508 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -63,7 +63,7 @@ enum class AppletId : u32 { }; /// Send a parameter to the currently-running application, which will read it via ReceiveParameter -void SendParameter(MessageParameter const& parameter); +void SendParameter(const MessageParameter& parameter); /** * APT::Initialize service function diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h index 9fcf6f06f..268089fdd 100644 --- a/src/core/hle/service/gsp_gpu.h +++ b/src/core/hle/service/gsp_gpu.h @@ -176,7 +176,7 @@ void SignalInterrupt(InterruptId interrupt_id); void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info); /** - * Retrieves the framebuffer info stored in the GSP shared memory for the + * Retrieves the framebuffer info stored in the GSP shared memory for the * specified screen index and thread id. * @param thread_id GSP thread id of the process that accesses the structure that we are requesting. * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1).