From 33c3e67b31ab31f92353197b3ebf5381aa94f11b Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 3 Jan 2025 19:14:31 +0200 Subject: [PATCH 1/4] CRO: Lighter icache flushes --- include/cpu_dynarmic.hpp | 2 ++ include/kernel/kernel.hpp | 1 + src/core/kernel/kernel.cpp | 1 + src/core/services/ldr_ro.cpp | 17 ++++++++--------- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/cpu_dynarmic.hpp b/include/cpu_dynarmic.hpp index 43f31d30..24358533 100644 --- a/include/cpu_dynarmic.hpp +++ b/include/cpu_dynarmic.hpp @@ -181,5 +181,7 @@ class CPU { void addTicks(u64 ticks) { env.AddTicks(ticks); } void clearCache() { jit->ClearCache(); } + void clearCacheRange(u32 start, u32 size) { jit->InvalidateCacheRange(start, size); } + void runFrame(); }; \ No newline at end of file diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index abc508ac..da5298a4 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -250,4 +250,5 @@ public: void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); } void clearInstructionCache(); + void clearInstructionCacheRange(u32 start, u32 size); }; \ No newline at end of file diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index d4229b55..fe7bd301 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -298,6 +298,7 @@ void Kernel::duplicateHandle() { } void Kernel::clearInstructionCache() { cpu.clearCache(); } +void Kernel::clearInstructionCacheRange(u32 start, u32 size) { cpu.clearCacheRange(start, size); } namespace SystemInfoType { enum : u32 { diff --git a/src/core/services/ldr_ro.cpp b/src/core/services/ldr_ro.cpp index a6114729..48621986 100644 --- a/src/core/services/ldr_ro.cpp +++ b/src/core/services/ldr_ro.cpp @@ -22,6 +22,7 @@ namespace CROHeader { NameOffset = 0x084, NextCRO = 0x088, PrevCRO = 0x08C, + FixedSize = 0x98, OnUnresolved = 0x0AC, CodeOffset = 0x0B0, DataOffset = 0x0B8, @@ -167,6 +168,10 @@ public: return mem.read32(croPointer + CROHeader::PrevCRO); } + u32 getFixedSize() { + return mem.read32(croPointer + CROHeader::FixedSize); + } + void setNextCRO(u32 nextCRO) { mem.write32(croPointer + CROHeader::NextCRO, nextCRO); } @@ -1248,8 +1253,7 @@ void LDRService::initialize(u32 messagePointer) { Helpers::panic("Failed to rebase CRS"); } - kernel.clearInstructionCache(); - + kernel.clearInstructionCacheRange(mapVaddr, size); loadedCRS = mapVaddr; mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); @@ -1278,8 +1282,6 @@ void LDRService::linkCRO(u32 messagePointer) { Helpers::panic("Failed to link CRO"); } - kernel.clearInstructionCache(); - mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -1346,8 +1348,7 @@ void LDRService::loadCRO(u32 messagePointer, bool isNew) { // TODO: add fixing cro.fix(fixLevel); - - kernel.clearInstructionCache(); + kernel.clearInstructionCacheRange(mapVaddr, size); if (isNew) { mem.write32(messagePointer, IPC::responseHeader(0x9, 2, 0)); @@ -1377,7 +1378,6 @@ void LDRService::unloadCRO(u32 messagePointer) { } CRO cro(mem, mapVaddr, true); - cro.unregisterCRO(loadedCRS); if (!cro.unlink(loadedCRS)) { @@ -1388,8 +1388,7 @@ void LDRService::unloadCRO(u32 messagePointer) { Helpers::panic("Failed to unrebase CRO"); } - kernel.clearInstructionCache(); - + kernel.clearInstructionCacheRange(mapVaddr, cro.getFixedSize()); mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file From 84c358660c0b38c29b5068de7aff4f591cbca081 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 3 Jan 2025 19:21:45 +0200 Subject: [PATCH 2/4] Implement Luma icache SVCs --- include/kernel/kernel.hpp | 2 ++ src/core/kernel/kernel.cpp | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index da5298a4..45085e15 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -175,6 +175,8 @@ public: void svcSignalEvent(); void svcSetTimer(); void svcSleepThread(); + void svcInvalidateInstructionCacheRange(); + void svcInvalidateEntireInstructionCache(); void connectToPort(); void outputDebugString(); void waitSynchronization1(); diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index fe7bd301..8208d4ac 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -69,6 +69,10 @@ void Kernel::serviceSVC(u32 svc) { case 0x3A: getResourceLimitCurrentValues(); break; case 0x3B: getThreadContext(); break; case 0x3D: outputDebugString(); break; + + // Luma SVCs + case 0x93: svcInvalidateInstructionCacheRange(); break; + case 0x94: svcInvalidateEntireInstructionCache(); break; default: Helpers::panic("Unimplemented svc: %X @ %08X", svc, regs[15]); break; } @@ -300,6 +304,19 @@ void Kernel::duplicateHandle() { void Kernel::clearInstructionCache() { cpu.clearCache(); } void Kernel::clearInstructionCacheRange(u32 start, u32 size) { cpu.clearCacheRange(start, size); } +void Kernel::svcInvalidateInstructionCacheRange() { + const u32 start = regs[0]; + const u32 size = regs[1]; + + clearInstructionCacheRange(start, size); + regs[0] = Result::Success; +} + +void Kernel::svcInvalidateEntireInstructionCache() { + clearInstructionCache(); + regs[0] = Result::Success; +} + namespace SystemInfoType { enum : u32 { MemoryInformation = 0, From 5042594f3b156344e86acf877529720fde08cf11 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 3 Jan 2025 19:23:46 +0200 Subject: [PATCH 3/4] Add missing SVC logs --- src/core/kernel/kernel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 8208d4ac..e097fab6 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -307,12 +307,15 @@ void Kernel::clearInstructionCacheRange(u32 start, u32 size) { cpu.clearCacheRan void Kernel::svcInvalidateInstructionCacheRange() { const u32 start = regs[0]; const u32 size = regs[1]; + logSVC("svcInvalidateInstructionCacheRange(start = %08X, size = %08X)\n", start, size); clearInstructionCacheRange(start, size); regs[0] = Result::Success; } void Kernel::svcInvalidateEntireInstructionCache() { + logSVC("svcInvalidateEntireInstructionCache()\n"); + clearInstructionCache(); regs[0] = Result::Success; } From 86ea40a9e5946d0159bb1bff723c10e8b7ca08d1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:24:46 +0200 Subject: [PATCH 4/4] GPU: Add sw texture copies --- include/renderer.hpp | 1 + src/core/renderer_gl/renderer_gl.cpp | 2 ++ src/core/renderer_mtl/renderer_mtl.cpp | 2 +- src/renderer.cpp | 38 ++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/renderer.hpp b/include/renderer.hpp index b458ecce..ca28455f 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -53,6 +53,7 @@ class Renderer { EmulatorConfig* emulatorConfig = nullptr; + void doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap); public: Renderer(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs); virtual ~Renderer(); diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index c1899655..2d54e586 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -792,6 +792,8 @@ void RendererGL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 shutUpCounter++; printf("RendererGL::TextureCopy failed to locate src framebuffer!\n"); } + + doSoftwareTextureCopy(inputAddr, outputAddr, copySize, inputWidth, inputGap, outputWidth, outputGap); return; } diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 9cf58716..14bca4d2 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -426,7 +426,7 @@ void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 // Find the source surface. auto srcFramebuffer = getColorRenderTarget(inputAddr, PICA::ColorFmt::RGBA8, copyStride, copyHeight, false); if (!srcFramebuffer) { - Helpers::warn("RendererMTL::TextureCopy failed to locate src framebuffer!\n"); + doSoftwareTextureCopy(inputAddr, outputAddr, copySize, inputWidth, inputGap, outputWidth, outputGap); return; } nextRenderPassName = "Clear before texture copy"; diff --git a/src/renderer.cpp b/src/renderer.cpp index 6a18df85..390a3fa6 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -3,6 +3,8 @@ #include #include +#include "PICA/gpu.hpp" + Renderer::Renderer(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs) : gpu(gpu), regs(internalRegs), externalRegs(externalRegs) {} Renderer::~Renderer() {} @@ -39,3 +41,39 @@ const char* Renderer::typeToString(RendererType rendererType) { default: return "Invalid"; } } + +void Renderer::doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap) { + u8* inputPointer = gpu.getPointerPhys(inputAddr); + u8* outputPointer = gpu.getPointerPhys(outputAddr); + + if (inputPointer == nullptr || outputPointer == nullptr) { + return; + } + + u32 inputBytesLeft = inputWidth; + u32 outputBytesLeft = outputWidth; + u32 copyBytesLeft = copySize; + + while (copyBytesLeft > 0) { + const u32 bytes = std::min({inputBytesLeft, outputBytesLeft, copyBytesLeft}); + std::memcpy(outputPointer, inputPointer, bytes); + + inputPointer += bytes; + outputPointer += bytes; + + inputBytesLeft -= bytes; + outputBytesLeft -= bytes; + copyBytesLeft -= bytes; + + // Apply input and output gap when an input or output line ends + if (inputBytesLeft == 0) { + inputBytesLeft = inputWidth; + inputPointer += inputGap; + } + + if (outputBytesLeft == 0) { + outputBytesLeft = outputWidth; + outputPointer += outputGap; + } + } +}