From bb2fb12edd2b0a0aff4116420d254c56409c005e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 5 Apr 2014 01:25:04 -0700 Subject: [PATCH 1/4] Inline SetupVertexDecoder() in SubmitPrim(). Everything SubmitPrim() calls is expensive... --- GPU/GLES/TransformPipeline.cpp | 8 ++++++-- GPU/GLES/TransformPipeline.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index d7b6932672..951b9fc276 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -255,9 +255,13 @@ VertexDecoder *TransformDrawEngine::GetVertexDecoder(u32 vtype) { } void TransformDrawEngine::SetupVertexDecoder(u32 vertType) { + SetupVertexDecoderInternal(vertType); +} + +inline void TransformDrawEngine::SetupVertexDecoderInternal(u32 vertType) { // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it // into the top of the verttype where there are unused bits. - u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); + const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); // If vtype has changed, setup the vertex decoder. // TODO: Simply cache the setup decoders instead. @@ -280,7 +284,7 @@ void TransformDrawEngine::SubmitPrim(void *verts, void *inds, GEPrimitiveType pr } prevPrim_ = prim; - SetupVertexDecoder(vertType); + SetupVertexDecoderInternal(vertType); dec_->IncrementStat(STAT_VERTSSUBMITTED, vertexCount); diff --git a/GPU/GLES/TransformPipeline.h b/GPU/GLES/TransformPipeline.h index c0c146cbda..4176168890 100644 --- a/GPU/GLES/TransformPipeline.h +++ b/GPU/GLES/TransformPipeline.h @@ -124,6 +124,7 @@ public: void ClearTrackedVertexArrays(); void SetupVertexDecoder(u32 vertType); + inline void SetupVertexDecoderInternal(u32 vertType); // This requires a SetupVertexDecoder call first. int EstimatePerVertexCost() { From cbb6c01d4c35fbd240ca2106ac370049cec7b4b5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 5 Apr 2014 01:41:54 -0700 Subject: [PATCH 2/4] Avoid some debug stats when disabled. This function can get called a lot sometimes, and an if helps on ARM a little. --- GPU/GPUCommon.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 679b6fa37e..8fd9f501c2 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -559,12 +559,14 @@ void GPUCommon::SlowRunLoop(DisplayList &list) // The newPC parameter is used for jumps, we don't count cycles between. void GPUCommon::UpdatePC(u32 currentPC, u32 newPC) { // Rough estimate, 2 CPU ticks (it's double the clock rate) per GPU instruction. - int executed = (currentPC - cycleLastPC) / 4; + u32 executed = (currentPC - cycleLastPC) / 4; cyclesExecuted += 2 * executed; - gpuStats.otherGPUCycles += 2 * executed; cycleLastPC = newPC == 0 ? currentPC : newPC; - gpuStats.gpuCommandsAtCallLevel[std::min(currentList->stackptr, 3)] += executed; + if (g_Config.bShowDebugStats) { + gpuStats.otherGPUCycles += 2 * executed; + gpuStats.gpuCommandsAtCallLevel[std::min(currentList->stackptr, 3)] += executed; + } // Exit the runloop and recalculate things. This happens a lot in some games. easy_guard innerGuard(listLock); From 82df1b1fa88a572794a30f5f2ef05e6f613fda14 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 5 Apr 2014 12:04:10 -0700 Subject: [PATCH 3/4] Simplify UpdatePC() a bit more. --- GPU/GPUCommon.cpp | 4 ++-- GPU/GPUCommon.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 8fd9f501c2..5fab34bdb8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -561,7 +561,7 @@ void GPUCommon::UpdatePC(u32 currentPC, u32 newPC) { // Rough estimate, 2 CPU ticks (it's double the clock rate) per GPU instruction. u32 executed = (currentPC - cycleLastPC) / 4; cyclesExecuted += 2 * executed; - cycleLastPC = newPC == 0 ? currentPC : newPC; + cycleLastPC = currentPC; if (g_Config.bShowDebugStats) { gpuStats.otherGPUCycles += 2 * executed; @@ -571,7 +571,7 @@ void GPUCommon::UpdatePC(u32 currentPC, u32 newPC) { // Exit the runloop and recalculate things. This happens a lot in some games. easy_guard innerGuard(listLock); if (currentList) - downcount = currentList->stall == 0 ? 0x0FFFFFFF : (currentList->stall - cycleLastPC) / 4; + downcount = currentList->stall == 0 ? 0x0FFFFFFF : (currentList->stall - currentPC) / 4; else downcount = 0; } diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 6f53879939..c25e98e8db 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -81,7 +81,10 @@ protected: // To avoid virtual calls to PreExecuteOp(). virtual void FastRunLoop(DisplayList &list) = 0; void SlowRunLoop(DisplayList &list); - void UpdatePC(u32 currentPC, u32 newPC = 0); + void UpdatePC(u32 currentPC, u32 newPC); + void UpdatePC(u32 currentPC) { + UpdatePC(currentPC, currentPC); + } void UpdateState(GPUState state); void PopDLQueue(); void CheckDrawSync(); From d91ad87daa0b4ee3ee8b7869ea3c916c7610ce85 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 5 Apr 2014 12:32:10 -0700 Subject: [PATCH 4/4] Small perf improvements in DecodeVertsStep(). --- GPU/GLES/TransformPipeline.cpp | 54 +++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index 951b9fc276..1d0218e5a1 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -377,33 +377,45 @@ void TransformDrawEngine::DecodeVertsStep() { // 1. Look ahead to find the max index, only looking as "matching" drawcalls. // Expand the lower and upper bounds as we go. - int j = i + 1; int lastMatch = i; - while (j < numDrawCalls) { - if (drawCalls[j].verts != dc.verts) - break; - if (uvScale && memcmp(&uvScale[j], &uvScale[i], sizeof(uvScale[0])) != 0) - break; + const int total = numDrawCalls; + if (uvScale) { + for (int j = i + 1; j < total; ++j) { + if (drawCalls[j].verts != dc.verts) + break; + if (memcmp(&uvScale[j], &uvScale[i], sizeof(uvScale[0])) != 0) + break; - indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound); - indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound); - lastMatch = j; - j++; - } + indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound); + indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound); + lastMatch = j; + } + } else { + for (int j = i + 1; j < total; ++j) { + if (drawCalls[j].verts != dc.verts) + break; - // 2. Loop through the drawcalls, translating indices as we go. - for (j = i; j <= lastMatch; j++) { - switch (indexType) { - case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT: - indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound); - break; - case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT: - indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16 *)drawCalls[j].inds, indexLowerBound); - break; + indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound); + indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound); + lastMatch = j; } } - int vertexCount = indexUpperBound - indexLowerBound + 1; + // 2. Loop through the drawcalls, translating indices as we go. + switch (indexType) { + case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT: + for (int j = i; j <= lastMatch; j++) { + indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound); + } + break; + case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT: + for (int j = i; j <= lastMatch; j++) { + indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16 *)drawCalls[j].inds, indexLowerBound); + } + break; + } + + const int vertexCount = indexUpperBound - indexLowerBound + 1; // 3. Decode that range of vertex data. dec_->DecodeVerts(decoded + decodedVerts_ * (int)dec_->GetDecVtxFmt().stride, dc.verts, indexLowerBound, indexUpperBound);