From fec232f8a8dde1648e3031d8057c33cfea8778ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 17 Dec 2024 16:58:10 +0100 Subject: [PATCH] GPU: Move things around a little, out of DrawEngine. --- GPU/Common/DrawEngineCommon.cpp | 106 +------------------------ GPU/Common/DrawEngineCommon.h | 2 - GPU/Common/SoftwareTransformCommon.cpp | 103 ++++++++++++++++++++++++ GPU/Common/SoftwareTransformCommon.h | 3 + GPU/Common/SplineCommon.h | 14 +--- GPU/Common/TransformCommon.h | 12 +++ GPU/Software/TransformUnit.cpp | 3 +- 7 files changed, 124 insertions(+), 119 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 502d115b53..7b87756b4b 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -27,6 +27,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/SplineCommon.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -140,7 +141,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec = GetVertexDecoder(vertTypeID); if (vertexSize) *vertexSize = dec->VertexSize(); - return DrawEngineCommon::NormalizeVertices(outPtr, bufPtr, inPtr, dec, lowerBound, upperBound, vertType); + return ::NormalizeVertices(outPtr, bufPtr, inPtr, lowerBound, upperBound, dec, vertType); } void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) { @@ -750,109 +751,6 @@ bool DrawEngineCommon::GetCurrentSimpleVertices(int count, std::vectorDecodeVerts(bufPtr, inPtr, &gstate_c.uv, lowerBound, upperBound); - - // OK, morphing eliminated but bones still remain to be taken care of. - // Let's do a partial software transform where we only do skinning. - - VertexReader reader(bufPtr, dec->GetDecVtxFmt(), vertType); - - SimpleVertex *sverts = (SimpleVertex *)outPtr; - - const u8 defaultColor[4] = { - (u8)gstate.getMaterialAmbientR(), - (u8)gstate.getMaterialAmbientG(), - (u8)gstate.getMaterialAmbientB(), - (u8)gstate.getMaterialAmbientA(), - }; - - // Let's have two separate loops, one for non skinning and one for skinning. - if (!dec->skinInDecode && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { - int numBoneWeights = vertTypeGetNumBoneWeights(vertType); - for (int i = lowerBound; i <= upperBound; i++) { - reader.Goto(i - lowerBound); - SimpleVertex &sv = sverts[i]; - if (vertType & GE_VTYPE_TC_MASK) { - reader.ReadUV(sv.uv); - } - - if (vertType & GE_VTYPE_COL_MASK) { - sv.color_32 = reader.ReadColor0_8888(); - } else { - memcpy(sv.color, defaultColor, 4); - } - - float nrm[3], pos[3]; - float bnrm[3], bpos[3]; - - if (vertType & GE_VTYPE_NRM_MASK) { - // Normals are generated during tessellation anyway, not sure if any need to supply - reader.ReadNrm(nrm); - } else { - nrm[0] = 0; - nrm[1] = 0; - nrm[2] = 1.0f; - } - reader.ReadPos(pos); - - // Apply skinning transform directly - float weights[8]; - reader.ReadWeights(weights); - // Skinning - Vec3Packedf psum(0, 0, 0); - Vec3Packedf nsum(0, 0, 0); - for (int w = 0; w < numBoneWeights; w++) { - if (weights[w] != 0.0f) { - Vec3ByMatrix43(bpos, pos, gstate.boneMatrix + w * 12); - Vec3Packedf tpos(bpos); - psum += tpos * weights[w]; - - Norm3ByMatrix43(bnrm, nrm, gstate.boneMatrix + w * 12); - Vec3Packedf tnorm(bnrm); - nsum += tnorm * weights[w]; - } - } - sv.pos = psum; - sv.nrm = nsum; - } - } else { - for (int i = lowerBound; i <= upperBound; i++) { - reader.Goto(i - lowerBound); - SimpleVertex &sv = sverts[i]; - if (vertType & GE_VTYPE_TC_MASK) { - reader.ReadUV(sv.uv); - } else { - sv.uv[0] = 0.0f; // This will get filled in during tessellation - sv.uv[1] = 0.0f; - } - if (vertType & GE_VTYPE_COL_MASK) { - sv.color_32 = reader.ReadColor0_8888(); - } else { - memcpy(sv.color, defaultColor, 4); - } - if (vertType & GE_VTYPE_NRM_MASK) { - // Normals are generated during tessellation anyway, not sure if any need to supply - reader.ReadNrm((float *)&sv.nrm); - } else { - sv.nrm.x = 0.0f; - sv.nrm.y = 0.0f; - sv.nrm.z = 1.0f; - } - reader.ReadPos((float *)&sv.pos); - } - } - - // Okay, there we are! Return the new type (but keep the index bits) - return GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_NRM_FLOAT | GE_VTYPE_POS_FLOAT | (vertType & (GE_VTYPE_IDX_MASK | GE_VTYPE_THROUGH)); -} - void DrawEngineCommon::ApplyFramebufferRead(FBOTexState *fboTexState) { if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) { *fboTexState = FBO_TEX_READ_FRAMEBUFFER; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index c8733ecbaa..828bc213d0 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -88,8 +88,6 @@ public: bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices); - static u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType); - // Dispatches the queued-up draws. virtual void Flush() = 0; diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index c2a8b8f1ff..6fa5d76f16 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -934,3 +934,106 @@ bool SoftwareTransform::ExpandPoints(int vertexCount, int &maxIndex, int vertsSi inds = newInds; return true; } + +// This normalizes a set of vertices in any format to SimpleVertex format, by processing away morphing AND skinning. +// The rest of the transform pipeline like lighting will go as normal, either hardware or software. +// The implementation is initially a bit inefficient but shouldn't be a big deal. +// An intermediate buffer of not-easy-to-predict size is stored at bufPtr. +u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, VertexDecoder *dec, u32 vertType) { + // First, decode the vertices into a GPU compatible format. This step can be eliminated but will need a separate + // implementation of the vertex decoder. + dec->DecodeVerts(bufPtr, inPtr, &gstate_c.uv, lowerBound, upperBound); + + // OK, morphing eliminated but bones still remain to be taken care of. + // Let's do a partial software transform where we only do skinning. + + VertexReader reader(bufPtr, dec->GetDecVtxFmt(), vertType); + + SimpleVertex *sverts = (SimpleVertex *)outPtr; + + const u8 defaultColor[4] = { + (u8)gstate.getMaterialAmbientR(), + (u8)gstate.getMaterialAmbientG(), + (u8)gstate.getMaterialAmbientB(), + (u8)gstate.getMaterialAmbientA(), + }; + + // Let's have two separate loops, one for non skinning and one for skinning. + if (!dec->skinInDecode && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { + int numBoneWeights = vertTypeGetNumBoneWeights(vertType); + for (int i = lowerBound; i <= upperBound; i++) { + reader.Goto(i - lowerBound); + SimpleVertex &sv = sverts[i]; + if (vertType & GE_VTYPE_TC_MASK) { + reader.ReadUV(sv.uv); + } + + if (vertType & GE_VTYPE_COL_MASK) { + sv.color_32 = reader.ReadColor0_8888(); + } else { + memcpy(sv.color, defaultColor, 4); + } + + float nrm[3], pos[3]; + float bnrm[3], bpos[3]; + + if (vertType & GE_VTYPE_NRM_MASK) { + // Normals are generated during tessellation anyway, not sure if any need to supply + reader.ReadNrm(nrm); + } else { + nrm[0] = 0; + nrm[1] = 0; + nrm[2] = 1.0f; + } + reader.ReadPos(pos); + + // Apply skinning transform directly + float weights[8]; + reader.ReadWeights(weights); + // Skinning + Vec3Packedf psum(0, 0, 0); + Vec3Packedf nsum(0, 0, 0); + for (int w = 0; w < numBoneWeights; w++) { + if (weights[w] != 0.0f) { + Vec3ByMatrix43(bpos, pos, gstate.boneMatrix + w * 12); + Vec3Packedf tpos(bpos); + psum += tpos * weights[w]; + + Norm3ByMatrix43(bnrm, nrm, gstate.boneMatrix + w * 12); + Vec3Packedf tnorm(bnrm); + nsum += tnorm * weights[w]; + } + } + sv.pos = psum; + sv.nrm = nsum; + } + } else { + for (int i = lowerBound; i <= upperBound; i++) { + reader.Goto(i - lowerBound); + SimpleVertex &sv = sverts[i]; + if (vertType & GE_VTYPE_TC_MASK) { + reader.ReadUV(sv.uv); + } else { + sv.uv[0] = 0.0f; // This will get filled in during tessellation + sv.uv[1] = 0.0f; + } + if (vertType & GE_VTYPE_COL_MASK) { + sv.color_32 = reader.ReadColor0_8888(); + } else { + memcpy(sv.color, defaultColor, 4); + } + if (vertType & GE_VTYPE_NRM_MASK) { + // Normals are generated during tessellation anyway, not sure if any need to supply + reader.ReadNrm((float *)&sv.nrm); + } else { + sv.nrm.x = 0.0f; + sv.nrm.y = 0.0f; + sv.nrm.z = 1.0f; + } + reader.ReadPos((float *)&sv.pos); + } + } + + // Okay, there we are! Return the new type (but keep the index bits) + return GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_NRM_FLOAT | GE_VTYPE_POS_FLOAT | (vertType & (GE_VTYPE_IDX_MASK | GE_VTYPE_THROUGH)); +} diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index 457fd6a253..d6d72b32dc 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -84,3 +84,6 @@ protected: const SoftwareTransformParams ¶ms_; Lin::Matrix4x4 projMatrix_; }; + +// Slow. See description in the cpp file. +u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, VertexDecoder *dec, u32 vertType); diff --git a/GPU/Common/SplineCommon.h b/GPU/Common/SplineCommon.h index e3acec7a67..bec51004e8 100644 --- a/GPU/Common/SplineCommon.h +++ b/GPU/Common/SplineCommon.h @@ -22,22 +22,12 @@ #include "Common/Swap.h" #include "GPU/Math3D.h" #include "GPU/ge_constants.h" +#include "GPU/Common/TransformCommon.h" + #include "Core/Config.h" #define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f) -// PSP compatible format so we can use the end of the pipeline in beziers etc -// 8 + 4 + 12 + 12 = 36 bytes -struct SimpleVertex { - float uv[2]; - union { - u8 color[4]; - u32_le color_32; - }; - Vec3Packedf nrm; - Vec3Packedf pos; -}; - class SimpleBufferManager; namespace Spline { diff --git a/GPU/Common/TransformCommon.h b/GPU/Common/TransformCommon.h index 4da0a83113..9911bcff4a 100644 --- a/GPU/Common/TransformCommon.h +++ b/GPU/Common/TransformCommon.h @@ -22,6 +22,7 @@ #include "Common/CommonTypes.h" #include "GPU/ge_constants.h" #include "GPU/Math3D.h" +#include "GPU/GPU.h" struct Color4 { float r, g, b, a; @@ -94,3 +95,14 @@ private: float lcolor[3][4][3]; }; +// PSP compatible format so we can use the end of the pipeline in beziers etc +// 8 + 4 + 12 + 12 = 36 bytes +struct SimpleVertex { + float uv[2]; + union { + u8 color[4]; + u32_le color_32; + }; + Vec3Packedf nrm; + Vec3Packedf pos; +}; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index ea03a5b360..0baf088473 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -27,6 +27,7 @@ #include "GPU/GPUState.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/Common/SplineCommon.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/Debugger/Debugger.h" @@ -979,7 +980,7 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector