Remove the cached UVScale in gstate_c. Conversion is cheap enough to do directly from gstate, no point in caching.

This commit is contained in:
Henrik Rydgård
2026-07-03 13:10:05 +02:00
parent e2fbf295cf
commit 6d2948a09b
10 changed files with 18 additions and 45 deletions
+4 -2
View File
@@ -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.
+1 -3
View File
@@ -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;
-2
View File
@@ -1325,8 +1325,6 @@ void GPUCommon::FlushImm() {
SetDrawType(DRAW_PRIM, immPrim_);
gstate_c.UpdateUVScaleOffset();
VirtualFramebuffer *vfb = nullptr;
if (framebufferManager_) {
bool changed;
-8
View File
@@ -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);
+2 -1
View File
@@ -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;
-18
View File
@@ -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;
+4 -2
View File
@@ -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;
}
-3
View File
@@ -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();
+3 -1
View File
@@ -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.)
+4 -5
View File
@@ -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);