From 6d2948a09bc31e6c06a84b0a499ccf4a0df1a8e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 3 Jul 2026 13:10:05 +0200 Subject: [PATCH] Remove the cached UVScale in gstate_c. Conversion is cheap enough to do directly from gstate, no point in caching. --- GPU/Common/DrawEngineCommon.cpp | 6 ++++-- GPU/Common/SoftwareTransformCommon.cpp | 4 +--- GPU/GPUCommon.cpp | 2 -- GPU/GPUCommonHW.cpp | 8 -------- GPU/GPUState.cpp | 3 ++- GPU/GPUState.h | 18 ------------------ GPU/GPUStateSIMDUtil.h | 6 ++++-- GPU/Software/SoftGpu.cpp | 3 --- GPU/Software/TransformUnit.cpp | 4 +++- unittest/TestVertexJit.cpp | 9 ++++----- 10 files changed, 18 insertions(+), 45 deletions(-) diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 9a2e1e6a2a..5cfc1389dd 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -232,7 +232,8 @@ bool DrawEngineCommon::TestBoundingBox(const void *vdata, const void *inds, int // TODO: Avoid normalization if just plain skinning. // Force software skinning. const u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode(), true); - ::NormalizeVertices(corners, temp_buffer, (const u8 *)vdata, indexLowerBound, indexUpperBound, gstate_c.uv, dec, vertType); + UVScale uvScale{}; // We don't care about UV. + ::NormalizeVertices(corners, temp_buffer, (const u8 *)vdata, indexLowerBound, indexUpperBound, uvScale, dec, vertType); IndexConverter conv(vertType, inds); for (int i = 0; i < vertexCount; i++) { verts[i * 3] = corners[conv(i)].pos.x; @@ -891,7 +892,7 @@ bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimiti numDrawVerts_ = numDrawVerts + 1; // Increment the uncached variable dv.verts = verts; dv.vertexCount = vertexCount; - dv.uvScale = gstate_c.uv; + dv.uvScale = LoadUVScaleOffset(gstate); // Does handle the unindexed case. GetIndexBounds(inds, vertexCount, vertTypeID, &dv.indexLowerBound, &dv.indexUpperBound); } @@ -1064,6 +1065,7 @@ Mat4F32 ComputeFinalProjMatrix() { 0.0f, }; + // TODO: Simply use Mat4F32 m(gstate_c.worldviewproj); Mat4F32 wv = Mul4x3By4x4(Mat4x3F32(gstate.worldMatrix), Mat4F32::Load4x3(gstate.viewMatrix)); Mat4F32 m = Mul4x4By4x4(wv, Mat4F32(gstate.projMatrix)); // NOTE: Applying the translation actually works pre-divide, since W is also affected. diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 390aa0dc07..a84bbcd793 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -1543,12 +1543,10 @@ bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GECommand cmd, const int stride = (int)dec->GetDecVtxFmt().stride; vertsTemp.resize(stride * verticesToDecode + 32); // Add some padding bytes for "over-writes". - UVScale uvScale{}; - LoadUVScaleOffsetVec(gstate).Store(&uvScale.uScale); - const u8 *startPos = verts + indexLowerBound * dec->VertexSize(); bool savedVertexFullAlpha = gstate_c.vertexFullAlpha; + const UVScale uvScale = LoadUVScaleOffset(gstate); dec->DecodeVerts(vertsTemp.data(), startPos, &uvScale, verticesToDecode); gstate_c.vertexFullAlpha = savedVertexFullAlpha; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 36b1edd434..7babc15025 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1325,8 +1325,6 @@ void GPUCommon::FlushImm() { SetDrawType(DRAW_PRIM, immPrim_); - gstate_c.UpdateUVScaleOffset(); - VirtualFramebuffer *vfb = nullptr; if (framebufferManager_) { bool changed; diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index f64f2110c0..1d54435528 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -967,8 +967,6 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { canExtend = false; } - gstate_c.UpdateUVScaleOffset(); - // cull mode int cullMode = gstate.getCullMode(); @@ -1190,22 +1188,18 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { // when texscale commands are in line with the prims like this, they actually have an effect // and requires us to stop extending strips anyway. gstate.cmdmem[GE_CMD_TEXSCALEU] = data; - gstate_c.uv.uScale = getFloat24(data); canExtend = false; break; case GE_CMD_TEXSCALEV: gstate.cmdmem[GE_CMD_TEXSCALEV] = data; - gstate_c.uv.vScale = getFloat24(data); canExtend = false; break; case GE_CMD_TEXOFFSETU: gstate.cmdmem[GE_CMD_TEXOFFSETU] = data; - gstate_c.uv.uOff = getFloat24(data); canExtend = false; break; case GE_CMD_TEXOFFSETV: gstate.cmdmem[GE_CMD_TEXOFFSETV] = data; - gstate_c.uv.vOff = getFloat24(data); canExtend = false; break; case GE_CMD_TEXLEVEL: @@ -1333,7 +1327,6 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) { gstate_c.submitType = SubmitType::BEZIER; int bytesRead = 0; - gstate_c.UpdateUVScaleOffset(); drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier"); gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_UVSCALEOFFSET); @@ -1405,7 +1398,6 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) { gstate_c.submitType = SubmitType::SPLINE; int bytesRead = 0; - gstate_c.UpdateUVScaleOffset(); drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline"); gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_UVSCALEOFFSET); diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index ccc970a32b..22a8bd8f5f 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -292,7 +292,6 @@ void GPUStateCache::DoState(PointerWrap &p) { textureSolidAlpha = old.textureSolidAlpha; vertexFullAlpha = old.vertexFullAlpha; skipDrawReason = old.skipDrawReason; - uv = old.uv; savedContextVersion = 0; } else { @@ -310,6 +309,8 @@ void GPUStateCache::DoState(PointerWrap &p) { Do(p, skipDrawReason); + // Legacy, remove in the next bump. + UVScale uv{}; Do(p, uv); bool oldFlipTexture = false; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 2da2e260c2..c30b2acfcf 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -26,7 +26,6 @@ #include "GPU/GPU.h" #include "GPU/ge_constants.h" #include "GPU/Common/ShaderCommon.h" -#include "Common/Math/SIMDHeaders.h" #include "Common/Math/lin/vec3.h" class PointerWrap; @@ -588,21 +587,6 @@ struct GPUStateCache { return useFlags_; } - void UpdateUVScaleOffset() { -#if defined(_M_SSE) - __m128i values = _mm_slli_epi32(_mm_load_si128((const __m128i *)&gstate.texscaleu), 8); - _mm_storeu_si128((__m128i *)&uv, values); -#elif PPSSPP_ARCH(ARM_NEON) - const uint32x4_t values = vshlq_n_u32(vld1q_u32((const u32 *)&gstate.texscaleu), 8); - vst1q_u32((u32 *)&uv, values); -#else - uv.uScale = getFloat24(gstate.texscaleu); - uv.vScale = getFloat24(gstate.texscalev); - uv.uOff = getFloat24(gstate.texoffsetu); - uv.vOff = getFloat24(gstate.texoffsetv); -#endif - } - private: u32 useFlags_; public: @@ -625,8 +609,6 @@ public: int skipDrawReason; - UVScale uv; - bool bgraTexture; bool needShaderTexClamp; bool textureIsArray; diff --git a/GPU/GPUStateSIMDUtil.h b/GPU/GPUStateSIMDUtil.h index b7d956ac94..465d37f8c2 100644 --- a/GPU/GPUStateSIMDUtil.h +++ b/GPU/GPUStateSIMDUtil.h @@ -11,6 +11,8 @@ inline Vec4F32 LoadViewportScaleVec(const GEState &gstate) { // We ignore the last member. return Vec4F32::LoadF24x4(&gstate.viewportxscale); } -inline Vec4F32 LoadUVScaleOffsetVec(const GEState &gstate) { - return Vec4F32::LoadF24x4(&gstate.texscaleu); +inline UVScale LoadUVScaleOffset(const GEState &gstate) { + UVScale uvScale; + Vec4F32::LoadF24x4(&gstate.texscaleu).Store(&uvScale.uScale); + return uvScale; } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 9cb12b5078..336df8343c 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -863,7 +863,6 @@ void SoftGPU::Execute_Prim(u32 op, u32 diff) { cyclesExecuted += EstimatePerVertexCost() * count; int bytesRead; - gstate_c.UpdateUVScaleOffset(); drawEngine_->transformUnit.SetDirty(dirtyFlags_); drawEngine_->transformUnit.SubmitPrimitive(verts, indices, prim, count, gstate.vertType, &bytesRead, drawEngine_); dirtyFlags_ = drawEngine_->transformUnit.GetDirty(); @@ -916,7 +915,6 @@ void SoftGPU::Execute_Bezier(u32 op, u32 diff) { SetDrawType(DRAW_BEZIER, PatchPrimToPrim(surface.primType)); int bytesRead = 0; - gstate_c.UpdateUVScaleOffset(); drawEngine_->transformUnit.SetDirty(dirtyFlags_); drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier"); dirtyFlags_ = drawEngine_->transformUnit.GetDirty(); @@ -970,7 +968,6 @@ void SoftGPU::Execute_Spline(u32 op, u32 diff) { SetDrawType(DRAW_SPLINE, PatchPrimToPrim(surface.primType)); int bytesRead = 0; - gstate_c.UpdateUVScaleOffset(); drawEngine_->transformUnit.SetDirty(dirtyFlags_); drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline"); dirtyFlags_ = drawEngine_->transformUnit.GetDirty(); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index f57c1fcc02..706bac6bab 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -29,6 +29,7 @@ #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SoftwareTransformCommon.h" #include "GPU/Common/VertexReader.h" +#include "GPU/GPUStateSIMDUtil.h" #include "Common/Math/SIMDHeaders.h" #include "GPU/Software/BinManager.h" #include "GPU/Software/Clipper.h" @@ -482,7 +483,8 @@ public: GetIndexBounds(indices, vertex_count, vertex_type, &lowerBound_, &upperBound_); if (vertex_count != 0) { const int count = upperBound_ - lowerBound_ + 1; - vdecoder.DecodeVerts(base, (const u8 *)vertices + vdecoder.VertexSize() * lowerBound_, &gstate_c.uv, count); + const UVScale uvScale = LoadUVScaleOffset(gstate); + vdecoder.DecodeVerts(base, (const u8 *)vertices + vdecoder.VertexSize() * lowerBound_, &uvScale, count); } // If we're only using a subset of verts, it's better to decode with random access (usually.) diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp index 1646a67bf9..119c6394bb 100644 --- a/unittest/TestVertexJit.cpp +++ b/unittest/TestVertexJit.cpp @@ -27,6 +27,8 @@ #include "unittest/TestVertexJit.h" #include "unittest/UnitTest.h" +const UVScale g_uvScale{1.0f, 1.0f, 0.0f, 0.0f}; + class VertexDecoderTestHarness { static const int BUFFER_SIZE = 64 * 65536; static const int ROUNDS = 200; @@ -37,9 +39,6 @@ public: src_ = new u8[BUFFER_SIZE]; dst_ = new u8[BUFFER_SIZE]; cache_ = new VertexDecoderJitCache(); - - gstate_c.uv.uScale = 1.0f; - gstate_c.uv.vScale = 1.0f; } ~VertexDecoderTestHarness() { delete [] src_; @@ -69,7 +68,7 @@ public: void Execute(int vtype, int count, bool useJit) { SetupExecute(vtype, useJit); - dec_->DecodeVerts(dst_, src_, &gstate_c.uv, count); + dec_->DecodeVerts(dst_, src_, &g_uvScale, count); } double ExecuteTimed(int vtype, int count, bool useJit) { @@ -79,7 +78,7 @@ public: double st = time_now_d(); do { for (int j = 0; j < ROUNDS; ++j) { - dec_->DecodeVerts(dst_, src_, &gstate_c.uv, count); + dec_->DecodeVerts(dst_, src_, &g_uvScale, count); ++total; } } while (time_now_d() - st < 0.5);