From 96a2dc18b1e44ae0732b7d8a75151f26c6185fc3 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Thu, 29 Dec 2022 00:57:44 +0200 Subject: [PATCH 01/25] [CFG Add country info --- src/core/services/cfg.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/services/cfg.cpp b/src/core/services/cfg.cpp index 2fb21070..c5f68c15 100644 --- a/src/core/services/cfg.cpp +++ b/src/core/services/cfg.cpp @@ -37,7 +37,12 @@ void CFGService::getConfigInfoBlk2(u32 messagePointer) { mem.write8(output, static_cast(DSPService::SoundOutputMode::Stereo)); } else if (size == 1 && blockID == 0xA0002){ // System language mem.write8(output, static_cast(LanguageCodes::English)); - } else if (size == 0x20 && blockID == 0x50005) { + } else if (size == 4 && blockID == 0xB0000) { // Country info + mem.write8(output, 0); // Unknown + mem.write8(output + 1, 0); // Unknown + mem.write8(output + 2, 2); // Province (Temporarily stubbed to Washington DC like Citra) + mem.write8(output + 3, 49); // Country code (Temporarily stubbed to USA like Citra) + }else if (size == 0x20 && blockID == 0x50005) { printf("[Unimplemented] Read stereo display settings from NAND\n"); } else { Helpers::panic("Unhandled GetConfigInfoBlk2 configuration"); From 2fe65a58a1cc6a1cbec79c25f19e1ae974bda1b2 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 30 Dec 2022 17:51:30 +0200 Subject: [PATCH 02/25] [PICA] Fix shader on Nvidia --- src/core/PICA/renderer_opengl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/PICA/renderer_opengl.cpp b/src/core/PICA/renderer_opengl.cpp index 9f57a9f9..2c41dba5 100644 --- a/src/core/PICA/renderer_opengl.cpp +++ b/src/core/PICA/renderer_opengl.cpp @@ -38,7 +38,7 @@ const char* fragmentShader = R"( float alpha = fragColour.a; switch (func) { - case 0: discard; break; // Never pass alpha test + case 0: discard; // Never pass alpha test case 1: break; // Always pass alpha test case 2: // Pass if equal if (alpha != reference) From f2ab7a03707f18179d835a7111b1d10f77e228b5 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 30 Dec 2022 19:24:42 +0200 Subject: [PATCH 03/25] [HID] Implement more of the gyro, OoT stops hanging --- src/core/services/hid.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/core/services/hid.cpp b/src/core/services/hid.cpp index 740b5650..27661954 100644 --- a/src/core/services/hid.cpp +++ b/src/core/services/hid.cpp @@ -1,4 +1,5 @@ #include "services/hid.hpp" +#include namespace HIDCommands { enum : u32 { @@ -49,19 +50,25 @@ void HIDService::enableGyroscopeLow(u32 messagePointer) { void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) { log("HID::GetGyroscopeLowCalibrateParam\n"); + constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware mem.write32(messagePointer + 4, Result::Success); - // Fill calibration data with 0s since we don't have gyro - for (int i = 0; i < 5; i++) { - mem.write32(messagePointer + 8 + i * 4, 0); + // Fill calibration data (for x/y/z depending on i) + for (int i = 0; i < 3; i++) { + const u32 pointer = messagePointer + 8 + i * 3 * sizeof(u16); // Pointer to write the calibration info for the current coordinate + + mem.write16(pointer, 0); // Zero point + mem.write16(pointer + 1 * sizeof(u16), unit); // Positive unit point + mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point } } void HIDService::getGyroscopeCoefficient(u32 messagePointer) { log("HID::GetGyroscopeLowRawToDpsCoefficient\n"); + constexpr float gyroscopeCoeff = 14.375f; // Same as retail 3DS mem.write32(messagePointer + 4, Result::Success); - // This should write a coeff value here but we don't have gyro so + mem.write32(messagePointer + 8, std::bit_cast(gyroscopeCoeff)); } void HIDService::getIPCHandles(u32 messagePointer) { From 23a6ef447fc8a1bb8529a4779904472494008c60 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 31 Dec 2022 15:54:24 +0200 Subject: [PATCH 04/25] Stuffs --- include/arm_defs.hpp | 3 ++- src/core/CPU/cpu_dynarmic.cpp | 4 ++-- src/core/PICA/regs.cpp | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/arm_defs.hpp b/include/arm_defs.hpp index 03143932..ef017775 100644 --- a/include/arm_defs.hpp +++ b/include/arm_defs.hpp @@ -61,6 +61,7 @@ namespace FPSCR { RoundToZero = 3 << 22, // Default FPSCR value for threads - ThreadDefault = DefaultNan | FlushToZero | RoundToZero | IXC + ThreadDefault = DefaultNan | FlushToZero | RoundToZero, + MainThreadDefault = ThreadDefault | IXC; }; } \ No newline at end of file diff --git a/src/core/CPU/cpu_dynarmic.cpp b/src/core/CPU/cpu_dynarmic.cpp index 9092b7a3..94903c2f 100644 --- a/src/core/CPU/cpu_dynarmic.cpp +++ b/src/core/CPU/cpu_dynarmic.cpp @@ -9,7 +9,7 @@ CPU::CPU(Memory& mem, Kernel& kernel) : mem(mem), env(mem, kernel, *this) { config.arch_version = Dynarmic::A32::ArchVersion::v6K; config.callbacks = &env; config.coprocessors[15] = cp15; - // config.define_unpredictable_behaviour = true; + config.define_unpredictable_behaviour = true; config.global_monitor = &exclusiveMonitor; config.processor_id = 0; @@ -18,7 +18,7 @@ CPU::CPU(Memory& mem, Kernel& kernel) : mem(mem), env(mem, kernel, *this) { void CPU::reset() { setCPSR(CPSR::UserMode); - setFPSCR(FPSCR::ThreadDefault); + setFPSCR(FPSCR::MainThreadDefault); env.totalTicks = 0; cp15->reset(); diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 7a2c15c4..10ae9b46 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -4,8 +4,13 @@ using namespace Floats; u32 GPU::readReg(u32 address) { - log("Ignoring read from GPU register %08X\n", address); - return 0; + if (address >= 0x1EF01000 && address < 0x1EF01C00) { // Internal registers + const u32 index = (address - 0x1EF01000) / sizeof(u32); + return readInternalReg(index); + } else { + log("Ignoring read to external GPU register %08X.\n", address); + return 0; + } } void GPU::writeReg(u32 address, u32 value) { From 6b69010628e96dc4a1f293ac409459a00ec0d3f0 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 31 Dec 2022 15:57:24 +0200 Subject: [PATCH 05/25] [Kernel] Forgot a sortThreads call, oops. --- src/core/kernel/threads.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index 7f686783..1931a158 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -274,7 +274,7 @@ void Kernel::setThreadPriority() { object->getData()->priority = priority; } } - + sortThreads(); rescheduleThreads(); } From 672a893938558f9b153bf3cbf1162355f0d527c9 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 31 Dec 2022 16:38:28 +0200 Subject: [PATCH 06/25] Fix typo & reset FPRs on CPU reset --- include/arm_defs.hpp | 2 +- src/core/CPU/cpu_dynarmic.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/arm_defs.hpp b/include/arm_defs.hpp index ef017775..1d7a9bde 100644 --- a/include/arm_defs.hpp +++ b/include/arm_defs.hpp @@ -62,6 +62,6 @@ namespace FPSCR { // Default FPSCR value for threads ThreadDefault = DefaultNan | FlushToZero | RoundToZero, - MainThreadDefault = ThreadDefault | IXC; + MainThreadDefault = ThreadDefault | IXC }; } \ No newline at end of file diff --git a/src/core/CPU/cpu_dynarmic.cpp b/src/core/CPU/cpu_dynarmic.cpp index 94903c2f..c01d0641 100644 --- a/src/core/CPU/cpu_dynarmic.cpp +++ b/src/core/CPU/cpu_dynarmic.cpp @@ -26,6 +26,7 @@ void CPU::reset() { jit->Reset(); jit->ClearCache(); jit->Regs().fill(0); + jit->ExtRegs().fill(0); } #endif // CPU_DYNARMIC \ No newline at end of file From 9f792c2cf57f35b3b61e4dc42c2d71ac2566e167 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sun, 1 Jan 2023 21:04:34 +0200 Subject: [PATCH 07/25] Add thread logger, split renderer from PICA --- CMakeLists.txt | 7 +++- include/kernel/kernel.hpp | 1 + include/logger.hpp | 37 ++++++++++--------- src/core/kernel/threads.cpp | 4 +- .../renderer_gl.cpp} | 4 +- 5 files changed, 28 insertions(+), 25 deletions(-) rename src/core/{PICA/renderer_opengl.cpp => renderer_gl/renderer_gl.cpp} (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 429f979a..87f8a9ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,8 +59,10 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/ptm.cpp src/core/services/mic.cpp src/core/services/cecd.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp - src/core/PICA/shader_interpreter.cpp src/core/PICA/renderer_opengl.cpp + src/core/PICA/shader_interpreter.cpp ) +set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp) + set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp) set(FS_SOURCE_FILES src/core/fs/archive_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp) @@ -95,8 +97,9 @@ source_group("Source Files\\Core\\Kernel" FILES ${KERNEL_SOURCE_FILES}) source_group("Source Files\\Core\\Loader" FILES ${LOADER_SOURCE_FILES}) source_group("Source Files\\Core\\Services" FILES ${SERVICE_SOURCE_FILES}) source_group("Source Files\\Core\\PICA" FILES ${PICA_SOURCE_FILES}) +source_group("Source Files\\Core\\OpenGL Renderer" FILES ${RENDERER_GL_SOURCE_FILES}) source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES}) add_executable(Alber ${SOURCE_FILES} ${FS_SOURCE_FILES} ${KERNEL_SOURCE_FILES} ${LOADER_SOURCE_FILES} ${SERVICE_SOURCE_FILES} -${PICA_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES}) +${PICA_SOURCE_FILES} ${RENDERER_GL_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES}) target_link_libraries(Alber PRIVATE dynarmic SDL2-static) \ No newline at end of file diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index ac6315b5..6662a722 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -81,6 +81,7 @@ private: MAKE_LOG_FUNCTION(log, kernelLogger) MAKE_LOG_FUNCTION(logSVC, svcLogger) + MAKE_LOG_FUNCTION(logThread, threadLogger) MAKE_LOG_FUNCTION(logDebugString, debugStringLogger) MAKE_LOG_FUNCTION(logError, errorLogger) MAKE_LOG_FUNCTION(logFileIO, fileIOLogger) diff --git a/include/logger.hpp b/include/logger.hpp index 01ac282b..5025bc44 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -18,26 +18,27 @@ namespace Log { }; // Our loggers here. Enable/disable by toggling the template param - static Logger kernelLogger; - static Logger debugStringLogger; // Enables output for the outputDebugString SVC - static Logger errorLogger; - static Logger fileIOLogger; - static Logger svcLogger; - static Logger gpuLogger; + static Logger kernelLogger; + static Logger debugStringLogger; // Enables output for the outputDebugString SVC + static Logger errorLogger; + static Logger fileIOLogger; + static Logger svcLogger; + static Logger threadLogger; + static Logger gpuLogger; // Service loggers - static Logger aptLogger; - static Logger cecdLogger; - static Logger cfgLogger; - static Logger dspServiceLogger; - static Logger fsLogger; - static Logger hidLogger; - static Logger gspGPULogger; - static Logger gspLCDLogger; - static Logger micLogger; - static Logger ndmLogger; - static Logger ptmLogger; - static Logger srvLogger; + static Logger aptLogger; + static Logger cecdLogger; + static Logger cfgLogger; + static Logger dspServiceLogger; + static Logger fsLogger; + static Logger hidLogger; + static Logger gspGPULogger; + static Logger gspLCDLogger; + static Logger micLogger; + static Logger ndmLogger; + static Logger ptmLogger; + static Logger srvLogger; #define MAKE_LOG_FUNCTION(functionName, logger) \ template \ diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index 1931a158..9198d069 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -11,7 +11,7 @@ void Kernel::switchThread(int newThreadIndex) { auto& oldThread = threads[currentThreadIndex]; auto& newThread = threads[newThreadIndex]; newThread.status = ThreadStatus::Running; - printf("Switching from thread %d to %d\n", currentThreadIndex, newThreadIndex); + logThread("Switching from thread %d to %d\n", currentThreadIndex, newThreadIndex); // Bail early if the new thread is actually the old thread if (currentThreadIndex == newThreadIndex) [[unlikely]] { @@ -70,8 +70,6 @@ std::optional Kernel::getNextThread() { if (canThreadRun(t)) { return index; } - - // TODO: Check timeouts here } // No thread was found diff --git a/src/core/PICA/renderer_opengl.cpp b/src/core/renderer_gl/renderer_gl.cpp similarity index 97% rename from src/core/PICA/renderer_opengl.cpp rename to src/core/renderer_gl/renderer_gl.cpp index 2c41dba5..5cd63dd1 100644 --- a/src/core/PICA/renderer_opengl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -191,8 +191,8 @@ void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) f24 depthOffset = f24::fromRaw(regs[PICAInternalRegs::DepthOffset] & 0xffffff); printf("Depth enable: %d, func: %d, writeEnable: %d\n", depthEnable, depthFunc, depthWriteEnable); - if (depthScale.toFloat32() != -1.0 || depthOffset.toFloat32() != 0.0) - Helpers::panic("TODO: Implement depth scale/offset. Remove the depth *= -1.0 from vertex shader"); + //if (depthScale.toFloat32() != -1.0 || depthOffset.toFloat32() != 0.0) + // Helpers::panic("TODO: Implement depth scale/offset. Remove the depth *= -1.0 from vertex shader"); // TODO: Actually use this float viewportWidth = f24::fromRaw(regs[PICAInternalRegs::ViewportWidth] & 0xffffff).toFloat32() * 2.0; From 57ef4e25e73a4a83dfc249d67fe43f77fe64b389 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sun, 1 Jan 2023 22:06:54 +0200 Subject: [PATCH 08/25] Separate renderer and PICA completely --- CMakeLists.txt | 2 +- include/PICA/gpu.hpp | 36 ++++++----------------- include/logger.hpp | 1 + include/renderer_gl/renderer_gl.hpp | 44 ++++++++++++++++++++++++++++ src/core/PICA/gpu.cpp | 6 ++-- src/core/renderer_gl/renderer_gl.cpp | 13 ++++---- 6 files changed, 65 insertions(+), 37 deletions(-) create mode 100644 include/renderer_gl/renderer_gl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 87f8a9ed..4a6a5648 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/loader/lz77.hpp include/fs/archive_base.hpp include/fs/archive_ncch.hpp include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp - include/services/mic.hpp include/services/cecd.hpp + include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index 7a80c633..32655035 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -3,9 +3,9 @@ #include "helpers.hpp" #include "logger.hpp" #include "memory.hpp" -#include "opengl.hpp" #include "PICA/float_types.hpp" #include "PICA/shader_unit.hpp" +#include "renderer_gl/renderer_gl.hpp" class GPU { using vec4f = OpenGL::Vector; @@ -20,11 +20,6 @@ class GPU { static constexpr u32 vramSize = 6_MB; std::array regs; // GPU internal registers - struct Vertex { - OpenGL::vec4 position; - OpenGL::vec4 colour; - }; - // Read a value of type T from physical address paddr // This is necessary because vertex attribute fetching uses physical addresses template @@ -80,32 +75,15 @@ class GPU { u32 fixedAttribCount = 0; // How many attribute components have we written? When we get to 4 the attr will actually get submitted std::array fixedAttrBuff; // Buffer to hold fixed attributes in until they get submitted - // OpenGL renderer state - OpenGL::Framebuffer fbo; - OpenGL::Texture fboTexture; - OpenGL::Program triangleProgram; - OpenGL::Program displayProgram; - - OpenGL::VertexArray vao; - OpenGL::VertexBuffer vbo; - GLint alphaControlLoc = -1; - u32 oldAlphaControl = 0; - - // Dummy VAO/VBO for blitting the final output - OpenGL::VertexArray dummyVAO; - OpenGL::VertexBuffer dummyVBO; - - static constexpr u32 vertexBufferSize = 0x1000; - void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count); + Renderer renderer; public: GPU(Memory& mem); - void initGraphicsContext(); // Initialize graphics context - void getGraphicsContext(); // Set up the graphics context for rendering - void display(); // Display the screen contents onto our window + void initGraphicsContext() { renderer.initGraphicsContext(); } + void getGraphicsContext() { renderer.getGraphicsContext(); } + void display() { renderer.display(); } void fireDMA(u32 dest, u32 source, u32 size); - void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); void reset(); // Used by the GSP GPU service for readHwRegs/writeHwRegs/writeHwRegsMasked @@ -115,4 +93,8 @@ public: // Used when processing GPU command lists u32 readInternalReg(u32 index); void writeInternalReg(u32 index, u32 value, u32 mask); + + void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { + renderer.clearBuffer(startAddress, endAddress, value, control); + } }; \ No newline at end of file diff --git a/include/logger.hpp b/include/logger.hpp index 5025bc44..cdcf2f2c 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -25,6 +25,7 @@ namespace Log { static Logger svcLogger; static Logger threadLogger; static Logger gpuLogger; + static Logger rendererLogger; // Service loggers static Logger aptLogger; diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp new file mode 100644 index 00000000..999272e3 --- /dev/null +++ b/include/renderer_gl/renderer_gl.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include "helpers.hpp" +#include "logger.hpp" +#include "opengl.hpp" + +struct Vertex { + OpenGL::vec4 position; + OpenGL::vec4 colour; +}; + +class Renderer { + // OpenGL renderer state + OpenGL::Framebuffer fbo; + OpenGL::Texture fboTexture; + OpenGL::Program triangleProgram; + OpenGL::Program displayProgram; + + OpenGL::VertexArray vao; + OpenGL::VertexBuffer vbo; + GLint alphaControlLoc = -1; + u32 oldAlphaControl = 0; + + // Dummy VAO/VBO for blitting the final output + OpenGL::VertexArray dummyVAO; + OpenGL::VertexBuffer dummyVBO; + + static constexpr u32 regNum = 0x300; // Number of internal PICA registers + const std::array& regs; + + MAKE_LOG_FUNCTION(log, rendererLogger) + +public: + Renderer(const std::array& internalRegs) : regs(internalRegs) {} + + void reset(); + void display(); // Display the 3DS screen contents to the window + void initGraphicsContext(); // Initialize graphics context + void getGraphicsContext(); // Set up graphics context for rendering + void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); // Clear a GPU buffer in VRAM + void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count); // Draw the given vertices + + static constexpr u32 vertexBufferSize = 0x1500; +}; \ No newline at end of file diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 3e02280f..0b7ad3d3 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -6,6 +6,7 @@ using namespace Floats; GPU::GPU(Memory& mem) : mem(mem) { +GPU::GPU(Memory& mem) : mem(mem), renderer(regs) { vram = new u8[vramSize]; } @@ -49,12 +50,13 @@ void GPU::drawArrays() { const u32 primType = (primConfig >> 8) & 3; if (primType != 0 && primType != 1) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType); if (vertexCount > vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize"); + if (vertexCount > Renderer::vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize"); if ((primType == 0 && vertexCount % 3) || (primType == 1 && vertexCount < 3)) { Helpers::panic("Invalid vertex count for primitive. Type: %d, vert count: %d\n", primType, vertexCount); } - Vertex vertices[vertexBufferSize]; + Vertex vertices[Renderer::vertexBufferSize]; // Get the configuration for the index buffer, used only for indexed drawing u32 indexBufferConfig = regs[PICAInternalRegs::IndexBufferConfig]; @@ -157,7 +159,7 @@ void GPU::drawArrays() { OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::LineStrip }; const auto shape = primTypes[primType]; - drawVertices(shape, vertices, vertexCount); + renderer.drawVertices(shape, vertices, vertexCount); } void GPU::fireDMA(u32 dest, u32 source, u32 size) { diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 5cd63dd1..a5c18d75 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -1,7 +1,6 @@ +#include "renderer_gl/renderer_gl.hpp" #include "PICA/float_types.hpp" -#include "PICA/gpu.hpp" #include "PICA/regs.hpp" -#include "opengl.hpp" using namespace Floats; @@ -106,7 +105,7 @@ const char* displayFragmentShader = R"( } )"; -void GPU::initGraphicsContext() { +void Renderer::initGraphicsContext() { // Set up texture for top screen fboTexture.create(400, 240, GL_RGBA8); fboTexture.bind(); @@ -159,7 +158,7 @@ void GPU::initGraphicsContext() { dummyVAO.create(); } -void GPU::getGraphicsContext() { +void Renderer::getGraphicsContext() { OpenGL::disableScissor(); OpenGL::setViewport(400, 240); fbo.bind(OpenGL::DrawAndReadFramebuffer); @@ -169,7 +168,7 @@ void GPU::getGraphicsContext() { triangleProgram.use(); } -void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { +void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { // Adjust alpha test if necessary const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig]; if (alphaControl != oldAlphaControl) { @@ -220,7 +219,7 @@ constexpr u32 topScreenBuffer = 0x1f000000; constexpr u32 bottomScreenBuffer = 0x1f05dc00; // Quick hack to display top screen for now -void GPU::display() { +void Renderer::display() { OpenGL::disableDepth(); OpenGL::disableScissor(); OpenGL::bindScreenFramebuffer(); @@ -234,7 +233,7 @@ void GPU::display() { OpenGL::draw(OpenGL::TriangleStrip, 4); } -void GPU::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { +void Renderer::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control); const float r = float((value >> 24) & 0xff) / 255.0; From ecbb33b906c98ebc36ced35150328c0c49bf61a1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 2 Jan 2023 15:01:17 +0200 Subject: [PATCH 09/25] [GPU] Surface cache vol 1 --- CMakeLists.txt | 2 + include/PICA/regs.hpp | 4 + include/renderer_gl/renderer_gl.hpp | 28 ++++++ include/renderer_gl/surface_cache.hpp | 62 +++++++++++++ include/renderer_gl/surfaces.hpp | 125 ++++++++++++++++++++++++++ src/core/PICA/regs.cpp | 25 ++++++ src/core/renderer_gl/renderer_gl.cpp | 30 +++++++ 7 files changed, 276 insertions(+) create mode 100644 include/renderer_gl/surface_cache.hpp create mode 100644 include/renderer_gl/surfaces.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a6a5648..d4be6caf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) include_directories(${PROJECT_SOURCE_DIR}/include/) include_directories(${PROJECT_SOURCE_DIR}/include/kernel) include_directories (${FMT_INCLUDE_DIR}) +include_directories(third_party/boost/) include_directories(third_party/elfio/) include_directories(third_party/gl3w/) include_directories(third_party/imgui/) @@ -79,6 +80,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp + include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/PICA/regs.hpp b/include/PICA/regs.hpp index 76112d4c..dff9c819 100644 --- a/include/PICA/regs.hpp +++ b/include/PICA/regs.hpp @@ -14,6 +14,10 @@ namespace PICAInternalRegs { // Framebuffer registers AlphaTestConfig = 0x104, DepthAndColorMask = 0x107, + ColourBufferFormat = 0x117, + DepthBufferLoc = 0x11C, + ColourBufferLoc = 0x11D, + FramebufferSize = 0x11E, // Geometry pipeline registers VertexAttribLoc = 0x200, diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 999272e3..6f55fdce 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -3,6 +3,7 @@ #include "helpers.hpp" #include "logger.hpp" #include "opengl.hpp" +#include "surface_cache.hpp" struct Vertex { OpenGL::vec4 position; @@ -21,6 +22,17 @@ class Renderer { GLint alphaControlLoc = -1; u32 oldAlphaControl = 0; + SurfaceCache depthBufferCache; + SurfaceCache colourBufferCache; + OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)' + + u32 colourBufferLoc; // Location in 3DS VRAM for the colour buffer + ColourBuffer::Formats colourBufferFormat; // Format of the colours stored in the colour buffer + + // Same for the depth/stencil buffer + u32 depthBufferLoc; + DepthBuffer::Formats depthBufferFormat; + // Dummy VAO/VBO for blitting the final output OpenGL::VertexArray dummyVAO; OpenGL::VertexBuffer dummyVBO; @@ -28,6 +40,8 @@ class Renderer { static constexpr u32 regNum = 0x300; // Number of internal PICA registers const std::array& regs; + OpenGL::Framebuffer getColourFBO(); + MAKE_LOG_FUNCTION(log, rendererLogger) public: @@ -40,5 +54,19 @@ public: void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); // Clear a GPU buffer in VRAM void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count); // Draw the given vertices + void setFBSize(u32 width, u32 height) { + fbSize.x() = width; + fbSize.y() = height; + } + + void setColourFormat(ColourBuffer::Formats format) { colourBufferFormat = format; } + void setColourFormat(u32 format) { colourBufferFormat = static_cast(format); } + + void setDepthFormat(DepthBuffer::Formats format) { depthBufferFormat = format; } + void setDepthFormat(u32 format) { depthBufferFormat = static_cast(format); } + + void setColourBufferLoc(u32 loc) { colourBufferLoc = loc; } + void setDepthBufferLoc(u32 loc) { depthBufferLoc = loc; } + static constexpr u32 vertexBufferSize = 0x1500; }; \ No newline at end of file diff --git a/include/renderer_gl/surface_cache.hpp b/include/renderer_gl/surface_cache.hpp new file mode 100644 index 00000000..b7508a36 --- /dev/null +++ b/include/renderer_gl/surface_cache.hpp @@ -0,0 +1,62 @@ +#pragma once +#include +#include +#include "surfaces.hpp" + +// Surface cache class that can fit "capacity" instances of the "SurfaceType" class of surfaces +// SurfaceType *must* have all of the following +// - An "allocate" function that allocates GL resources for the surfaces +// - A "free" function that frees up all resources the surface is taking up +// - A "matches" function that, when provided with a SurfaceType object reference +// Will tell us if the 2 surfaces match (Only as far as location in VRAM, format, dimensions, etc) +// Are concerned. We could overload the == operator, but that implies full equality +// Including equality of the allocated OpenGL resources, which we don't want +// - A "valid" member that tells us whether the function is still valid or not +template +class SurfaceCache { + // Vanilla std::optional can't hold actual references + using OptionalRef = std::optional>; + static_assert(std::is_same() || std::is_same(), + "Invalid surface type"); + + size_t size; + std::array buffer; + +public: + void reset() { + size = 0; + for (auto& e : buffer) { // Free the VRAM of all surfaces + e.free(); + } + } + + OptionalRef find(SurfaceType& other) { + for (auto& e : buffer) { + if (e.matches(other) && e.valid) + return e; + } + + return std::nullopt; + } + + // Adds a surface object to the cache and returns it + SurfaceType add(SurfaceType& surface) { + if (size >= capacity) { + Helpers::panic("Surface cache full! Add emptying!"); + } + size++; + + // Find an invalid entry in the cache and overwrite it with the new surface + for (auto& e : buffer) { + if (!e.valid) { + e = surface; + e.allocate(); + Sleep(2000); + return e; + } + } + + // This should be unreachable but helps to panic anyways + Helpers::panic("Couldn't add surface to cache\n"); + } +}; diff --git a/include/renderer_gl/surfaces.hpp b/include/renderer_gl/surfaces.hpp new file mode 100644 index 00000000..e88acf1d --- /dev/null +++ b/include/renderer_gl/surfaces.hpp @@ -0,0 +1,125 @@ +#pragma once +#include "boost/icl/interval.hpp" +#include "helpers.hpp" +#include "opengl.hpp" + +template +using Interval = boost::icl::right_open_interval; + +struct ColourBuffer { + enum class Formats : u32 { + RGBA8 = 0, + BGR8 = 1, + RGB5A1 = 2, + RGB565 = 3, + RGBA4 = 4, + + Trash1 = 5, Trash2 = 6, Trash3 = 7 // Technically selectable, but their function is unknown + }; + + u32 location; + Formats format; + OpenGL::uvec2 size; + bool valid; + + // Range of VRAM taken up by buffer + Interval range; + // OpenGL resources allocated to buffer + OpenGL::Texture texture; + OpenGL::Framebuffer fbo; + + ColourBuffer() : valid(false) {} + + ColourBuffer(u32 loc, Formats format, u32 x, u32 y, bool valid = true) + : location(loc), format(format), size({x, y}), valid(valid) { + + u64 endLoc = (u64)loc + sizeInBytes(); + // Check if start and end are valid here + range = Interval(loc, (u32)endLoc); + } + + void allocate() { + printf("Make this colour buffer allocate itself\n"); + } + + void free() { + valid = false; + printf("Make this colour buffer free itself\n"); + } + + bool matches(ColourBuffer& other) { + return location == other.location && format == other.format && + size.x() == other.size.x() && size.y() == other.size.y(); + } + + // Size occupied by each pixel in bytes + // All formats are 16BPP except for RGBA8 (32BPP) and BGR8 (24BPP) + size_t sizePerPixel() { + switch (format) { + case Formats::BGR8: return 3; + case Formats::RGBA8: return 4; + default: return 2; + } + } + + size_t sizeInBytes() { + return (size_t)size.x() * (size_t)size.y() * sizePerPixel(); + } +}; + +struct DepthBuffer { + enum class Formats : u32 { + Depth16 = 0, + Garbage = 1, + Depth24 = 2, + Depth24Stencil8 = 3 + }; + + u32 location; + Formats format; + OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer + bool valid; + + // Range of VRAM taken up by buffer + Interval range; + // OpenGL texture used for storing depth/stencil + OpenGL::Texture texture; + + DepthBuffer() : valid(false) {} + + DepthBuffer(u32 loc, Formats format, u32 x, u32 y, bool valid = true) : + location(loc), format(format), size({x, y}), valid(valid) {} + + bool hasStencil() { + return format == Formats::Depth24Stencil8; + } + + void allocate() { + printf("Make this depth buffer allocate itself\n"); + } + + void free() { + valid = false; + printf("Make this depth buffer free itself\n"); + } + + bool matches(DepthBuffer& other) { + return location == other.location && format == other.format && + size.x() == other.size.x() && size.y() == other.size.y(); + } + + // Size occupied by each pixel in bytes + size_t sizePerPixel() { + switch (format) { + case Formats::Depth16: return 2; + case Formats::Depth24: return 3; + case Formats::Depth24Stencil8: return 4; + + default: return 1; // Invalid format + } + } + + size_t sizeInBytes() { + return (size_t)size.x() * (size_t)size.y() * sizePerPixel(); + } +}; \ No newline at end of file diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 10ae9b46..cfd0c6d0 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -59,6 +59,31 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { fixedAttribMask = (value >> 16) & 0xfff; // Determines which vertex attributes are fixed for all vertices break; + case ColourBufferLoc: { + u32 loc = (value & 0x0fffffff) << 3; + renderer.setColourBufferLoc(loc); + break; + }; + + case ColourBufferFormat: { + u32 format = (value >> 16) & 7; + renderer.setColourFormat(format); + break; + } + + case DepthBufferLoc: { + u32 loc = (value & 0x0fffffff) << 3; + renderer.setDepthBufferLoc(loc); + break; + } + + case FramebufferSize: { + const u32 width = value & 0x7ff; + const u32 height = ((value >> 12) & 0x3ff) + 1; + renderer.setFBSize(width, height); + break; + } + case VertexFloatUniformIndex: shaderUnit.vs.setFloatUniformIndex(value); break; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index a5c18d75..8d493620 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -105,6 +105,18 @@ const char* displayFragmentShader = R"( } )"; +void Renderer::reset() { + depthBufferCache.reset(); + colourBufferCache.reset(); + + // Init the colour/depth buffer settings to some random defaults on reset + colourBufferLoc = 0; + colourBufferFormat = ColourBuffer::Formats::RGBA8; + + depthBufferLoc = 0; + depthBufferFormat = DepthBuffer::Formats::Depth16; +} + void Renderer::initGraphicsContext() { // Set up texture for top screen fboTexture.create(400, 240, GL_RGBA8); @@ -156,6 +168,7 @@ void Renderer::initGraphicsContext() { dummyVBO.create(); dummyVAO.create(); + reset(); } void Renderer::getGraphicsContext() { @@ -168,6 +181,8 @@ void Renderer::getGraphicsContext() { triangleProgram.use(); } +OpenGL::Framebuffer poop; + void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { // Adjust alpha test if necessary const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig]; @@ -176,6 +191,8 @@ void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 c glUniform1ui(alphaControlLoc, alphaControl); } + poop = getColourFBO(); + const u32 depthControl = regs[PICAInternalRegs::DepthAndColorMask]; bool depthEnable = depthControl & 1; bool depthWriteEnable = (depthControl >> 12) & 1; @@ -252,4 +269,17 @@ void Renderer::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 cont OpenGL::setClearColor(r, g, b, a); OpenGL::clearColor(); +} + +OpenGL::Framebuffer Renderer::getColourFBO() { + //We construct a colour buffer object and see if our cache has any matching colour buffers in it + // If not, we allocate a texture & FBO for our framebuffer and store it in the cache + ColourBuffer sampleBuffer(colourBufferLoc, colourBufferFormat, fbSize.x(), fbSize.y()); + auto buffer = colourBufferCache.find(sampleBuffer); + + if (buffer.has_value()) { + return buffer.value().get().fbo; + } else { + return colourBufferCache.add(sampleBuffer).fbo; + } } \ No newline at end of file From e9217722f15f2286aa88cc1133f993eb4a2d0a46 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 2 Jan 2023 15:01:46 +0200 Subject: [PATCH 10/25] oops --- src/core/PICA/gpu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index 0b7ad3d3..c9e22190 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -5,7 +5,6 @@ using namespace Floats; -GPU::GPU(Memory& mem) : mem(mem) { GPU::GPU(Memory& mem) : mem(mem), renderer(regs) { vram = new u8[vramSize]; } @@ -28,7 +27,7 @@ void GPU::reset() { e.config2 = 0; } - // TODO: Reset blending, texturing, etc here + renderer.reset(); } void GPU::drawArrays(bool indexed) { From 9d741ba17783040f005702f88def3f13633ec449 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 2 Jan 2023 20:06:40 +0200 Subject: [PATCH 11/25] Add SurfaceCache::operator[] --- include/renderer_gl/surface_cache.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/renderer_gl/surface_cache.hpp b/include/renderer_gl/surface_cache.hpp index b7508a36..8523e7fb 100644 --- a/include/renderer_gl/surface_cache.hpp +++ b/include/renderer_gl/surface_cache.hpp @@ -51,7 +51,6 @@ public: if (!e.valid) { e = surface; e.allocate(); - Sleep(2000); return e; } } @@ -59,4 +58,8 @@ public: // This should be unreachable but helps to panic anyways Helpers::panic("Couldn't add surface to cache\n"); } + + SurfaceType& operator[](size_t i) { + return buffer[i]; + } }; From 1b7c38e27ff7c50fdfa4812c674953d59325956f Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 2 Jan 2023 23:35:34 +0200 Subject: [PATCH 12/25] [OpenGL] Better deallocation scheme --- include/opengl.hpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/include/opengl.hpp b/include/opengl.hpp index 07ecc9f0..f91471e8 100644 --- a/include/opengl.hpp +++ b/include/opengl.hpp @@ -30,6 +30,9 @@ #include "gl3w.h" +// Uncomment the following define if you want GL objects to automatically free themselves when their lifetime ends +// #define OPENGL_DESTRUCTORS + namespace OpenGL { // Workaround for using static_assert inside constexpr if @@ -51,7 +54,9 @@ namespace OpenGL { } } - ~VertexArray() { glDeleteVertexArrays(1, &m_handle); } +#ifdef OPENGL_DESTRUCTORS + ~VertexArray() { free(); } +#endif GLuint handle() { return m_handle; } bool exists() { return m_handle != 0; } void bind() { glBindVertexArray(m_handle); } @@ -121,6 +126,10 @@ namespace OpenGL { void enableAttribute(GLuint index) { glEnableVertexAttribArray(index); } void disableAttribute(GLuint index) { glDisableVertexAttribArray(index); } + + void free() { + glDeleteVertexArrays(1, &m_handle); + } }; enum FramebufferTypes { @@ -165,12 +174,16 @@ namespace OpenGL { create(width, height, internalFormat, GL_TEXTURE_2D_MULTISAMPLE, samples); } - ~Texture() { glDeleteTextures(1, &m_handle); } +#ifdef OPENGL_DESTRUCTORS + ~Texture() { free(); } +#endif GLuint handle() { return m_handle; } bool exists() { return m_handle != 0; } void bind() { glBindTexture(m_binding, m_handle); } int width() { return m_width; } int height() { return m_height; } + + void free() { glDeleteTextures(1, &m_handle); } }; struct Framebuffer { @@ -189,11 +202,14 @@ namespace OpenGL { } } - ~Framebuffer() { glDeleteFramebuffers(1, &m_handle); } +#ifdef OPENGL_DESTRUCTORS + ~Framebuffer() { free(); } +#endif GLuint handle() { return m_handle; } bool exists() { return m_handle != 0; } void bind(GLenum target) { glBindFramebuffer(target, m_handle); } void bind(FramebufferTypes target) { bind(static_cast(target)); } + void free() { glDeleteFramebuffers(1, &m_handle); } void createWithTexture(Texture& tex, GLenum mode = GL_FRAMEBUFFER, GLenum textureType = GL_TEXTURE_2D) { m_textureType = textureType; @@ -313,10 +329,13 @@ namespace OpenGL { } } - ~VertexBuffer() { glDeleteBuffers(1, &m_handle); } +#ifdef OPENGL_DESTRUCTORS + ~VertexBuffer() { free(); } +#endif GLuint handle() { return m_handle; } bool exists() { return m_handle != 0; } void bind() { glBindBuffer(GL_ARRAY_BUFFER, m_handle); } + void free() { glDeleteBuffers(1, &m_handle); } // Reallocates the buffer on every call. Prefer the sub version if possible. template From 684fda077174a1245a6bd633f89c2451ec347236 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Tue, 3 Jan 2023 01:32:50 +0200 Subject: [PATCH 13/25] [Kernel] Implement SyscoreVer --- include/kernel/config_mem.hpp | 1 + src/core/memory.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/kernel/config_mem.hpp b/include/kernel/config_mem.hpp index 541bf9bd..397e84a2 100644 --- a/include/kernel/config_mem.hpp +++ b/include/kernel/config_mem.hpp @@ -6,6 +6,7 @@ namespace ConfigMem { enum : u32 { KernelVersionMinor = 0x1FF80002, KernelVersionMajor = 0x1FF80003, + SyscoreVer = 0x1FF80010, EnvInfo = 0x1FF80014, AppMemAlloc = 0x1FF80040, Datetime0 = 0x1FF81020, diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 12ebeeaf..464ab1f7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -115,6 +115,7 @@ u32 Memory::read32(u32 vaddr) { return 0; // Set to 0 by PTM case ConfigMem::AppMemAlloc: return appResourceLimits.maxCommit; + case ConfigMem::SyscoreVer: return 2; case 0x1FF81000: return 0; // TODO: Figure out what this config mem address does default: if (vaddr >= VirtualAddrs::VramStart && vaddr < VirtualAddrs::VramStart + VirtualAddrs::VramSize) { From 9396b1ec9c70ead9c60298e1350cea72cbd3d764 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Tue, 3 Jan 2023 19:27:56 +0200 Subject: [PATCH 14/25] [APT] Fix initialize --- src/core/services/apt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 6cd3ce1e..2b7da987 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -96,7 +96,7 @@ void APTService::initialize(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event Handle - mem.write32(messagePointer + 12, resumeEvent.value()); // Resume Event Handle + mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event Handle } void APTService::getLockHandle(u32 messagePointer) { From 70dd8b2e9d35a2a77a324538aa1dfef0047ab552 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Tue, 3 Jan 2023 22:02:12 +0200 Subject: [PATCH 15/25] [APT] Add inquireNotification/setScreencapPermission --- include/services/apt.hpp | 19 +++++++++++++++++++ src/core/services/apt.cpp | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/services/apt.hpp b/include/services/apt.hpp index f5356058..6c6c5fb4 100644 --- a/include/services/apt.hpp +++ b/include/services/apt.hpp @@ -27,14 +27,33 @@ class APTService { void checkNew3DSApp(u32 messagePointer); void enable(u32 messagePointer); void initialize(u32 messagePointer); + void inquireNotification(u32 messagePointer); void notifyToWait(u32 messagePointer); void receiveParameter(u32 messagePointer); void replySleepQuery(u32 messagePointer); void setApplicationCpuTimeLimit(u32 messagePointer); + void setScreencapPostPermission(u32 messagePointer); // Percentage of the syscore available to the application, between 5% and 89% u32 cpuTimeLimit; + enum class NotificationType : u32 { + None = 0, + HomeButton1 = 1, + HomeButton2 = 2, + SleepQuery = 3, + SleepCanceledByOpen = 4, + SleepAccepted = 5, + SleepAwake = 6, + Shutdown = 7, + PowerButtonClick = 8, + PowerButtonClear = 9, + TrySleep = 10, + OrderToClose = 11 + }; + + u32 screencapPostPermission; + public: APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} void reset(); diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 2b7da987..1a38f643 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -6,12 +6,14 @@ namespace APTCommands { GetLockHandle = 0x00010040, Initialize = 0x00020080, Enable = 0x00030040, + InquireNotification = 0x000B0040, ReceiveParameter = 0x000D0080, ReplySleepQuery = 0x003E0080, NotifyToWait = 0x00430040, AppletUtility = 0x004B00C2, SetApplicationCpuTimeLimit = 0x004F0080, GetApplicationCpuTimeLimit = 0x00500040, + SetScreencapPostPermission = 0x00550040, CheckNew3DSApp = 0x01010000, CheckNew3DS = 0x01020000 }; @@ -49,12 +51,14 @@ void APTService::handleSyncRequest(u32 messagePointer) { case APTCommands::CheckNew3DSApp: checkNew3DSApp(messagePointer); break; case APTCommands::Enable: enable(messagePointer); break; case APTCommands::Initialize: initialize(messagePointer); break; + case APTCommands::InquireNotification: inquireNotification(messagePointer); break; case APTCommands::GetApplicationCpuTimeLimit: getApplicationCpuTimeLimit(messagePointer); break; case APTCommands::GetLockHandle: getLockHandle(messagePointer); break; case APTCommands::NotifyToWait: notifyToWait(messagePointer); break; case APTCommands::ReceiveParameter: receiveParameter(messagePointer); break; case APTCommands::ReplySleepQuery: replySleepQuery(messagePointer); break; case APTCommands::SetApplicationCpuTimeLimit: setApplicationCpuTimeLimit(messagePointer); break; + case APTCommands::SetScreencapPostPermission: setScreencapPostPermission(messagePointer); break; default: Helpers::panic("APT service requested. Command: %08X\n", command); } } @@ -99,6 +103,13 @@ void APTService::initialize(u32 messagePointer) { mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event Handle } +void APTService::inquireNotification(u32 messagePointer) { + log("APT::InquireNotification\n"); + + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, static_cast(NotificationType::None)); +} + void APTService::getLockHandle(u32 messagePointer) { log("APT::GetLockHandle\n"); @@ -159,4 +170,13 @@ void APTService::getApplicationCpuTimeLimit(u32 messagePointer) { log("APT::GetApplicationCpuTimeLimit\n"); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, cpuTimeLimit); +} + +void APTService::setScreencapPostPermission(u32 messagePointer) { + u32 perm = mem.read32(messagePointer + 4); + log("APT::SetScreencapPostPermission (perm = %d)\n"); + + // Apparently only 1-3 are valid values, but I see 0 used in some games like Pokemon Rumble + mem.write32(messagePointer, Result::Success); + screencapPostPermission = perm; } \ No newline at end of file From 3ce9dc1d7bf4c4dbe6dc2fb6d53023da11606d17 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Thu, 5 Jan 2023 20:41:09 +0200 Subject: [PATCH 16/25] Surface cachin' again --- include/renderer_gl/renderer_gl.hpp | 3 --- include/renderer_gl/surfaces.hpp | 31 +++++++++++++++++++++-- src/core/renderer_gl/renderer_gl.cpp | 37 ++++++---------------------- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 6f55fdce..072f0d11 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -11,9 +11,6 @@ struct Vertex { }; class Renderer { - // OpenGL renderer state - OpenGL::Framebuffer fbo; - OpenGL::Texture fboTexture; OpenGL::Program triangleProgram; OpenGL::Program displayProgram; diff --git a/include/renderer_gl/surfaces.hpp b/include/renderer_gl/surfaces.hpp index e88acf1d..93ccd839 100644 --- a/include/renderer_gl/surfaces.hpp +++ b/include/renderer_gl/surfaces.hpp @@ -39,12 +39,39 @@ struct ColourBuffer { } void allocate() { - printf("Make this colour buffer allocate itself\n"); + // Create texture for the FBO, setting up filters and the like + // Reading back the current texture is slow, but allocate calls should be and far between. + // If this becomes a bottleneck, we can fix it semi-easily + auto prevTexture = OpenGL::getTex2D(); + texture.create(size.x(), size.y(), GL_RGBA8); + texture.bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, prevTexture); + + //Helpers::panic("Creating FBO: %d, %d\n", size.x(), size.y()); + + fbo.createWithDrawTexture(texture); + fbo.bind(OpenGL::DrawAndReadFramebuffer); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + Helpers::panic("Incomplete framebuffer"); + //glBindRenderbuffer(GL_RENDERBUFFER, 0); + + // TODO: This should not clear the framebuffer contents. It should load them from VRAM. + GLint oldViewport[4]; + glGetIntegerv(GL_VIEWPORT, oldViewport); + OpenGL::setViewport(size.x(), size.y()); + OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0); + OpenGL::clearColor(); + OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); } void free() { valid = false; - printf("Make this colour buffer free itself\n"); + + if (texture.exists() || fbo.exists()) + Helpers::panic("Make this buffer free itself"); } bool matches(ColourBuffer& other) { diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 8d493620..48c66ad4 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -118,30 +118,6 @@ void Renderer::reset() { } void Renderer::initGraphicsContext() { - // Set up texture for top screen - fboTexture.create(400, 240, GL_RGBA8); - fboTexture.bind(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - - fbo.createWithDrawTexture(fboTexture); - fbo.bind(OpenGL::DrawAndReadFramebuffer); - - GLuint rbo; - glGenRenderbuffers(1, &rbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 400, 240); // use a single renderbuffer object for both a depth AND stencil buffer. - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - Helpers::panic("Incomplete framebuffer"); - //glBindRenderbuffer(GL_RENDERBUFFER, 0); - - OpenGL::setViewport(400, 240); - OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0); - OpenGL::clearColor(); - OpenGL::Shader vert(vertexShader, OpenGL::Vertex); OpenGL::Shader frag(fragmentShader, OpenGL::Fragment); triangleProgram.create({ vert, frag }); @@ -174,15 +150,12 @@ void Renderer::initGraphicsContext() { void Renderer::getGraphicsContext() { OpenGL::disableScissor(); OpenGL::setViewport(400, 240); - fbo.bind(OpenGL::DrawAndReadFramebuffer); vbo.bind(); vao.bind(); triangleProgram.use(); } -OpenGL::Framebuffer poop; - void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { // Adjust alpha test if necessary const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig]; @@ -191,7 +164,8 @@ void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 c glUniform1ui(alphaControlLoc, alphaControl); } - poop = getColourFBO(); + OpenGL::Framebuffer poop = getColourFBO(); + poop.bind(OpenGL::DrawAndReadFramebuffer); const u32 depthControl = regs[PICAInternalRegs::DepthAndColorMask]; bool depthEnable = depthControl & 1; @@ -239,18 +213,21 @@ constexpr u32 bottomScreenBuffer = 0x1f05dc00; void Renderer::display() { OpenGL::disableDepth(); OpenGL::disableScissor(); + OpenGL::bindScreenFramebuffer(); - fboTexture.bind(); + colourBufferCache[0].texture.bind(); + displayProgram.use(); dummyVAO.bind(); - OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0); // Clear screen colour + OpenGL::setClearColor(0.0, 0.0, 1.0, 1.0); // Clear screen colour OpenGL::clearColor(); OpenGL::setViewport(0, 240, 400, 240); // Actually draw our 3DS screen OpenGL::draw(OpenGL::TriangleStrip, 4); } void Renderer::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { + return; log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control); const float r = float((value >> 24) & 0xff) / 255.0; From 400db8ef0a002b2ccc6c5b24411ee9217e73a8ca Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Thu, 5 Jan 2023 21:10:35 +0200 Subject: [PATCH 17/25] [APT] Some hacks --- src/core/kernel/events.cpp | 3 ++- src/core/services/apt.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/kernel/events.cpp b/src/core/kernel/events.cpp index 3c12ee2c..b74b5536 100644 --- a/src/core/kernel/events.cpp +++ b/src/core/kernel/events.cpp @@ -37,7 +37,7 @@ void Kernel::clearEvent() { logSVC("ClearEvent(event handle = %X)\n", handle); if (event == nullptr) [[unlikely]] { - Helpers::panic("Tried to clear non-existent event"); + Helpers::panic("Tried to clear non-existent event (handle = %X)", handle); regs[0] = SVCResult::BadHandle; return; } @@ -154,6 +154,7 @@ void Kernel::waitSynchronizationN() { } regs[0] = SVCResult::Success; + regs[1] = waitAll ? handleCount - 1 : 0; // Index of the handle that triggered the exit. STUBBED t.status = ThreadStatus::WaitSyncAll; t.waitAll = waitAll; t.outPointer = outPointer; diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 1a38f643..24e41a17 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -104,9 +104,12 @@ void APTService::initialize(u32 messagePointer) { } void APTService::inquireNotification(u32 messagePointer) { - log("APT::InquireNotification\n"); + log("APT::InquireNotification (STUBBED TO FAIL)\n"); - mem.write32(messagePointer + 4, Result::Success); + // Thanks to our silly WaitSynchronization hacks, sometimes games will switch to the APT thread without actually getting a notif + // After REing the APT code, I figured that making InquireNotification fail is one way of making games not crash when this happens + // We should fix this in the future, when the sync object implementation is less hacky. + mem.write32(messagePointer + 4, Result::Failure); mem.write32(messagePointer + 8, static_cast(NotificationType::None)); } From 94fe205c484af53aa995c69192625fd4e5799083 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Thu, 5 Jan 2023 21:41:52 +0200 Subject: [PATCH 18/25] [AC] Add service + SetClientVersion --- CMakeLists.txt | 3 ++- include/kernel/handles.hpp | 3 ++- include/services/ac.hpp | 19 +++++++++++++++++ include/services/cecd.hpp | 2 +- include/services/service_manager.hpp | 2 ++ src/core/services/ac.cpp | 30 +++++++++++++++++++++++++++ src/core/services/service_manager.cpp | 8 +++++-- 7 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 include/services/ac.hpp create mode 100644 src/core/services/ac.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4be6caf..877af0ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/fs.cpp src/core/services/gsp_gpu.cpp src/core/services/gsp_lcd.cpp src/core/services/ndm.cpp src/core/services/dsp.cpp src/core/services/cfg.cpp src/core/services/ptm.cpp src/core/services/mic.cpp src/core/services/cecd.cpp + src/core/services/ac.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp @@ -80,7 +81,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp - include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp + include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index 890d0318..d38c4e55 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -10,6 +10,7 @@ namespace KernelHandles { // Hardcoded handles CurrentThread = 0xFFFF8000, // Used by the original kernel CurrentProcess = 0xFFFF8001, // Used by the original kernel + AC, APT, // App Title something service? CECD, // Streetpass stuff? CFG, // CFG service (Console & region info) @@ -22,7 +23,7 @@ namespace KernelHandles { NDM, // ????? PTM, // PTM service (Used for accessing various console info, such as battery, shell and pedometer state) - MinServiceHandle = APT, + MinServiceHandle = AC, MaxServiceHandle = PTM, GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory diff --git a/include/services/ac.hpp b/include/services/ac.hpp new file mode 100644 index 00000000..2053ea21 --- /dev/null +++ b/include/services/ac.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" + +class ACService { + Handle handle = KernelHandles::AC; + Memory& mem; + MAKE_LOG_FUNCTION(log, acLogger) + + // Service commands + void setClientVersion(u32 messagePointer); + +public: + ACService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/cecd.hpp b/include/services/cecd.hpp index 53c30b59..3a592a32 100644 --- a/include/services/cecd.hpp +++ b/include/services/cecd.hpp @@ -9,7 +9,7 @@ class CECDService { Memory& mem; MAKE_LOG_FUNCTION(log, cecdLogger) - // Service commands + // Service commands public: CECDService(Memory& mem) : mem(mem) {} diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index d9903372..51b49710 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -4,6 +4,7 @@ #include "kernel_types.hpp" #include "logger.hpp" #include "memory.hpp" +#include "services/ac.hpp" #include "services/apt.hpp" #include "services/cecd.hpp" #include "services/cfg.hpp" @@ -28,6 +29,7 @@ class ServiceManager { MAKE_LOG_FUNCTION(log, srvLogger) + ACService ac; APTService apt; CECDService cecd; CFGService cfg; diff --git a/src/core/services/ac.cpp b/src/core/services/ac.cpp new file mode 100644 index 00000000..cc1e3bd5 --- /dev/null +++ b/src/core/services/ac.cpp @@ -0,0 +1,30 @@ +#include "services/ac.hpp" + +namespace ACCommands { + enum : u32 { + SetClientVersion = 0x00400042 + }; +} + +namespace Result { + enum : u32 { + Success = 0, + }; +} + +void ACService::reset() {} + +void ACService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + case ACCommands::SetClientVersion: setClientVersion(messagePointer); break; + default: Helpers::panic("AC service requested. Command: %08X\n", command); + } +} + +void ACService::setClientVersion(u32 messagePointer) { + u32 version = mem.read32(messagePointer + 4); + log("AC::SetClientVersion (version = %d)\n", version); + + mem.write32(messagePointer + 4, Result::Success); +} \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index d27e6ce1..b3ebe6e6 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -2,12 +2,13 @@ #include "kernel.hpp" ServiceManager::ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) - : regs(regs), mem(mem), kernel(kernel), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem), + : regs(regs), mem(mem), kernel(kernel), ac(mem), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} static constexpr int MAX_NOTIFICATION_COUNT = 16; void ServiceManager::reset() { + ac.reset(); apt.reset(); cecd.reset(); cfg.reset(); @@ -79,7 +80,9 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { std::string service = mem.readString(messagePointer + 4, 8); log("srv::getServiceHandle (Service: %s, nameLength: %d, flags: %d)\n", service.c_str(), nameLength, flags); - if (service == "APT:S") { // TODO: APT:A, APT:S and APT:U are slightly different + if (service == "ac:u") { + handle = KernelHandles::AC; + } else if (service == "APT:S") { // TODO: APT:A, APT:S and APT:U are slightly different handle = KernelHandles::APT; } else if (service == "APT:A") { handle = KernelHandles::APT; @@ -136,6 +139,7 @@ void ServiceManager::receiveNotification(u32 messagePointer) { void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { switch (handle) { + case KernelHandles::AC: ac.handleSyncRequest(messagePointer); break; case KernelHandles::APT: apt.handleSyncRequest(messagePointer); break; case KernelHandles::CECD: cecd.handleSyncRequest(messagePointer); break; case KernelHandles::CFG: cfg.handleSyncRequest(messagePointer); break; From 9f07286de876fd5a9582178407b7e732d05f1f90 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Thu, 5 Jan 2023 22:23:05 +0200 Subject: [PATCH 19/25] Add FRD service --- CMakeLists.txt | 3 +- include/kernel/handles.hpp | 3 +- include/logger.hpp | 2 + include/services/frd.hpp | 21 ++++++++++ include/services/service_manager.hpp | 2 + src/core/services/frd.cpp | 56 +++++++++++++++++++++++++++ src/core/services/service_manager.cpp | 8 +++- 7 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 include/services/frd.hpp create mode 100644 src/core/services/frd.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 877af0ae..77bd20b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/fs.cpp src/core/services/gsp_gpu.cpp src/core/services/gsp_lcd.cpp src/core/services/ndm.cpp src/core/services/dsp.cpp src/core/services/cfg.cpp src/core/services/ptm.cpp src/core/services/mic.cpp src/core/services/cecd.cpp - src/core/services/ac.cpp + src/core/services/ac.cpp src/core/services/frd.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp @@ -82,6 +82,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp + include/services/frd.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index d38c4e55..2bcc3d57 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -10,11 +10,12 @@ namespace KernelHandles { // Hardcoded handles CurrentThread = 0xFFFF8000, // Used by the original kernel CurrentProcess = 0xFFFF8001, // Used by the original kernel - AC, + AC, // Something network related APT, // App Title something service? CECD, // Streetpass stuff? CFG, // CFG service (Console & region info) HID, // HID service (Handles everything input-related including gyro) + FRD, // Friend service (Miiverse friend service) FS, // Filesystem service GPU, // GPU service DSP, // DSP service (Used for audio decoding and output) diff --git a/include/logger.hpp b/include/logger.hpp index cdcf2f2c..f83aaace 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -28,10 +28,12 @@ namespace Log { static Logger rendererLogger; // Service loggers + static Logger acLogger; static Logger aptLogger; static Logger cecdLogger; static Logger cfgLogger; static Logger dspServiceLogger; + static Logger frdLogger; static Logger fsLogger; static Logger hidLogger; static Logger gspGPULogger; diff --git a/include/services/frd.hpp b/include/services/frd.hpp new file mode 100644 index 00000000..c33aeb5b --- /dev/null +++ b/include/services/frd.hpp @@ -0,0 +1,21 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" + +class FRDService { + Handle handle = KernelHandles::FRD; + Memory& mem; + MAKE_LOG_FUNCTION(log, frdLogger) + + // Service commands + void getMyFriendKey(u32 messagePointer); + void getMyPresence(u32 messagePointer); + void setClientSDKVersion(u32 messagePointer); + +public: + FRDService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 51b49710..91f3b8be 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -10,6 +10,7 @@ #include "services/cfg.hpp" #include "services/dsp.hpp" #include "services/hid.hpp" +#include "services/frd.hpp" #include "services/fs.hpp" #include "services/gsp_gpu.hpp" #include "services/gsp_lcd.hpp" @@ -35,6 +36,7 @@ class ServiceManager { CFGService cfg; DSPService dsp; HIDService hid; + FRDService frd; FSService fs; GPUService gsp_gpu; LCDService gsp_lcd; diff --git a/src/core/services/frd.cpp b/src/core/services/frd.cpp new file mode 100644 index 00000000..cb93b06d --- /dev/null +++ b/src/core/services/frd.cpp @@ -0,0 +1,56 @@ +#include "services/frd.hpp" + +namespace FRDCommands { + enum : u32 { + SetClientSdkVersion = 0x00320042, + GetMyFriendKey = 0x00050000, + GetMyPresence = 0x00080000 + }; +} + +namespace Result { + enum : u32 { + Success = 0, + }; +} + +void FRDService::reset() {} + +void FRDService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + case FRDCommands::GetMyFriendKey: getMyFriendKey(messagePointer); break; + case FRDCommands::GetMyPresence: getMyPresence(messagePointer); break; + case FRDCommands::SetClientSdkVersion: setClientSDKVersion(messagePointer); break; + default: Helpers::panic("FRD service requested. Command: %08X\n", command); + } +} + +void FRDService::getMyFriendKey(u32 messagePointer) { + log("FRD::GetMyFriendKey"); + + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // Principal ID + mem.write32(messagePointer + 12, 0); // Padding (?) + mem.write32(messagePointer + 16, 0); // Local friend code + mem.write32(messagePointer + 20, 0); +} + +void FRDService::getMyPresence(u32 messagePointer) { + static constexpr u32 presenceSize = 0x12C; // A presence seems to be 12C bytes of data, not sure what it contains + log("FRD::GetMyPresence\n"); + u32 buffer = mem.read32(messagePointer + 0x104); // Buffer to write presence info to. + + for (u32 i = 0; i < presenceSize; i += 4) { // Clear presence info with 0s for now + mem.write32(buffer + i, 0); + } + + mem.write32(messagePointer + 4, Result::Success); +} + +void FRDService::setClientSDKVersion(u32 messagePointer) { + u32 version = mem.read32(messagePointer + 4); + log("FRD::SetClientSdkVersion (version = %d)\n", version); + + mem.write32(messagePointer + 4, Result::Success); +} \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index b3ebe6e6..f079d9c4 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -3,7 +3,7 @@ ServiceManager::ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) : regs(regs), mem(mem), kernel(kernel), ac(mem), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem), - fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} + frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} static constexpr int MAX_NOTIFICATION_COUNT = 16; @@ -14,6 +14,7 @@ void ServiceManager::reset() { cfg.reset(); dsp.reset(); hid.reset(); + frd.reset(); fs.reset(); gsp_gpu.reset(); gsp_lcd.reset(); @@ -96,7 +97,9 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { handle = KernelHandles::DSP; } else if (service == "hid:USER") { handle = KernelHandles::HID; - } else if (service == "fs:USER") { + } else if (service == "frd:u") { + handle = KernelHandles::FRD; + } else if (service == "fs:USER") { handle = KernelHandles::FS; } else if (service == "gsp::Gpu") { handle = KernelHandles::GPU; @@ -145,6 +148,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { case KernelHandles::CFG: cfg.handleSyncRequest(messagePointer); break; case KernelHandles::DSP: dsp.handleSyncRequest(messagePointer); break; case KernelHandles::HID: hid.handleSyncRequest(messagePointer); break; + case KernelHandles::FRD: frd.handleSyncRequest(messagePointer); break; case KernelHandles::FS: fs.handleSyncRequest(messagePointer); break; case KernelHandles::GPU: [[likely]] gsp_gpu.handleSyncRequest(messagePointer); break; case KernelHandles::LCD: gsp_lcd.handleSyncRequest(messagePointer); break; From 243224eed3539ac836d3d53bd631737fb7c04ed8 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 6 Jan 2023 00:32:02 +0200 Subject: [PATCH 20/25] More service calls implemented --- include/kernel/config_mem.hpp | 4 +++- include/memory.hpp | 11 +++++++++++ include/services/dsp.hpp | 1 + include/services/fs.hpp | 1 + include/services/gsp_gpu.hpp | 1 + include/services/service_manager.hpp | 1 + src/core/memory.cpp | 2 ++ src/core/services/dsp.cpp | 11 +++++++++++ src/core/services/fs.cpp | 8 ++++++++ src/core/services/gsp_gpu.cpp | 13 ++++++++++++- src/core/services/service_manager.cpp | 8 ++++++++ 11 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/kernel/config_mem.hpp b/include/kernel/config_mem.hpp index 397e84a2..7533c42c 100644 --- a/include/kernel/config_mem.hpp +++ b/include/kernel/config_mem.hpp @@ -10,6 +10,8 @@ namespace ConfigMem { EnvInfo = 0x1FF80014, AppMemAlloc = 0x1FF80040, Datetime0 = 0x1FF81020, - LedState3D = 0x1FF81084 + LedState3D = 0x1FF81084, + BatteryState = 0x1FF81085, + HeadphonesConnectedMaybe = 0x1FF810C0 // TODO: What is actually stored here? }; } \ No newline at end of file diff --git a/include/memory.hpp b/include/memory.hpp index a3815534..1775bf04 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -156,6 +156,17 @@ public: u32 getLinearHeapVaddr(); u8* getFCRAM() { return fcram; } + enum class BatteryLevel { + Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars + }; + u8 getBatteryState(bool adapterConnected, bool charging, BatteryLevel batteryLevel) { + u8 value = static_cast(batteryLevel) << 2; // Bits 2:4 are the battery level from 0 to 5 + if (adapterConnected) value |= 1 << 0; // Bit 0 shows if the charger is connected + if (charging) value |= 1 << 1; // Bit 1 shows if we're charging + + return value; + } + NCCH* getCXI() { if (loadedCXI.has_value()) { return &loadedCXI.value(); diff --git a/include/services/dsp.hpp b/include/services/dsp.hpp index 0033bdc6..e32aa314 100644 --- a/include/services/dsp.hpp +++ b/include/services/dsp.hpp @@ -50,6 +50,7 @@ class DSPService { // Service functions void convertProcessAddressFromDspDram(u32 messagePointer); // Nice function name + void flushDataCache(u32 messagePointer); void getHeadphoneStatus(u32 messagePointer); void getSemaphoreHandle(u32 messagePointer); void loadComponent(u32 messagePointer); diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 9e338c91..62f361ca 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -31,6 +31,7 @@ class FSService { void getPriority(u32 messagePointer); void initialize(u32 messagePointer); void initializeWithSdkVersion(u32 messagePointer); + void isSdmcDetected(u32 messagePointer); void openArchive(u32 messagePointer); void openFile(u32 messagePointer); void openFileDirectly(u32 messagePointer); diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index 3c974b65..789ed211 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -37,6 +37,7 @@ class GPUService { void setAxiConfigQoSMode(u32 messagePointer); void setInternalPriorities(u32 messagePointer); void setLCDForceBlack(u32 messagePointer); + void storeDataCache(u32 messagePointer); void triggerCmdReqQueue(u32 messagePointer); void writeHwRegs(u32 messagePointer); void writeHwRegsWithMask(u32 messagePointer); diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 91f3b8be..6b2326d4 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -49,6 +49,7 @@ class ServiceManager { void getServiceHandle(u32 messagePointer); void receiveNotification(u32 messagePointer); void registerClient(u32 messagePointer); + void subscribe(u32 messagePointer); public: ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 464ab1f7..d8de8584 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -74,10 +74,12 @@ u8 Memory::read8(u32 vaddr) { } else { switch (vaddr) { + case ConfigMem::BatteryState: return getBatteryState(true, true, BatteryLevel::FourBars); case ConfigMem::EnvInfo: return envInfo; case ConfigMem::KernelVersionMinor: return u8(kernelVersion & 0xff); case ConfigMem::KernelVersionMajor: return u8(kernelVersion >> 8); case ConfigMem::LedState3D: return 1; // Report the 3D LED as always off (non-zero) for now + case ConfigMem::HeadphonesConnectedMaybe: return 0; default: Helpers::panic("Unimplemented 8-bit read, addr: %08X", vaddr); } } diff --git a/src/core/services/dsp.cpp b/src/core/services/dsp.cpp index cbcf687f..9e10fc17 100644 --- a/src/core/services/dsp.cpp +++ b/src/core/services/dsp.cpp @@ -7,6 +7,7 @@ namespace DSPCommands { WriteProcessPipe = 0x000D0082, ReadPipeIfPossible = 0x001000C0, LoadComponent = 0x001100C2, + FlushDataCache = 0x00130082, RegisterInterruptEvents = 0x00150082, GetSemaphoreHandle = 0x00160000, SetSemaphoreMask = 0x00170040, @@ -30,6 +31,7 @@ void DSPService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { case DSPCommands::ConvertProcessAddressFromDspDram: convertProcessAddressFromDspDram(messagePointer); break; + case DSPCommands::FlushDataCache: flushDataCache(messagePointer); break; case DSPCommands::GetHeadphoneStatus: getHeadphoneStatus(messagePointer); break; case DSPCommands::GetSemaphoreHandle: getSemaphoreHandle(messagePointer); break; case DSPCommands::LoadComponent: loadComponent(messagePointer); break; @@ -133,4 +135,13 @@ void DSPService::writeProcessPipe(u32 messagePointer) { log("DSP::writeProcessPipe (channel = %d, size = %X, buffer = %08X)\n", channel, size, buffer); mem.write32(messagePointer + 4, Result::Success); +} + +void DSPService::flushDataCache(u32 messagePointer) { + u32 address = mem.read32(messagePointer + 4); + u32 size = mem.read32(messagePointer + 8); + u32 process = mem.read32(messagePointer + 16); + + log("DSP::FlushDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 87f42c81..a8a4d891 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -8,6 +8,7 @@ namespace FSCommands { OpenFileDirectly = 0x08030204, OpenArchive = 0x080C00C2, CloseArchive = 0x080E0080, + IsSdmcDetected = 0x08170000, InitializeWithSdkVersion = 0x08610042, SetPriority = 0x08620040, GetPriority = 0x08630000 @@ -77,6 +78,7 @@ void FSService::handleSyncRequest(u32 messagePointer) { case FSCommands::GetPriority: getPriority(messagePointer); break; case FSCommands::Initialize: initialize(messagePointer); break; case FSCommands::InitializeWithSdkVersion: initializeWithSdkVersion(messagePointer); break; + case FSCommands::IsSdmcDetected: isSdmcDetected(messagePointer); break; case FSCommands::OpenArchive: openArchive(messagePointer); break; case FSCommands::OpenFile: openFile(messagePointer); break; case FSCommands::OpenFileDirectly: openFileDirectly(messagePointer); break; @@ -210,4 +212,10 @@ void FSService::setPriority(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); priority = value; +} + +void FSService::isSdmcDetected(u32 messagePointer) { + log("FS::IsSdmcDetected\n"); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); // Whether SD is detected. For now we emulate a 3DS without an SD. } \ No newline at end of file diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 910f7aa9..684b3c4f 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -11,7 +11,8 @@ namespace ServiceCommands { FlushDataCache = 0x00080082, SetLCDForceBlack = 0x000B0040, TriggerCmdReqQueue = 0x000C0000, - SetInternalPriorities = 0x001E0080 + SetInternalPriorities = 0x001E0080, + StoreDataCache = 0x001F0082 }; } @@ -47,6 +48,7 @@ void GPUService::handleSyncRequest(u32 messagePointer) { case ServiceCommands::SetAxiConfigQoSMode: setAxiConfigQoSMode(messagePointer); break; case ServiceCommands::SetInternalPriorities: setInternalPriorities(messagePointer); break; case ServiceCommands::SetLCDForceBlack: setLCDForceBlack(messagePointer); break; + case ServiceCommands::StoreDataCache: storeDataCache(messagePointer); break; case ServiceCommands::TriggerCmdReqQueue: [[likely]] triggerCmdReqQueue(messagePointer); break; case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break; case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break; @@ -184,6 +186,15 @@ void GPUService::flushDataCache(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void GPUService::storeDataCache(u32 messagePointer) { + u32 address = mem.read32(messagePointer + 4); + u32 size = mem.read32(messagePointer + 8); + u32 processHandle = handle = mem.read32(messagePointer + 16); + log("GSP::GPU::StoreDataCache(address = %08X, size = %X, process = %X\n", address, size, processHandle); + + mem.write32(messagePointer + 4, Result::Success); +} + void GPUService::setLCDForceBlack(u32 messagePointer) { u32 flag = mem.read32(messagePointer + 4); log("GSP::GPU::SetLCDForceBlank(flag = %d)\n", flag); diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index f079d9c4..4dd44d58 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -62,6 +62,7 @@ void ServiceManager::handleSyncRequest(u32 messagePointer) { case Commands::ReceiveNotification: receiveNotification(messagePointer); break; case Commands::RegisterClient: registerClient(messagePointer); break; case Commands::GetServiceHandle: getServiceHandle(messagePointer); break; + case Commands::Subscribe: subscribe(messagePointer); break; default: Helpers::panic("Unknown \"srv:\" command: %08X", header); } } @@ -140,6 +141,13 @@ void ServiceManager::receiveNotification(u32 messagePointer) { mem.write32(messagePointer + 8, 0); // Notification ID } +void ServiceManager::subscribe(u32 messagePointer) { + u32 id = mem.read32(messagePointer + 4); + log("srv::Subscribe (id = %d) (stubbed)\n", id); + + mem.write32(messagePointer + 4, Result::Success); +} + void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { switch (handle) { case KernelHandles::AC: ac.handleSyncRequest(messagePointer); break; From f965dea916e064816d9cc23b1127b3c61756304a Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 6 Jan 2023 02:40:45 +0200 Subject: [PATCH 21/25] Add BOSS service --- CMakeLists.txt | 4 ++-- include/kernel/handles.hpp | 3 ++- include/logger.hpp | 1 + include/services/boss.hpp | 19 ++++++++++++++++++ include/services/service_manager.hpp | 2 ++ src/core/services/boss.cpp | 28 +++++++++++++++++++++++++++ src/core/services/service_manager.cpp | 8 ++++++-- 7 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 include/services/boss.hpp create mode 100644 src/core/services/boss.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77bd20b3..0466a643 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/fs.cpp src/core/services/gsp_gpu.cpp src/core/services/gsp_lcd.cpp src/core/services/ndm.cpp src/core/services/dsp.cpp src/core/services/cfg.cpp src/core/services/ptm.cpp src/core/services/mic.cpp src/core/services/cecd.cpp - src/core/services/ac.cpp src/core/services/frd.cpp + src/core/services/ac.cpp src/core/services/boss.cpp src/core/services/frd.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp @@ -82,7 +82,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp - include/services/frd.hpp + include/services/boss.hpp include/services/frd.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index 2bcc3d57..7735cacf 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -12,7 +12,8 @@ namespace KernelHandles { CurrentProcess = 0xFFFF8001, // Used by the original kernel AC, // Something network related APT, // App Title something service? - CECD, // Streetpass stuff? + BOSS, // Streetpass stuff? + CECD, // More Streetpass stuff? CFG, // CFG service (Console & region info) HID, // HID service (Handles everything input-related including gyro) FRD, // Friend service (Miiverse friend service) diff --git a/include/logger.hpp b/include/logger.hpp index f83aaace..8d6b406a 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -30,6 +30,7 @@ namespace Log { // Service loggers static Logger acLogger; static Logger aptLogger; + static Logger bossLogger; static Logger cecdLogger; static Logger cfgLogger; static Logger dspServiceLogger; diff --git a/include/services/boss.hpp b/include/services/boss.hpp new file mode 100644 index 00000000..87a72c9f --- /dev/null +++ b/include/services/boss.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" + +class BOSSService { + Handle handle = KernelHandles::BOSS; + Memory& mem; + MAKE_LOG_FUNCTION(log, bossLogger) + + // Service commands + void initializeSession(u32 messagePointer); + +public: + BOSSService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 6b2326d4..261ef9e8 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -6,6 +6,7 @@ #include "memory.hpp" #include "services/ac.hpp" #include "services/apt.hpp" +#include "services/boss.hpp" #include "services/cecd.hpp" #include "services/cfg.hpp" #include "services/dsp.hpp" @@ -32,6 +33,7 @@ class ServiceManager { ACService ac; APTService apt; + BOSSService boss; CECDService cecd; CFGService cfg; DSPService dsp; diff --git a/src/core/services/boss.cpp b/src/core/services/boss.cpp new file mode 100644 index 00000000..fb5053f7 --- /dev/null +++ b/src/core/services/boss.cpp @@ -0,0 +1,28 @@ +#include "services/boss.hpp" + +namespace BOSSCommands { + enum : u32 { + InitializeSession = 0x00010082 + }; +} + +namespace Result { + enum : u32 { + Success = 0, + }; +} + +void BOSSService::reset() {} + +void BOSSService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + case BOSSCommands::InitializeSession: initializeSession(messagePointer); break; + default: Helpers::panic("BOSS service requested. Command: %08X\n", command); + } +} + +void BOSSService::initializeSession(u32 messagePointer) { + log("BOSS::InitializeSession (stubbed)\n"); + mem.write32(messagePointer + 4, Result::Success); +} \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 4dd44d58..c9ec66b7 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -2,14 +2,15 @@ #include "kernel.hpp" ServiceManager::ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) - : regs(regs), mem(mem), kernel(kernel), ac(mem), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem), - frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} + : regs(regs), mem(mem), kernel(kernel), ac(mem), boss(mem), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), + hid(mem), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} static constexpr int MAX_NOTIFICATION_COUNT = 16; void ServiceManager::reset() { ac.reset(); apt.reset(); + boss.reset(); cecd.reset(); cfg.reset(); dsp.reset(); @@ -90,6 +91,8 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { handle = KernelHandles::APT; } else if (service == "APT:U") { handle = KernelHandles::APT; + } else if (service == "boss:U") { + handle = KernelHandles::BOSS; } else if (service == "cecd:u") { handle = KernelHandles::CECD; } else if (service == "cfg:u") { @@ -152,6 +155,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { switch (handle) { case KernelHandles::AC: ac.handleSyncRequest(messagePointer); break; case KernelHandles::APT: apt.handleSyncRequest(messagePointer); break; + case KernelHandles::BOSS: boss.handleSyncRequest(messagePointer); break; case KernelHandles::CECD: cecd.handleSyncRequest(messagePointer); break; case KernelHandles::CFG: cfg.handleSyncRequest(messagePointer); break; case KernelHandles::DSP: dsp.handleSyncRequest(messagePointer); break; From 64de1391ab124e7b848a9ac4e23d36c0811f87a5 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 6 Jan 2023 03:44:04 +0200 Subject: [PATCH 22/25] Add AM and NIM services --- CMakeLists.txt | 5 ++-- include/kernel/handles.hpp | 4 ++- include/logger.hpp | 2 ++ include/services/am.hpp | 19 ++++++++++++ include/services/nim.hpp | 19 ++++++++++++ include/services/service_manager.hpp | 4 +++ src/core/services/am.cpp | 43 +++++++++++++++++++++++++++ src/core/services/nim.cpp | 28 +++++++++++++++++ src/core/services/service_manager.cpp | 20 +++++++++---- 9 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 include/services/am.hpp create mode 100644 include/services/nim.hpp create mode 100644 src/core/services/am.cpp create mode 100644 src/core/services/nim.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0466a643..d69da150 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,8 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services src/core/services/fs.cpp src/core/services/gsp_gpu.cpp src/core/services/gsp_lcd.cpp src/core/services/ndm.cpp src/core/services/dsp.cpp src/core/services/cfg.cpp src/core/services/ptm.cpp src/core/services/mic.cpp src/core/services/cecd.cpp - src/core/services/ac.cpp src/core/services/boss.cpp src/core/services/frd.cpp + src/core/services/ac.cpp src/core/services/am.cpp src/core/services/boss.cpp + src/core/services/frd.cpp src/core/services/nim.cpp ) set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp @@ -82,7 +83,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp include/services/ptm.hpp include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp - include/services/boss.hpp include/services/frd.hpp + include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index 7735cacf..947f6589 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -10,7 +10,8 @@ namespace KernelHandles { // Hardcoded handles CurrentThread = 0xFFFF8000, // Used by the original kernel CurrentProcess = 0xFFFF8001, // Used by the original kernel - AC, // Something network related + AC, // Something network related + AM, // Application manager APT, // App Title something service? BOSS, // Streetpass stuff? CECD, // More Streetpass stuff? @@ -22,6 +23,7 @@ namespace KernelHandles { DSP, // DSP service (Used for audio decoding and output) LCD, // LCD service (Used for configuring the displays) MIC, // MIC service (Controls the microphone) + NIM, // Updates, DLC, etc NDM, // ????? PTM, // PTM service (Used for accessing various console info, such as battery, shell and pedometer state) diff --git a/include/logger.hpp b/include/logger.hpp index 8d6b406a..655a83ce 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -29,6 +29,7 @@ namespace Log { // Service loggers static Logger acLogger; + static Logger amLogger; static Logger aptLogger; static Logger bossLogger; static Logger cecdLogger; @@ -40,6 +41,7 @@ namespace Log { static Logger gspGPULogger; static Logger gspLCDLogger; static Logger micLogger; + static Logger nimLogger; static Logger ndmLogger; static Logger ptmLogger; static Logger srvLogger; diff --git a/include/services/am.hpp b/include/services/am.hpp new file mode 100644 index 00000000..e406b2ef --- /dev/null +++ b/include/services/am.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" + +class AMService { + Handle handle = KernelHandles::AM; + Memory& mem; + MAKE_LOG_FUNCTION(log, amLogger) + + // Service commands + void listTitleInfo(u32 messagePointer); + +public: + AMService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/nim.hpp b/include/services/nim.hpp new file mode 100644 index 00000000..6d45b837 --- /dev/null +++ b/include/services/nim.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" +#include "logger.hpp" +#include "memory.hpp" + +class NIMService { + Handle handle = KernelHandles::NIM; + Memory& mem; + MAKE_LOG_FUNCTION(log, nimLogger) + + // Service commands + void initialize(u32 messagePointer); + +public: + NIMService(Memory& mem) : mem(mem) {} + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 261ef9e8..a072b88a 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -5,6 +5,7 @@ #include "logger.hpp" #include "memory.hpp" #include "services/ac.hpp" +#include "services/am.hpp" #include "services/apt.hpp" #include "services/boss.hpp" #include "services/cecd.hpp" @@ -16,6 +17,7 @@ #include "services/gsp_gpu.hpp" #include "services/gsp_lcd.hpp" #include "services/mic.hpp" +#include "services/nim.hpp" #include "services/ndm.hpp" #include "services/ptm.hpp" @@ -32,6 +34,7 @@ class ServiceManager { MAKE_LOG_FUNCTION(log, srvLogger) ACService ac; + AMService am; APTService apt; BOSSService boss; CECDService cecd; @@ -43,6 +46,7 @@ class ServiceManager { GPUService gsp_gpu; LCDService gsp_lcd; MICService mic; + NIMService nim; NDMService ndm; PTMService ptm; diff --git a/src/core/services/am.cpp b/src/core/services/am.cpp new file mode 100644 index 00000000..5771f598 --- /dev/null +++ b/src/core/services/am.cpp @@ -0,0 +1,43 @@ +#include "services/am.hpp" + +namespace AMCommands { + enum : u32 { + ListTitleInfo = 0x10070102 + }; +} + +namespace Result { + enum : u32 { + Success = 0, + }; +} + +void AMService::reset() {} + +void AMService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + case AMCommands::ListTitleInfo: listTitleInfo(messagePointer); break; + default: Helpers::panic("AM service requested. Command: %08X\n", command); + } +} + +void AMService::listTitleInfo(u32 messagePointer) { + log("AM::ListDLCOrLicenseTicketInfos\n"); // Yes this is the actual name + u32 ticketCount = mem.read32(messagePointer + 4); + u64 titleID = mem.read64(messagePointer + 8); + u32 pointer = mem.read32(messagePointer + 24); + + for (u32 i = 0; i < ticketCount; i++) { + mem.write64(pointer, titleID); // Title ID + mem.write64(pointer + 8, 0); // Ticket ID + mem.write16(pointer + 16, 0); // Version + mem.write16(pointer + 18, 0); // Padding + mem.write32(pointer + 20, 0); // Size + + pointer += 24; // = sizeof(TicketInfo) + } + + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, ticketCount); +} \ No newline at end of file diff --git a/src/core/services/nim.cpp b/src/core/services/nim.cpp new file mode 100644 index 00000000..a3c48fb4 --- /dev/null +++ b/src/core/services/nim.cpp @@ -0,0 +1,28 @@ +#include "services/nim.hpp" + +namespace NIMCommands { + enum : u32 { + Initialize = 0x00210000 + }; +} + +namespace Result { + enum : u32 { + Success = 0, + }; +} + +void NIMService::reset() {} + +void NIMService::handleSyncRequest(u32 messagePointer) { + const u32 command = mem.read32(messagePointer); + switch (command) { + case NIMCommands::Initialize: initialize(messagePointer); break; + default: Helpers::panic("NIM service requested. Command: %08X\n", command); + } +} + +void NIMService::initialize(u32 messagePointer) { + log("NIM::Initialize\n"); + mem.write32(messagePointer + 4, Result::Success); +} \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index c9ec66b7..c960f461 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -2,24 +2,28 @@ #include "kernel.hpp" ServiceManager::ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) - : regs(regs), mem(mem), kernel(kernel), ac(mem), boss(mem), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), - hid(mem), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} + : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), apt(mem, kernel), cecd(mem), cfg(mem), + dsp(mem), hid(mem), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), + nim(mem), ndm(mem), ptm(mem) {} static constexpr int MAX_NOTIFICATION_COUNT = 16; +// Reset every single service void ServiceManager::reset() { - ac.reset(); + ac.reset(); + am.reset(); apt.reset(); - boss.reset(); + boss.reset(); cecd.reset(); cfg.reset(); dsp.reset(); hid.reset(); - frd.reset(); + frd.reset(); fs.reset(); gsp_gpu.reset(); gsp_lcd.reset(); mic.reset(); + nim.reset(); ndm.reset(); ptm.reset(); @@ -85,6 +89,8 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { if (service == "ac:u") { handle = KernelHandles::AC; + } else if (service == "am:app") { + handle = KernelHandles::AM; } else if (service == "APT:S") { // TODO: APT:A, APT:S and APT:U are slightly different handle = KernelHandles::APT; } else if (service == "APT:A") { @@ -113,6 +119,8 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { handle = KernelHandles::MIC; } else if (service == "ndm:u") { handle = KernelHandles::NDM; + } else if (service == "nim:aoc") { + handle = KernelHandles::NIM; } else if (service == "ptm:u") { handle = KernelHandles::PTM; } else { @@ -154,6 +162,7 @@ void ServiceManager::subscribe(u32 messagePointer) { void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { switch (handle) { case KernelHandles::AC: ac.handleSyncRequest(messagePointer); break; + case KernelHandles::AM: am.handleSyncRequest(messagePointer); break; case KernelHandles::APT: apt.handleSyncRequest(messagePointer); break; case KernelHandles::BOSS: boss.handleSyncRequest(messagePointer); break; case KernelHandles::CECD: cecd.handleSyncRequest(messagePointer); break; @@ -165,6 +174,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { case KernelHandles::GPU: [[likely]] gsp_gpu.handleSyncRequest(messagePointer); break; case KernelHandles::LCD: gsp_lcd.handleSyncRequest(messagePointer); break; case KernelHandles::MIC: mic.handleSyncRequest(messagePointer); break; + case KernelHandles::NIM: nim.handleSyncRequest(messagePointer); break; case KernelHandles::NDM: ndm.handleSyncRequest(messagePointer); break; case KernelHandles::PTM: ptm.handleSyncRequest(messagePointer); break; default: Helpers::panic("Sent IPC message to unknown service %08X\n Command: %08X", handle, mem.read32(messagePointer)); From bbb62a83d0eca08754d5cb7db0b843eee7e7344c Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 7 Jan 2023 01:34:34 +0200 Subject: [PATCH 23/25] [PICA] Implement RCP --- include/PICA/shader.hpp | 2 ++ src/core/PICA/shader_interpreter.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/PICA/shader.hpp b/include/PICA/shader.hpp index bad37d2e..4f556fe1 100644 --- a/include/PICA/shader.hpp +++ b/include/PICA/shader.hpp @@ -18,6 +18,7 @@ namespace ShaderOpcodes { MUL = 0x08, MAX = 0x0C, MIN = 0x0D, + RCP = 0x0E, RSQ = 0x0F, MOVA = 0x12, MOV = 0x13, @@ -99,6 +100,7 @@ class PICAShader { void mov(u32 instruction); void mova(u32 instruction); void mul(u32 instruction); + void rcp(u32 instruction); void rsq(u32 instruction); // src1, src2 and src3 have different negation & component swizzle bits in the operand descriptor diff --git a/src/core/PICA/shader_interpreter.cpp b/src/core/PICA/shader_interpreter.cpp index 7a7bf45b..122e75cb 100644 --- a/src/core/PICA/shader_interpreter.cpp +++ b/src/core/PICA/shader_interpreter.cpp @@ -30,6 +30,7 @@ void PICAShader::run() { case ShaderOpcodes::MOVA: mova(instruction); break; case ShaderOpcodes::MUL: mul(instruction); break; case ShaderOpcodes::NOP: break; // Do nothing + case ShaderOpcodes::RCP: rcp(instruction); break; case ShaderOpcodes::RSQ: rsq(instruction); break; case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: @@ -292,6 +293,26 @@ void PICAShader::dp4(u32 instruction) { } } +void PICAShader::rcp(u32 instruction) { + const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; + const u32 src1 = (instruction >> 12) & 0x7f; + const u32 idx = (instruction >> 19) & 3; + const u32 dest = (instruction >> 21) & 0x1f; + + if (idx) Helpers::panic("[PICA] RCP: idx != 0"); + vec4f srcVec1 = getSourceSwizzled<1>(src1, operandDescriptor); + + vec4f& destVector = getDest(dest); + f24 res = f24::fromFloat32(1.0f) / srcVec1[0]; + + u32 componentMask = operandDescriptor & 0xf; + for (int i = 0; i < 4; i++) { + if (componentMask & (1 << i)) { + destVector[3 - i] = res; + } + } +} + void PICAShader::rsq(u32 instruction) { const u32 operandDescriptor = operandDescriptors[instruction & 0x7f]; const u32 src1 = (instruction >> 12) & 0x7f; From 79c89f1f63088731d9792d1782429b25d81f0988 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 7 Jan 2023 03:30:32 +0200 Subject: [PATCH 24/25] Starting work on (Shared)ExtSaveData archive --- CMakeLists.txt | 5 ++++- include/fs/archive_ext_save_data.hpp | 16 ++++++++++++++++ include/fs/archive_ncch.hpp | 1 - include/fs/archive_save_data.hpp | 3 +-- include/fs/archive_sdmc.hpp | 3 +-- include/services/fs.hpp | 9 ++++++++- src/core/fs/archive_ext_save_data.cpp | 17 +++++++++++++++++ src/core/services/fs.cpp | 1 + 8 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 include/fs/archive_ext_save_data.hpp create mode 100644 src/core/fs/archive_ext_save_data.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d69da150..18c711a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,9 @@ set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp) set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp) -set(FS_SOURCE_FILES src/core/fs/archive_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp) +set(FS_SOURCE_FILES src/core/fs/archive_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp + src/core/fs/archive_ext_save_data.cpp +) set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel/kernel.hpp @@ -84,6 +86,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/services/mic.hpp include/services/cecd.hpp include/renderer_gl/renderer_gl.hpp include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp + include/fs/archive_ext_save_data.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/fs/archive_ext_save_data.hpp b/include/fs/archive_ext_save_data.hpp new file mode 100644 index 00000000..973b2061 --- /dev/null +++ b/include/fs/archive_ext_save_data.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "archive_base.hpp" + +class ExtSaveDataArchive : public ArchiveBase { +public: + ExtSaveDataArchive(Memory& mem) : ArchiveBase(mem) {} + + u64 getFreeBytes() override { Helpers::panic("ExtSaveData::GetFreeBytes unimplemented"); return 0; } + std::string name() override { return "ExtSaveData"; } + + bool openFile(const FSPath& path) override; + ArchiveBase* openArchive(const FSPath& path) override; + std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override; + + bool isShared = false; +}; \ No newline at end of file diff --git a/include/fs/archive_ncch.hpp b/include/fs/archive_ncch.hpp index 7ece602c..b079e60d 100644 --- a/include/fs/archive_ncch.hpp +++ b/include/fs/archive_ncch.hpp @@ -2,7 +2,6 @@ #include "archive_base.hpp" class SelfNCCHArchive : public ArchiveBase { - public: SelfNCCHArchive(Memory& mem) : ArchiveBase(mem) {} diff --git a/include/fs/archive_save_data.hpp b/include/fs/archive_save_data.hpp index f1f38560..5ff9d8ba 100644 --- a/include/fs/archive_save_data.hpp +++ b/include/fs/archive_save_data.hpp @@ -2,11 +2,10 @@ #include "archive_base.hpp" class SaveDataArchive : public ArchiveBase { - public: SaveDataArchive(Memory& mem) : ArchiveBase(mem) {} - u64 getFreeBytes() override { return 0; } + u64 getFreeBytes() override { Helpers::panic("SaveData::GetFreeBytes unimplemented"); return 0; } std::string name() override { return "SaveData"; } bool openFile(const FSPath& path) override; diff --git a/include/fs/archive_sdmc.hpp b/include/fs/archive_sdmc.hpp index d3cebe25..fc271881 100644 --- a/include/fs/archive_sdmc.hpp +++ b/include/fs/archive_sdmc.hpp @@ -2,11 +2,10 @@ #include "archive_base.hpp" class SDMCArchive : public ArchiveBase { - public: SDMCArchive(Memory& mem) : ArchiveBase(mem) {} - u64 getFreeBytes() override { return 0; } + u64 getFreeBytes() override { Helpers::panic("SDMC::GetFreeBytes unimplemented"); return 0; } std::string name() override { return "SDMC"; } bool openFile(const FSPath& path) override; diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 62f361ca..8dcfc854 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -1,4 +1,5 @@ #pragma once +#include "fs/archive_ext_save_data.hpp" #include "fs/archive_ncch.hpp" #include "fs/archive_save_data.hpp" #include "fs/archive_sdmc.hpp" @@ -20,6 +21,7 @@ class FSService { // The different filesystem archives (Save data, RomFS+ExeFS, etc) SelfNCCHArchive selfNcch; SaveDataArchive saveData; + ExtSaveDataArchive sharedExtSaveData; SDMCArchive sdmc; ArchiveBase* getArchiveFromID(u32 id); @@ -41,7 +43,12 @@ class FSService { u32 priority; public: - FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), sdmc(mem), selfNcch(mem), kernel(kernel) {} + FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), sharedExtSaveData(mem), sdmc(mem), selfNcch(mem), + kernel(kernel) + { + sharedExtSaveData.isShared = true; // Need to do this here because templates and virtual classes do not mix well + } + void reset(); void handleSyncRequest(u32 messagePointer); }; \ No newline at end of file diff --git a/src/core/fs/archive_ext_save_data.cpp b/src/core/fs/archive_ext_save_data.cpp new file mode 100644 index 00000000..be5dba50 --- /dev/null +++ b/src/core/fs/archive_ext_save_data.cpp @@ -0,0 +1,17 @@ +#include "fs/archive_ext_save_data.hpp" +#include + +bool ExtSaveDataArchive::openFile(const FSPath& path) { + Helpers::panic("ExtSaveDataArchive::OpenFile: Failed"); + return false; +} + +ArchiveBase* ExtSaveDataArchive::openArchive(const FSPath& path) { + Helpers::panic("ExtSaveDataArchive::OpenArchive: Failed. Path type: %d", path.type); + return nullptr; +} + +std::optional ExtSaveDataArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) { + Helpers::panic("ExtSaveDataArchive::ReadFile: Failed"); + return std::nullopt; +} \ No newline at end of file diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index a8a4d891..361aa64b 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -30,6 +30,7 @@ ArchiveBase* FSService::getArchiveFromID(u32 id) { switch (id) { case ArchiveID::SelfNCCH: return &selfNcch; case ArchiveID::SaveData: return &saveData; + case ArchiveID::SharedExtSaveData: return &sharedExtSaveData; case ArchiveID::SDMC: return &sdmc; default: Helpers::panic("Unknown archive. ID: %d\n", id); From c31b2b89109cd2e755c1e67a508b65305af8b41b Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 7 Jan 2023 03:44:15 +0200 Subject: [PATCH 25/25] [ExtSaveData] More work --- src/core/fs/archive_ext_save_data.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/core/fs/archive_ext_save_data.cpp b/src/core/fs/archive_ext_save_data.cpp index be5dba50..ea7adf61 100644 --- a/src/core/fs/archive_ext_save_data.cpp +++ b/src/core/fs/archive_ext_save_data.cpp @@ -2,13 +2,25 @@ #include bool ExtSaveDataArchive::openFile(const FSPath& path) { + if (path.type != PathType::Binary) { + Helpers::panic("ExtSaveData accessed with a non-binary path in OpenFile. Type: %d", path.type); + } + Helpers::panic("ExtSaveDataArchive::OpenFile: Failed"); return false; } ArchiveBase* ExtSaveDataArchive::openArchive(const FSPath& path) { - Helpers::panic("ExtSaveDataArchive::OpenArchive: Failed. Path type: %d", path.type); - return nullptr; + if (path.type != PathType::Binary || path.size != 12) { + Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive"); + } + + u32 mediaType = mem.read32(path.pointer); + u64 saveID = mem.read64(path.pointer + 4); + + Helpers::panic("ExtSaveData: media type = %d\n", mediaType); + + return this; } std::optional ExtSaveDataArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {