From c108da5e026b293d7efab583224fd7dd98be9bcf Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 24 Jan 2024 18:51:44 +0200 Subject: [PATCH] Moar appletting --- include/applets/applet.hpp | 9 ++++--- include/kernel/handles.hpp | 1 + include/memory.hpp | 3 ++- include/services/gsp_gpu.hpp | 18 +++++++++++++ src/core/applets/mii_selector.cpp | 12 +++++++++ src/core/applets/software_keyboard.cpp | 3 +++ src/core/kernel/memory_management.cpp | 1 + src/core/services/apt.cpp | 4 +-- src/core/services/gsp_gpu.cpp | 36 ++++++++++++++++++++++++-- 9 files changed, 78 insertions(+), 9 deletions(-) diff --git a/include/applets/applet.hpp b/include/applets/applet.hpp index 79fba1cb..8087ab82 100644 --- a/include/applets/applet.hpp +++ b/include/applets/applet.hpp @@ -65,10 +65,11 @@ namespace Applets { }; struct Parameter { - u32 senderID; - u32 destID; - u32 signal; - std::vector data; + u32 senderID; // ID of the parameter sender + u32 destID; // ID of the app to receive parameter + u32 signal; // Signal type (eg request) + u32 object; // Some applets will also respond with shared memory handles for transferring data between the sender and called + std::vector data; // Misc data }; class AppletBase { diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index b038049f..fe746b65 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -53,6 +53,7 @@ namespace KernelHandles { GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory FontSharedMemHandle, CSNDSharedMemHandle, + APTCaptureSharedMemHandle, // Shared memory for display capture info, HIDSharedMemHandle, MinSharedMemHandle = GSPSharedMemHandle, diff --git a/include/memory.hpp b/include/memory.hpp index 3ddd00cc..640ae5f0 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -112,11 +112,12 @@ class Memory { // This tracks our OS' memory allocations std::vector memoryInfo; - std::array sharedMemBlocks = { + std::array sharedMemBlocks = { SharedMemoryBlock(0, 0, KernelHandles::FontSharedMemHandle), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory + SharedMemoryBlock(0, 0xE7000, KernelHandles::APTCaptureSharedMemHandle), // APT Capture Buffer memory }; public: diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index 68e24580..0a8f8a0a 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -60,6 +60,15 @@ class GPUService { }; static_assert(sizeof(FramebufferUpdate) == 64, "GSP::GPU::FramebufferUpdate has the wrong size"); + // Used for saving and restoring GPU state via ImportDisplayCaptureInfo + struct CaptureInfo { + u32 leftFramebuffer; // Left framebuffer VA + u32 rightFramebuffer; // Right framebuffer VA (Top screen only) + u32 format; + u32 stride; + }; + static_assert(sizeof(CaptureInfo) == 16, "GSP::GPU::CaptureInfo has the wrong size"); + // Service commands void acquireRight(u32 messagePointer); void flushDataCache(u32 messagePointer); @@ -86,6 +95,15 @@ class GPUService { void setBufferSwapImpl(u32 screen_id, const FramebufferInfo& info); + // Get the framebuffer info in shared memory for a given screen + FramebufferUpdate* getFramebufferInfo(int screen) { + // TODO: Offset depends on GSP thread being triggered + return reinterpret_cast(&sharedMem[0x200 + screen * sizeof(FramebufferUpdate)]); + } + + FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); } + FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); } + public: GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu), kernel(kernel), currentPID(currentPID) {} diff --git a/src/core/applets/mii_selector.cpp b/src/core/applets/mii_selector.cpp index f392d846..6a06a01a 100644 --- a/src/core/applets/mii_selector.cpp +++ b/src/core/applets/mii_selector.cpp @@ -1,5 +1,7 @@ #include "applets/mii_selector.hpp" +#include "kernel/handles.hpp" + using namespace Applets; void MiiSelectorApplet::reset() {} @@ -7,5 +9,15 @@ Result::HorizonResult MiiSelectorApplet::start() { return Result::Success; } Result::HorizonResult MiiSelectorApplet::receiveParameter(const Applets::Parameter& parameter) { Helpers::warn("Mii Selector: Unimplemented ReceiveParameter"); + + Applets::Parameter param = Applets::Parameter{ + .senderID = parameter.destID, + .destID = AppletIDs::Application, + .signal = static_cast(APTSignal::Response), + .object = KernelHandles::APTCaptureSharedMemHandle, + .data = {}, + }; + + nextParameter = param; return Result::Success; } \ No newline at end of file diff --git a/src/core/applets/software_keyboard.cpp b/src/core/applets/software_keyboard.cpp index be5a9e21..fd5f4afe 100644 --- a/src/core/applets/software_keyboard.cpp +++ b/src/core/applets/software_keyboard.cpp @@ -1,5 +1,7 @@ #include "applets/software_keyboard.hpp" +#include "kernel/handles.hpp" + using namespace Applets; void SoftwareKeyboardApplet::reset() {} @@ -12,6 +14,7 @@ Result::HorizonResult SoftwareKeyboardApplet::receiveParameter(const Applets::Pa .senderID = parameter.destID, .destID = AppletIDs::Application, .signal = static_cast(APTSignal::Response), + .object = KernelHandles::APTCaptureSharedMemHandle, .data = {}, }; diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index e90a5697..7acc749b 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -144,6 +144,7 @@ void Kernel::mapMemoryBlock() { printf("Mapping CSND memory block\n"); break; + case KernelHandles::APTCaptureSharedMemHandle: break; default: Helpers::panic("Mapping unknown shared memory block: %X", block); } } else { diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 830b8377..25d063c1 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -274,7 +274,7 @@ void APTService::receiveParameter(u32 messagePointer) { // Size of parameter data mem.write32(messagePointer + 16, parameter.data.size()); mem.write32(messagePointer + 20, 0x10); - mem.write32(messagePointer + 24, 0); + mem.write32(messagePointer + 24, parameter.object); mem.write32(messagePointer + 28, 0); } @@ -296,7 +296,7 @@ void APTService::glanceParameter(u32 messagePointer) { // Size of parameter data mem.write32(messagePointer + 16, parameter.data.size()); mem.write32(messagePointer + 20, 0); - mem.write32(messagePointer + 24, 0); + mem.write32(messagePointer + 24, parameter.object); mem.write32(messagePointer + 28, 0); } diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 861dfb0a..a698f7cc 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -143,8 +143,7 @@ void GPUService::requestInterrupt(GPUInterrupt type) { // Not emulating this causes Yoshi's Wooly World, Captain Toad, Metroid 2 et al to hang if (type == GPUInterrupt::VBlank0 || type == GPUInterrupt::VBlank1) { int screen = static_cast(type) - static_cast(GPUInterrupt::VBlank0); // 0 for top screen, 1 for bottom - // TODO: Offset depends on GSP thread being triggered - FramebufferUpdate* update = reinterpret_cast(&sharedMem[0x200 + screen * sizeof(FramebufferUpdate)]); + FramebufferUpdate* update = getFramebufferInfo(screen); if (update->dirtyFlag & 1) { setBufferSwapImpl(screen, update->framebufferInfo[update->index]); @@ -488,4 +487,37 @@ void GPUService::importDisplayCaptureInfo(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x18, 9, 0)); mem.write32(messagePointer + 4, Result::Success); + + if (sharedMem == nullptr) { + Helpers::warn("GSP::GPU::ImportDisplayCaptureInfo called without GSP module being properly initialized!"); + return; + } + + FramebufferUpdate* topScreen = getTopFramebufferInfo(); + FramebufferUpdate* bottomScreen = getBottomFramebufferInfo(); + + // Capture the relevant data for both screens and return them to the caller + CaptureInfo topScreenCapture = { + .leftFramebuffer = topScreen->framebufferInfo[topScreen->index].leftFramebufferVaddr, + .rightFramebuffer = topScreen->framebufferInfo[topScreen->index].rightFramebufferVaddr, + .format = topScreen->framebufferInfo[topScreen->index].format, + .stride = topScreen->framebufferInfo[topScreen->index].stride, + }; + + CaptureInfo bottomScreenCapture = { + .leftFramebuffer = bottomScreen->framebufferInfo[bottomScreen->index].leftFramebufferVaddr, + .rightFramebuffer = bottomScreen->framebufferInfo[bottomScreen->index].rightFramebufferVaddr, + .format = bottomScreen->framebufferInfo[bottomScreen->index].format, + .stride = bottomScreen->framebufferInfo[bottomScreen->index].stride, + }; + + mem.write32(messagePointer + 8, topScreenCapture.leftFramebuffer); + mem.write32(messagePointer + 12, topScreenCapture.rightFramebuffer); + mem.write32(messagePointer + 16, topScreenCapture.format); + mem.write32(messagePointer + 20, topScreenCapture.stride); + + mem.write32(messagePointer + 24, bottomScreenCapture.leftFramebuffer); + mem.write32(messagePointer + 28, bottomScreenCapture.rightFramebuffer); + mem.write32(messagePointer + 32, bottomScreenCapture.format); + mem.write32(messagePointer + 36, bottomScreenCapture.stride); } \ No newline at end of file