summaryrefslogtreecommitdiff
path: root/src/core/hle/applets
diff options
context:
space:
mode:
authorGravatar bunnei2015-07-11 23:56:59 -0400
committerGravatar bunnei2015-07-11 23:56:59 -0400
commitf4e1d8ea36fc3f8309234b8a4a8c9f659b171c80 (patch)
tree8756cd27489dcb424103e443836b6ea8dba3fccd /src/core/hle/applets
parentMerge pull request #912 from yuriks/process-loading (diff)
parentApplets: Reworked how the Applet update event is handled. (diff)
downloadyuzu-f4e1d8ea36fc3f8309234b8a4a8c9f659b171c80.tar.gz
yuzu-f4e1d8ea36fc3f8309234b8a4a8c9f659b171c80.tar.xz
yuzu-f4e1d8ea36fc3f8309234b8a4a8c9f659b171c80.zip
Merge pull request #823 from Subv/applets_drawing
Library applet support (swkbd for now)
Diffstat (limited to 'src/core/hle/applets')
-rw-r--r--src/core/hle/applets/applet.cpp94
-rw-r--r--src/core/hle/applets/applet.h77
-rw-r--r--src/core/hle/applets/swkbd.cpp105
-rw-r--r--src/core/hle/applets/swkbd.h87
4 files changed, 363 insertions, 0 deletions
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
new file mode 100644
index 000000000..4dcce729a
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,94 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7
8#include "core/core_timing.h"
9#include "core/hle/applets/applet.h"
10#include "core/hle/applets/swkbd.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13
14// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
15// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
16namespace std {
17 template <>
18 struct hash<Service::APT::AppletId> {
19 typedef Service::APT::AppletId argument_type;
20 typedef std::size_t result_type;
21
22 result_type operator()(const argument_type& id_code) const {
23 typedef std::underlying_type<argument_type>::type Type;
24 return std::hash<Type>()(static_cast<Type>(id_code));
25 }
26 };
27}
28
29namespace HLE {
30namespace Applets {
31
32static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
33static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
34/// The interval at which the Applet update callback will be called, 16.6ms
35static const u64 applet_update_interval_us = 16666;
36
37ResultCode Applet::Create(Service::APT::AppletId id) {
38 switch (id) {
39 case Service::APT::AppletId::SoftwareKeyboard1:
40 case Service::APT::AppletId::SoftwareKeyboard2:
41 applets[id] = std::make_shared<SoftwareKeyboard>(id);
42 break;
43 default:
44 // TODO(Subv): Find the right error code
45 return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
46 }
47
48 return RESULT_SUCCESS;
49}
50
51std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
52 auto itr = applets.find(id);
53 if (itr != applets.end())
54 return itr->second;
55 return nullptr;
56}
57
58/// Handles updating the current Applet every time it's called.
59static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
60 Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
61 std::shared_ptr<Applet> applet = Applet::Get(id);
62 ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id);
63
64 applet->Update();
65
66 // If the applet is still running after the last update, reschedule the event
67 if (applet->IsRunning()) {
68 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
69 applet_update_event, applet_id);
70 } else {
71 // Otherwise the applet has terminated, in which case we should clean it up
72 applets[id] = nullptr;
73 }
74}
75
76ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
77 ResultCode result = StartImpl(parameter);
78 if (result.IsError())
79 return result;
80 // Schedule the update event
81 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
82 return result;
83}
84
85void Init() {
86 // Register the applet update callback
87 applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent);
88}
89
90void Shutdown() {
91}
92
93}
94} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 000000000..fe537e70d
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,77 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/shared_memory.h"
10#include "core/hle/service/apt/apt.h"
11
12namespace HLE {
13namespace Applets {
14
15class Applet {
16public:
17 virtual ~Applet() { }
18 Applet(Service::APT::AppletId id) : id(id) { }
19
20 /**
21 * Creates an instance of the Applet subclass identified by the parameter.
22 * and stores it in a global map.
23 * @param id Id of the applet to create.
24 * @returns ResultCode Whether the operation was successful or not.
25 */
26 static ResultCode Create(Service::APT::AppletId id);
27
28 /**
29 * Retrieves the Applet instance identified by the specified id.
30 * @param id Id of the Applet to retrieve.
31 * @returns Requested Applet or nullptr if not found.
32 */
33 static std::shared_ptr<Applet> Get(Service::APT::AppletId id);
34
35 /**
36 * Handles a parameter from the application.
37 * @param parameter Parameter data to handle.
38 * @returns ResultCode Whether the operation was successful or not.
39 */
40 virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0;
41
42 /**
43 * Handles the Applet start event, triggered from the application.
44 * @param parameter Parameter data to handle.
45 * @returns ResultCode Whether the operation was successful or not.
46 */
47 ResultCode Start(const Service::APT::AppletStartupParameter& parameter);
48
49 /**
50 * Whether the applet is currently executing instead of the host application or not.
51 */
52 virtual bool IsRunning() const = 0;
53
54 /**
55 * Handles an update tick for the Applet, lets it update the screen, send commands, etc.
56 */
57 virtual void Update() = 0;
58
59protected:
60 /**
61 * Handles the Applet start event, triggered from the application.
62 * @param parameter Parameter data to handle.
63 * @returns ResultCode Whether the operation was successful or not.
64 */
65 virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
66
67 Service::APT::AppletId id; ///< Id of this Applet
68};
69
70/// Initializes the HLE applets
71void Init();
72
73/// Shuts down the HLE applets
74void Shutdown();
75
76}
77} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 000000000..7431ebcf8
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,105 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7#include "common/string_util.h"
8
9#include "core/hle/applets/swkbd.h"
10#include "core/hle/service/hid/hid.h"
11#include "core/hle/service/gsp_gpu.h"
12#include "video_core/video_core.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15
16namespace HLE {
17namespace Applets {
18
19SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
20 // Create the SharedMemory that will hold the framebuffer data
21 // TODO(Subv): What size should we use here?
22 using Kernel::MemoryPermission;
23 framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
24}
25
26ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
27 if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) {
28 LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
29 UNIMPLEMENTED();
30 // TODO(Subv): Find the right error code
31 return ResultCode(-1);
32 }
33
34 Service::APT::MessageParameter result;
35 // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
36 result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
37 result.data = nullptr;
38 result.buffer_size = 0;
39 result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
40 result.sender_id = static_cast<u32>(id);
41 result.object = framebuffer_memory;
42
43 Service::APT::SendParameter(result);
44 return RESULT_SUCCESS;
45}
46
47ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
48 ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
49
50 memcpy(&config, parameter.data, parameter.buffer_size);
51 text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
52
53 // TODO(Subv): Verify if this is the correct behavior
54 memset(text_memory->GetPointer(), 0, text_memory->size);
55
56 DrawScreenKeyboard();
57
58 started = true;
59 return RESULT_SUCCESS;
60}
61
62void SoftwareKeyboard::Update() {
63 // TODO(Subv): Handle input using the touch events from the HID module
64
65 // TODO(Subv): Remove this hardcoded text
66 std::u16string text = Common::UTF8ToUTF16("Citra");
67 memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
68
69 // TODO(Subv): Ask for input and write it to the shared memory
70 // TODO(Subv): Find out what are the possible values for the return code,
71 // some games seem to check for a hardcoded 2
72 config.return_code = 2;
73 config.text_length = 6;
74 config.text_offset = 0;
75
76 // TODO(Subv): We're finalizing the applet immediately after it's started,
77 // but we should defer this call until after all the input has been collected.
78 Finalize();
79}
80
81void SoftwareKeyboard::DrawScreenKeyboard() {
82 auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
83 auto info = bottom_screen->framebuffer_info[bottom_screen->index];
84
85 // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
86 memset(Memory::GetPointer(info.address_left), 0, info.stride * 320);
87
88 GSP_GPU::SetBufferSwap(1, info);
89}
90
91void SoftwareKeyboard::Finalize() {
92 // Let the application know that we're closing
93 Service::APT::MessageParameter message;
94 message.buffer_size = sizeof(SoftwareKeyboardConfig);
95 message.data = reinterpret_cast<u8*>(&config);
96 message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
97 message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
98 message.sender_id = static_cast<u32>(id);
99 Service::APT::SendParameter(message);
100
101 started = false;
102}
103
104}
105} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 000000000..98e81c48a
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,87 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/hle/applets/applet.h"
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/shared_memory.h"
11#include "core/hle/service/apt/apt.h"
12
13namespace HLE {
14namespace Applets {
15
16struct SoftwareKeyboardConfig {
17 INSERT_PADDING_WORDS(0x8);
18
19 u16 max_text_length; ///< Maximum length of the input text
20
21 INSERT_PADDING_BYTES(0x6E);
22
23 char16_t display_text[65]; ///< Text to display when asking the user for input
24
25 INSERT_PADDING_BYTES(0xE);
26
27 u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
28
29 INSERT_PADDING_WORDS(0x3);
30
31 u32 shared_memory_size; ///< Size of the SharedMemory
32
33 INSERT_PADDING_WORDS(0x1);
34
35 u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
36
37 INSERT_PADDING_WORDS(0x2);
38
39 u32 text_offset; ///< Offset in the SharedMemory where the output text starts
40 u16 text_length; ///< Length in characters of the output text
41
42 INSERT_PADDING_BYTES(0x2B6);
43};
44
45/**
46 * The size of this structure (0x400) has been verified via reverse engineering of multiple games
47 * that use the software keyboard.
48 */
49static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
50
51class SoftwareKeyboard final : public Applet {
52public:
53 SoftwareKeyboard(Service::APT::AppletId id);
54 ~SoftwareKeyboard() {}
55
56 ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
57 ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
58 void Update() override;
59 bool IsRunning() const override { return started; }
60
61 /**
62 * Draws a keyboard to the current bottom screen framebuffer.
63 */
64 void DrawScreenKeyboard();
65
66 /**
67 * Sends the LibAppletClosing signal to the application,
68 * along with the relevant data buffers.
69 */
70 void Finalize();
71
72 /// TODO(Subv): Find out what this is actually used for.
73 /// It is believed that the application stores the current screen image here.
74 Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
75
76 /// SharedMemory where the output text will be stored
77 Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
78
79 /// Configuration of this instance of the SoftwareKeyboard, as received from the application
80 SoftwareKeyboardConfig config;
81
82 /// Whether this applet is currently running instead of the host application or not.
83 bool started;
84};
85
86}
87} // namespace