Browse Source

Applets: Reworked how the Applet update event is handled.

Applets are now cleaned up in AppletUpdateEvent after calling their respective Update method.
Subv 11 năm trước cách đây
mục cha
commit
725d5eea78

+ 26 - 10
src/core/hle/applets/applet.cpp

@@ -31,9 +31,8 @@ namespace Applets {
 
 static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> 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<Applet> 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> 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<Service::APT::AppletId>(applet_id);
+    std::shared_ptr<Applet> 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<u64>(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);
 }
 
 }

+ 14 - 7
src/core/hle/applets/applet.h

@@ -12,10 +12,10 @@
 namespace HLE {
 namespace Applets {
 
-class Applet : public std::enable_shared_from_this<Applet> {
+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<Applet> g_current_applet; ///< Applet that is currently executing
 }
 } // namespace

+ 6 - 7
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<u32>(Service::APT::SignalType::LibAppFinished);
-    result.data = nullptr; 
+    result.data = nullptr;
     result.buffer_size = 0;
     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
     result.sender_id = static_cast<u32>(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<Kernel::SharedMemory, Kernel::Object>(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;
 }
 
 }

+ 11 - 7
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<Kernel::SharedMemory> framebuffer_memory;
 
     /// SharedMemory where the output text will be stored
     Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
-    
+
     /// Configuration of this instance of the SoftwareKeyboard, as received from the application
     SoftwareKeyboardConfig config;
 

+ 2 - 2
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<AppletId>(cmd_buff[1]);
     std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
-    
+
     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
 
     if (applet == nullptr) {

+ 1 - 1
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

+ 1 - 1
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).