Merge pull request #21881 from hrydgard/render-code-cleanup

Misc render code cleanup - remove cached UVScale, etc
This commit is contained in:
Henrik Rydgård
2026-07-03 13:48:06 +02:00
committed by GitHub
29 changed files with 107 additions and 143 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, 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.
+3 -6
View File
@@ -154,10 +154,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
ReplaceBlendType replaceBlend = static_cast<ReplaceBlendType>(id.Bits(FS_BIT_REPLACE_BLEND, 3));
bool blueToAlpha = false;
if (replaceBlend == ReplaceBlendType::REPLACE_BLEND_BLUE_TO_ALPHA) {
blueToAlpha = true;
}
const bool blueToAlpha = replaceBlend == ReplaceBlendType::REPLACE_BLEND_BLUE_TO_ALPHA;
bool isModeClear = id.Bit(FS_BIT_CLEARMODE);
@@ -854,8 +851,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
// This happens before fog is applied.
*uniformMask |= DIRTY_TEX_ALPHA_MUL;
// We only need a clamp if the color will be further processed. Otherwise the hardware color conversion will clamp for us.
// TODO: Clamp is so cheap that this probably is pretty meaningless.
// We only need a clamp if the color will be further processed directly in the shader.
// Otherwise the hardware color conversion will clamp for us (unless we start using FP formats for fake HDR but then we probably don't want the clamp...)
if (enableFog || enableColorTest || replaceBlend != REPLACE_BLEND_NO || simulateLogicOpType != LOGICOPTYPE_NORMAL || colorWriteMask || blueToAlpha) {
WRITE(p, " v.rgb = clamp(v.rgb * u_texNoAlphaMul.y, 0.0, 1.0);\n");
} else {
+1 -1
View File
@@ -313,7 +313,7 @@ void FramebufferManagerCommon::EstimateDrawingSize(u32 fb_address, int fb_stride
DEBUG_LOG(Log::G3D, "Est: %08x V: %ix%i, R: %ix%i, S: %ix%i, STR: %i, THR:%i, Z:%08x = %ix%i %s", fb_address, viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough(), gstate.isDepthWriteEnabled() ? gstate.getDepthBufAddress() : 0, drawing_width, drawing_height, margin ? " (margin!)" : "");
}
void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate) {
void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GEState &gstate) {
// GetFramebufferHeuristicInputs is only called from rendering, and thus, it's VRAM.
params->fb_address = gstate.getFrameBufRawAddress() | 0x04000000;
params->fb_stride = gstate.FrameBufStride();
+3 -3
View File
@@ -195,10 +195,10 @@ struct FramebufferHeuristicParams {
int16_t scissorBottom;
};
struct GPUgstate;
extern GPUgstate gstate;
struct GEState;
extern GEState gstate;
void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate);
void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GEState &gstate);
enum BindFramebufferColorFlags {
BINDFBCOLOR_SKIP_COPY = 0,
+1 -1
View File
@@ -621,7 +621,7 @@ bool GEExpressionFunctions::parseSymbol(char *str, uint32_t &symbolValue) {
}
uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) {
GPUgstate state = gpu_->GetGState();
GEState state = gpu_->GetGState();
if (referenceIndex < 0x100) {
GECmdFormat fmt = GECmdInfoByCmd(GECommand(referenceIndex)).cmdFmt;
uint32_t value = state.cmdmem[referenceIndex];
+1 -1
View File
@@ -59,7 +59,7 @@ bool NeedsTestDiscard();
bool IsDepthTestEffectivelyDisabled();
bool IsStencilTestOutputDisabled();
inline bool CanForceBilinear(const GPUgstate &gstate) {
inline bool CanForceBilinear(const GEState &gstate) {
return ((!gstate.isColorTestEnabled() || IsColorTestTriviallyTrue()) && (!gstate.isAlphaTestEnabled() || IsAlphaTestTriviallyTrue()));
}
+1 -1
View File
@@ -254,7 +254,7 @@ void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms) {
}
}
void UpdateFogCoef(const GPUgstate &state, float fogCoef[2]) {
void UpdateFogCoef(const GEState &state, float fogCoef[2]) {
fogCoef[0] = getFloat24(gstate.fog1);
fogCoef[1] = getFloat24(gstate.fog2);
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
+2 -2
View File
@@ -123,10 +123,10 @@ void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms);
uint32_t PackLightControlBits();
uint32_t PackDepalBits();
void UpdateFogCoef(const GPUgstate &state, float fogCoef[2]);
void UpdateFogCoef(const GEState &state, float fogCoef[2]);
// This happens so much that I want it inline.
inline void UpdateUVScaleOff(const GPUgstate &state, float uvScaleOff[4]) {
inline void UpdateUVScaleOff(const GEState &state, float uvScaleOff[4]) {
float widthFactor;
float heightFactor;
if (gstate_c.textureIsFramebuffer) {
+5 -7
View File
@@ -80,7 +80,7 @@ static void RotateUV(TransformedVertex v[4]) {
}
}
static bool ShouldApplySpriteBorderFix(const GPUgstate &gstate) {
static bool ShouldApplySpriteBorderFix(const GEState &gstate) {
return gstate.isMagnifyFilteringEnabled() && gstate.isAlphaBlendEnabled() && gstate.getBlendFuncA() != GE_SRCBLEND_FIXA && gstate.isTextureAlphaUsed();
}
@@ -407,7 +407,7 @@ SoftwareTransformAction RunSoftwareTransform(SoftwareTransformParams &params, in
// Modifies the vertices in-place. Applies viewport and projection.
// TODO: SIMD.
static void ProjectVertices(const GPUgstate &gstate, TransformedVertex *transformed, int vertexCount) {
static void ProjectVertices(const GEState &gstate, TransformedVertex *transformed, int vertexCount) {
#if 0
Lin::Vec3 vpOffset(gstate.getViewportXCenter(), gstate.getViewportYCenter(), gstate.getViewportZCenter());
Lin::Vec3 vpScale(gstate.getViewportXScale(), gstate.getViewportYScale(), gstate.getViewportZScale());
@@ -1366,13 +1366,13 @@ static bool ExpandPoints(int vertexCount, int &maxIndex, int vertsSize, u16 *&in
// 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(SimpleVertex *sverts, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, const VertexDecoder *dec, u32 vertType) {
u32 NormalizeVertices(SimpleVertex *sverts, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, const UVScale &uvScale, const 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.
// Actually if software transform is off, we could enforce it in the vertex decoder lookup before calling this,
// avoiding having to implement it again below.
const int count = upperBound + 1 - lowerBound;
dec->DecodeVerts(bufPtr, inPtr + lowerBound * dec->VertexSize(), &gstate_c.uv, count);
dec->DecodeVerts(bufPtr, inPtr + lowerBound * dec->VertexSize(), &uvScale, count);
// OK, morphing eliminated but bones still remain to be taken care of.
// Let's do a partial software transform where we only do skinning.
@@ -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;
+1 -1
View File
@@ -83,7 +83,7 @@ SoftwareTransformAction RunSoftwareTransform(SoftwareTransformParams &params, in
class DrawEngineCommon;
// Slow. See description in the cpp file.
u32 NormalizeVertices(SimpleVertex *sverts, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, const VertexDecoder *dec, u32 vertType);
u32 NormalizeVertices(SimpleVertex *sverts, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, const UVScale &uvScale, const VertexDecoder *dec, u32 vertType);
// In the returned data, you should subtract the value of lowerIndexBound from the indices to get the actual vertex index in the vertices array.
// This is because some draws in some games use very large indices, but they only use a small range of them in each PRIM submission.
+13 -20
View File
@@ -159,6 +159,8 @@ private:
}
static void CalcWeights(float t, const float *knots, const KnotDiv &div, Weight &w) {
// TODO: This SSE code doesn't look like it's worth it. We need to parallelize across another
// dimension.
#ifdef _M_SSE
const __m128 knot012 = _mm_loadu_ps(knots);
const __m128 t012 = _mm_sub_ps(_mm_set_ps1(t), knot012);
@@ -463,8 +465,9 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
u16 index_lower_bound = 0;
u16 index_upper_bound = num_points - 1;
IndexConverter ConvertIndex(vertType, indices);
if (indices)
if (indices) {
GetIndexBounds(indices, num_points, vertType, &index_lower_bound, &index_upper_bound);
}
u32 vertTypeID = GetVertTypeID(vertType, gstate.getUVGenMode(), applySkinInDecode_);
VertexDecoder *origVDecoder = GetVertexDecoder(vertTypeID);
@@ -485,7 +488,8 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
}
const u32 origVertType = vertType;
vertType = ::NormalizeVertices(simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, origVDecoder, vertType);
UVScale neutralUVScale{1.0f, 1.0f, 0.0f, 0.0f}; // Avoid rescaling UV during normalization, it will happen anyway later (in DispatchSubmitPrim). Although ideally we should avoid running Decode at all there.
vertType = ::NormalizeVertices(simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, neutralUVScale, origVDecoder, vertType);
VertexDecoder *vdecoder = GetVertexDecoder(vertType);
@@ -500,8 +504,9 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
ERROR_LOG(Log::G3D, "Failed to allocate space for control point pointers, skipping curve draw");
return;
}
for (int idx = 0; idx < num_points; idx++)
for (int idx = 0; idx < num_points; idx++) {
points[idx] = simplified_control_points + (indices ? ConvertIndex(idx) : idx);
}
OutputBuffers output;
output.vertices = (SimpleVertex *)(decoded_ + DECODED_VERTEX_BUFFER_SIZE / 2);
@@ -513,23 +518,15 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
surface.Init(maxVerts);
ControlPoints cpoints(points, num_points, managedBuf);
if (cpoints.IsValid())
if (cpoints.IsValid()) {
// Run the tessellation!
SoftwareTessellation(output, surface, origVertType, cpoints);
else
} else {
ERROR_LOG(Log::G3D, "Failed to allocate space for control point values, skipping curve draw");
}
u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
UVScale prevUVScale;
if (origVertType & GE_VTYPE_TC_MASK) {
// We scaled during Normalize already so let's turn it off when drawing.
prevUVScale = gstate_c.uv;
gstate_c.uv.uScale = 1.0f;
gstate_c.uv.vScale = 1.0f;
gstate_c.uv.uOff = 0;
gstate_c.uv.vOff = 0;
}
vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), applySkinInDecode_);
int generatedBytesRead;
if (output.count) {
@@ -537,11 +534,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, true, &generatedBytesRead, flags);
}
if (flushOnParams_)
if (flushOnParams_) {
Flush();
if (origVertType & GE_VTYPE_TC_MASK) {
// If analysis says this is uninitialized, it's wrong.
gstate_c.uv = prevUVScale;
}
}
+23 -22
View File
@@ -27,7 +27,7 @@
#include "Core/Config.h"
#define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f)
inline int half_ceil(int x) { return (x + 1) / 2; } // Integer ceil = (int)ceil((float)x / 2.0f)
class SimpleBufferManager;
@@ -61,8 +61,8 @@ struct SurfaceInfo {
break;
case SplineQuality::MEDIUM_QUALITY:
// Don't cut below 2, though.
if (tess_u > 2) tess_u = HALF_CEIL(tess_u);
if (tess_v > 2) tess_v = HALF_CEIL(tess_v);
if (tess_u > 2) tess_u = half_ceil(tess_u);
if (tess_v > 2) tess_v = half_ceil(tess_v);
break;
default:
break;
@@ -140,7 +140,8 @@ struct SplineSurface : public SurfaceInfo {
};
struct Weight {
float basis[4], deriv[4];
float basis[4];
float deriv[4];
};
template<class T>
@@ -207,10 +208,10 @@ struct NAME { \
} \
};
template<typename Func, int NumParams, class Dispatcher>
template<typename Func, int NumParams, class Dispatcher>
class TemplateParameterDispatcher {
/* Store all combinations of template functions into an array */
// Store all combinations of template functions into an array
template<int LoopCount, int Index = 0, bool ...Params>
struct Initializer {
static void Init(Func funcs[]) {
@@ -218,7 +219,7 @@ class TemplateParameterDispatcher {
Initializer<LoopCount - 1, (Index << 1) + 0, false, Params...>::Init(funcs); // false
}
};
/* Specialized for terminates the recursive loop */
// Specialized for terminates the recursive loop
template<int Index, bool ...Params>
struct Initializer<0, Index, Params...> {
static void Init(Func funcs[]) {
@@ -226,19 +227,19 @@ class TemplateParameterDispatcher {
}
};
private:
Func funcs[1 << NumParams]; /* Function pointers array */
public:
TemplateParameterDispatcher() {
Initializer<NumParams>::Init(funcs);
}
Func GetFunc(const bool params[]) const {
/* Convert bool parameters to index of the array */
int index = 0;
for (int i = 0; i < NumParams; ++i)
index |= params[i] << i;
return funcs[index];
}
private:
Func funcs[1 << NumParams]; /* Function pointers array */
public:
TemplateParameterDispatcher() {
Initializer<NumParams>::Init(funcs);
}
Func GetFunc(const bool params[]) const {
// Convert bool parameters to index of the array
int index = 0;
for (int i = 0; i < NumParams; ++i) {
index |= params[i] << i;
}
return funcs[index];
}
};
+1 -1
View File
@@ -2301,7 +2301,7 @@ static bool CanDepalettizeBufferAs(GETextureFormat texFormat, GEBufferFormat buf
// But we only do it if the mask/shift exactly matches a color channel, else something different might be going
// on and we definitely don't want to interpolate.
// Great enhancement for Test Drive and Manhunt 2.
static bool CanUseSmoothDepal(const GPUgstate &gstate, GEBufferFormat framebufferFormat, const ClutTexture &clutTexture) {
static bool CanUseSmoothDepal(const GEState &gstate, GEBufferFormat framebufferFormat, const ClutTexture &clutTexture) {
for (int i = 0; i < ClutTexture::MAX_RAMPS; i++) {
if (gstate.getClutIndexStartPos() == clutTexture.rampStarts[i] &&
gstate.getClutIndexMask() < clutTexture.rampLengths[i]) {
+2 -2
View File
@@ -68,7 +68,7 @@ static bool lastWasFramebuffer;
static u32 pauseSetCmdValue;
// This is used only to highlight differences. Should really be owned by the debugger.
static GPUgstate lastGState;
static GEState lastGState;
const char *PauseActionToString(PauseAction action) {
switch (action) {
@@ -291,7 +291,7 @@ bool GPU_FlushDrawing() {
return true;
}
const GPUgstate &LastState() {
const GEState &LastState() {
return lastGState;
}
+1 -1
View File
@@ -47,5 +47,5 @@ namespace GPUStepping {
bool GPU_FlushDrawing();
// Can be used to highlight differences in a debugger.
const GPUgstate &LastState();
const GEState &LastState();
};
+1 -3
View File
@@ -1325,8 +1325,6 @@ void GPUCommon::FlushImm() {
SetDrawType(DRAW_PRIM, immPrim_);
gstate_c.UpdateUVScaleOffset();
VirtualFramebuffer *vfb = nullptr;
if (framebufferManager_) {
bool changed;
@@ -1707,7 +1705,7 @@ u32 GPUCommon::GetIndexAddress() {
return gstate_c.indexAddr;
}
const GPUgstate &GPUCommon::GetGState() {
const GEState &GPUCommon::GetGState() {
return gstate;
}
+2 -2
View File
@@ -30,7 +30,7 @@ class TextureCacheCommon;
class DrawEngineCommon;
class GraphicsContext;
struct PspGeListArgs;
struct GPUgstate;
struct GEState;
class PointerWrap;
struct VirtualFramebuffer;
@@ -221,7 +221,7 @@ public:
u32 GetRelativeAddress(u32 data);
u32 GetVertexAddress();
u32 GetIndexAddress();
const GPUgstate &GetGState();
const GEState &GetGState();
void SetCmdValue(u32 op);
DisplayList* getList(int listid) {
-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);
+7 -6
View File
@@ -27,7 +27,7 @@
#include "GPU/GPUState.h"
// This must be aligned so that the matrices within are aligned.
alignas(16) GPUgstate gstate;
alignas(16) GEState gstate;
// Let's align this one too for good measure.
alignas(16) GPUStateCache gstate_c;
@@ -102,7 +102,7 @@ static const u32_le *LoadMatrix(const u32_le *cmds, float *mtx, int sz) {
return cmds;
}
void GPUgstate::Reset() {
void GEState::Reset() {
memset(gstate.cmdmem, 0, sizeof(gstate.cmdmem));
for (int i = 0; i < 256; i++) {
gstate.cmdmem[i] = i << 24;
@@ -120,7 +120,7 @@ void GPUgstate::Reset() {
gstate_c.Dirty(DIRTY_WORLD_VIEW_PROJ_MATRIX | DIRTY_VIEW_PROJ_MATRIX | DIRTY_CULL_MATRIX);
}
void GPUgstate::Save(u32_le *ptr) {
void GEState::Save(u32_le *ptr) {
// Not sure what the first 10 values are, exactly, but these seem right.
ptr[5] = gstate_c.vertexAddr;
ptr[6] = gstate_c.indexAddr;
@@ -168,7 +168,7 @@ void GPUgstate::Save(u32_le *ptr) {
}
}
void GPUgstate::FastLoadBoneMatrix(u32 addr) {
void GEState::FastLoadBoneMatrix(u32 addr) {
const u32 *src = (const u32 *)Memory::GetPointerUnchecked(addr);
u32 num = boneMatrixNumber;
u32 *dst = (u32 *)(boneMatrix + (num & 0x7F));
@@ -204,7 +204,7 @@ void GPUgstate::FastLoadBoneMatrix(u32 addr) {
gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
}
void GPUgstate::Restore(const u32_le *ptr) {
void GEState::Restore(const u32_le *ptr) {
// Not sure what the first 10 values are, exactly, but these seem right.
gstate_c.vertexAddr = ptr[5];
gstate_c.indexAddr = ptr[6];
@@ -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;
+2 -20
View File
@@ -26,12 +26,11 @@
#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;
struct GPUgstate {
struct GEState {
// Getting rid of this ugly union in favor of the accessor functions
// might be a good idea....
union {
@@ -514,7 +513,7 @@ enum class SubmitType {
SPLINE,
};
extern GPUgstate gstate;
extern GEState gstate;
struct GPUStateCache {
bool Use(u32 flags) const { return (useFlags_ & flags) != 0; } // Return true if ANY of flags are true.
@@ -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;
+6 -4
View File
@@ -3,14 +3,16 @@
#include "Common/Math/CrossSIMD.h"
#include "GPU/GPUState.h"
inline Vec4F32 LoadViewportOffsetVec(const GPUgstate &gstate) {
inline Vec4F32 LoadViewportOffsetVec(const GEState &gstate) {
// We ignore the last member.
return Vec4F32::LoadF24x4(&gstate.viewportxcenter);
}
inline Vec4F32 LoadViewportScaleVec(const GPUgstate &gstate) {
inline Vec4F32 LoadViewportScaleVec(const GEState &gstate) {
// We ignore the last member.
return Vec4F32::LoadF24x4(&gstate.viewportxscale);
}
inline Vec4F32 LoadUVScaleOffsetVec(const GPUgstate &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.)
+1 -1
View File
@@ -1643,7 +1643,7 @@ void ImGeStateWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuDebu
bool sectionOpen = false;
for (size_t i = 0; i < numRows; i++) {
const GECmdInfo &info = GECmdInfoByCmd(rows[i].cmd);
const GPUgstate &lastState = GPUStepping::LastState();
const GEState &lastState = GPUStepping::LastState();
bool diff = lastState.cmdmem[rows[i].cmd] != gstate.cmdmem[rows[i].cmd];
if (rows[i].header) {
+9 -9
View File
@@ -377,7 +377,7 @@ void CGEDebugger::SetupPreviews() {
}
}
void CGEDebugger::DescribePrimaryPreview(const GPUgstate &state, char desc[256]) {
void CGEDebugger::DescribePrimaryPreview(const GEState &state, char desc[256]) {
if (primaryTrackX_ < primaryBuffer_->GetStride() && primaryTrackY_ < primaryBuffer_->GetHeight()) {
u32 pix = primaryBuffer_->GetRawPixel(primaryTrackX_, primaryTrackY_);
DescribePixel(pix, primaryBuffer_->GetFormat(), primaryTrackX_, primaryTrackY_, desc);
@@ -410,7 +410,7 @@ void CGEDebugger::DescribePrimaryPreview(const GPUgstate &state, char desc[256])
}
}
void CGEDebugger::DescribeSecondPreview(const GPUgstate &state, char desc[256]) {
void CGEDebugger::DescribeSecondPreview(const GEState &state, char desc[256]) {
if (secondTrackX_ != 0xFFFFFFFF) {
uint32_t x = secondTrackX_;
uint32_t y = secondTrackY_;
@@ -557,7 +557,7 @@ void CGEDebugger::UpdatePreviews() {
return;
}
GPUgstate state{};
GEState state{};
if (gpu != nullptr) {
state = gpu->GetGState();
@@ -663,7 +663,7 @@ int CGEDebugger::HasTabIndex(GEDebuggerTab *tab, GETabPosition pos) {
return -1;
}
u32 CGEDebugger::TexturePreviewFlags(const GPUgstate &state) {
u32 CGEDebugger::TexturePreviewFlags(const GEState &state) {
if (state.isTextureAlphaUsed() && !forceOpaque_) {
return SimpleGLWindow::ALPHA_BLEND | SimpleGLWindow::RESIZE_BEST_CENTER;
} else {
@@ -671,7 +671,7 @@ u32 CGEDebugger::TexturePreviewFlags(const GPUgstate &state) {
}
}
void CGEDebugger::UpdatePrimaryPreview(const GPUgstate &state) {
void CGEDebugger::UpdatePrimaryPreview(const GEState &state) {
bool bufferResult = false;
u32 flags = SimpleGLWindow::ALPHA_IGNORE | SimpleGLWindow::RESIZE_SHRINK_CENTER;
@@ -724,7 +724,7 @@ void CGEDebugger::UpdatePrimaryPreview(const GPUgstate &state) {
}
}
void CGEDebugger::UpdateSecondPreview(const GPUgstate &state) {
void CGEDebugger::UpdateSecondPreview(const GEState &state) {
bool bufferResult = false;
SetupPreviews();
@@ -784,7 +784,7 @@ void CGEDebugger::PrimaryPreviewHover(int x, int y) {
desc[0] = 0;
} else if (x < 0 || y < 0) {
// This means they left the area.
GPUgstate state{};
GEState state{};
if (gpu != nullptr) {
state = gpu->GetGState();
}
@@ -812,7 +812,7 @@ void CGEDebugger::SecondPreviewHover(int x, int y) {
desc[0] = 0;
} else if (x < 0 || y < 0) {
// This means they left the area.
GPUgstate state{};
GEState state{};
if (gpu != nullptr) {
state = gpu->GetGState();
}
@@ -834,7 +834,7 @@ void CGEDebugger::SecondPreviewHover(int x, int y) {
}
void CGEDebugger::UpdateTextureLevel(int level) {
GPUgstate state{};
GEState state{};
if (gpu != nullptr) {
state = gpu->GetGState();
}
+6 -6
View File
@@ -43,7 +43,7 @@ class TabStateSettings;
class TabVertices;
class TabMatrices;
class TabStateWatch;
struct GPUgstate;
struct GEState;
enum class GETabPosition {
LEFT = 1,
@@ -100,8 +100,8 @@ protected:
private:
void SetupPreviews();
void UpdatePreviews();
void UpdatePrimaryPreview(const GPUgstate &state);
void UpdateSecondPreview(const GPUgstate &state);
void UpdatePrimaryPreview(const GEState &state);
void UpdateSecondPreview(const GEState &state);
static u32 PrimPreviewOp();
void UpdatePrimPreview(u32 op, int which);
void CleanupPrimPreview();
@@ -109,8 +109,8 @@ private:
void UpdateSize(WORD width, WORD height);
void SavePosition();
void UpdateTextureLevel(int level);
void DescribePrimaryPreview(const GPUgstate &state, char desc[256]);
void DescribeSecondPreview(const GPUgstate &state, char desc[256]);
void DescribePrimaryPreview(const GEState &state, char desc[256]);
void DescribeSecondPreview(const GEState &state, char desc[256]);
void PrimaryPreviewHover(int x, int y);
void SecondPreviewHover(int x, int y);
void PreviewExport(const GPUDebugBuffer *buffer);
@@ -122,7 +122,7 @@ private:
int HasTabIndex(GEDebuggerTab *tab, GETabPosition pos);
void CheckTabMessage(TabControl *t, GETabPosition pos, LPARAM lParam);
u32 TexturePreviewFlags(const GPUgstate &state);
u32 TexturePreviewFlags(const GEState &state);
SimpleGLWindow *primaryWindow = nullptr;
SimpleGLWindow *secondWindow = nullptr;
+2 -2
View File
@@ -328,7 +328,7 @@ bool CtrlMatrixList::OnColPrePaint(int row, int col, LPNMLVCUSTOMDRAW msg) {
return false;
}
bool CtrlMatrixList::ColChanged(const GPUgstate &lastState, const GPUgstate &state, int row, int col) {
bool CtrlMatrixList::ColChanged(const GEState &lastState, const GEState &state, int row, int col) {
union {
float f;
uint32_t u;
@@ -340,7 +340,7 @@ bool CtrlMatrixList::ColChanged(const GPUgstate &lastState, const GPUgstate &sta
return newVal.u != oldVal.u;
}
bool CtrlMatrixList::GetValue(const GPUgstate &state, int row, int col, float &val) {
bool CtrlMatrixList::GetValue(const GEState &state, int row, int col, float &val) {
if (!gpu || row < 0 || row >= MATRIXLIST_ROW_COUNT || col < 0 || col >= MATRIXLIST_COL_COUNT)
return false;
+2 -2
View File
@@ -83,8 +83,8 @@ protected:
bool OnColPrePaint(int row, int col, LPNMLVCUSTOMDRAW msg) override;
private:
bool GetValue(const GPUgstate &state, int row, int col, float &val);
bool ColChanged(const GPUgstate &lastState, const GPUgstate &state, int row, int col);
bool GetValue(const GEState &state, int row, int col, float &val);
bool ColChanged(const GEState &lastState, const GEState &state, int row, int col);
void ToggleBreakpoint(int row);
void PromptBreakpointCond(int row);
};
+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);