From 219e0db4e5baf13adfd20424a22af861f63c3b7d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 Feb 2023 13:31:39 -0800 Subject: [PATCH] riscv: Initial vertexjit. --- CMakeLists.txt | 4 + GPU/Common/VertexDecoderCommon.h | 4 + GPU/Common/VertexDecoderRiscV.cpp | 152 ++++++++++++++++++++++++++++++ GPU/GPU.vcxproj | 1 + GPU/GPU.vcxproj.filters | 3 + 5 files changed, 164 insertions(+) create mode 100644 GPU/Common/VertexDecoderRiscV.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a344e03c74..4b0206f664 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1485,6 +1485,10 @@ list(APPEND CoreExtra Core/MIPS/MIPS/MipsJit.h ) +list(APPEND CoreExtra + GPU/Common/VertexDecoderRiscV.cpp +) + if(NOT MOBILE_DEVICE) set(CoreExtra ${CoreExtra} Core/AVIDump.cpp diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 70bd18795d..7de309b406 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -37,6 +37,8 @@ #include "Common/Arm64Emitter.h" #elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) #include "Common/x64Emitter.h" +#elif PPSSPP_ARCH(RISCV64) +#include "Common/RiscVEmitter.h" #else #include "Common/FakeEmitter.h" #endif @@ -489,6 +491,8 @@ public: #define VERTEXDECODER_JIT_BACKEND Arm64Gen::ARM64CodeBlock #elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) #define VERTEXDECODER_JIT_BACKEND Gen::XCodeBlock +#elif PPSSPP_ARCH(RISCV64) +#define VERTEXDECODER_JIT_BACKEND RiscVGen::RiscVCodeBlock #endif diff --git a/GPU/Common/VertexDecoderRiscV.cpp b/GPU/Common/VertexDecoderRiscV.cpp new file mode 100644 index 0000000000..58dfee0c9b --- /dev/null +++ b/GPU/Common/VertexDecoderRiscV.cpp @@ -0,0 +1,152 @@ +// Copyright (c) 2023- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "ppsspp_config.h" +#if PPSSPP_ARCH(RISCV64) + +#include "Common/CPUDetect.h" +#include "Common/Log.h" +#include "Common/RiscVEmitter.h" +#include "Core/MIPS/JitCommon/JitCommon.h" +#include "GPU/GPUState.h" +#include "GPU/Common/VertexDecoderCommon.h" + +using namespace RiscVGen; + +static const RiscVReg srcReg = X10; +static const RiscVReg dstReg = X11; +static const RiscVReg counterReg = X12; + +static const RiscVReg tempReg1 = X13; +static const RiscVReg tempReg2 = X14; +static const RiscVReg tempReg3 = X15; +static const RiscVReg scratchReg = X16; + +static const RiscVReg fullAlphaReg = X17; +static const RiscVReg boundsMinUReg = X28; +static const RiscVReg boundsMinVReg = X29; +static const RiscVReg boundsMaxUReg = X30; +static const RiscVReg boundsMaxVReg = X31; + +static const RiscVReg fpScratchReg1 = F10; +static const RiscVReg fpScratchReg2 = F11; +static const RiscVReg fpScratchReg3 = F12; +static const RiscVReg fpScratchReg4 = F13; + +static const JitLookup jitLookup[] = { + {&VertexDecoder::Step_TcFloat, &VertexDecoderJitCache::Jit_TcFloat}, +}; + +JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int32_t *jittedSize) { + dec_ = &dec; + + BeginWrite(4096); + const u8 *start = AlignCode16(); + SetAutoCompress(true); + + bool log = false; + + if (dec.col) { + // Or LDB and skip the conditional? This is probably cheaper. + LI(fullAlphaReg, 0xFF); + } + + if (dec.tc && dec.throughmode) { + // TODO: Smarter, only when doing bounds. + LI(tempReg1, &gstate_c.vertBounds.minU); + LH(boundsMinUReg, tempReg1, offsetof(KnownVertexBounds, minU)); + LH(boundsMaxUReg, tempReg1, offsetof(KnownVertexBounds, maxU)); + LH(boundsMinVReg, tempReg1, offsetof(KnownVertexBounds, minV)); + LH(boundsMaxVReg, tempReg1, offsetof(KnownVertexBounds, maxV)); + } + + // TODO: Skipping, prescale. + + const u8 *loopStart = GetCodePtr(); + for (int i = 0; i < dec.numSteps_; i++) { + if (!CompileStep(dec, i)) { + EndWrite(); + // Reset the code ptr (effectively undoing what we generated) and return zero to indicate that we failed. + ResetCodePtr(GetOffset(start)); + char temp[1024]{}; + dec.ToString(temp); + ERROR_LOG(G3D, "Could not compile vertex decoder, failed at step %d: %s", i, temp); + return nullptr; + } + } + + ADDI(srcReg, srcReg, dec.VertexSize()); + ADDI(dstReg, dstReg, dec.decFmt.stride); + ADDI(counterReg, counterReg, -1); + BLT(R_ZERO, counterReg, loopStart); + + if (dec.col) { + LI(tempReg1, &gstate_c.vertexFullAlpha); + FixupBranch skip = BNE(R_ZERO, fullAlphaReg); + SB(fullAlphaReg, tempReg1, 0); + SetJumpTarget(skip); + } + + if (dec.tc && dec.throughmode) { + // TODO: Smarter, only when doing bounds. + LI(tempReg1, &gstate_c.vertBounds.minU); + SH(boundsMinUReg, tempReg1, offsetof(KnownVertexBounds, minU)); + SH(boundsMaxUReg, tempReg1, offsetof(KnownVertexBounds, maxU)); + SH(boundsMinVReg, tempReg1, offsetof(KnownVertexBounds, minV)); + SH(boundsMaxVReg, tempReg1, offsetof(KnownVertexBounds, maxV)); + } + + RET(); + + FlushIcache(); + + if (log) { + char temp[1024]{}; + dec.ToString(temp); + INFO_LOG(JIT, "=== %s (%d bytes) ===", temp, (int)(GetCodePtr() - start)); + std::vector lines = DisassembleRV64(start, (int)(GetCodePtr() - start)); + for (auto line : lines) { + INFO_LOG(JIT, "%s", line.c_str()); + } + INFO_LOG(JIT, "=========="); + } + + *jittedSize = (int)(GetCodePtr() - start); + EndWrite(); + return (JittedVertexDecoder)start; +} + +bool VertexDecoderJitCache::CompileStep(const VertexDecoder &dec, int step) { + // See if we find a matching JIT function. + for (size_t i = 0; i < ARRAY_SIZE(jitLookup); i++) { + if (dec.steps_[step] == jitLookup[i].func) { + ((*this).*jitLookup[i].jitFunc)(); + return true; + } + } + return false; +} + +void VertexDecoderJitCache::Jit_TcFloat() { + // Just copy 64 bits. Might be nice if we could detect misaligned load perf. + LW(tempReg1, srcReg, dec_->tcoff); + LW(tempReg2, srcReg, dec_->tcoff + 4); + SW(tempReg1, dstReg, dec_->decFmt.uvoff); + SW(tempReg2, dstReg, dec_->decFmt.uvoff + 4); +} + +#endif // PPSSPP_ARCH(RISCV64) diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 0f8711b03b..625bfb112c 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -498,6 +498,7 @@ true + true true diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 828e4c5265..e30366acb3 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -521,6 +521,9 @@ GLES + + Common +