hrydgard/ppsspp — pull request #4466 by unknownbrackets (2013-11-06 16:12:54+00:00)
Title: Cut down a bit on memory access in FastRunLoop

This seems to improve overall performance by 1.5% or so, at least in Senjou no Valkyria 3.

I also tried this larger change, which seemed to improve things a tiny bit more maybe, but could hurt/help other games differently and didn't test it on Android:

```diff
diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp
index 343bea3..fb270d0 100644
--- a/GPU/GLES/GLES_GPU.cpp
+++ b/GPU/GLES/GLES_GPU.cpp
@@ -41,8 +41,9 @@
enum {
FLAG_FLUSHBEFORE = 1,
FLAG_FLUSHBEFOREONCHANGE = 2,
-	FLAG_EXECUTE = 4, // needs to actually be executed. unused for now.
+	FLAG_EXECUTE = 4, // needs to actually be executed.
FLAG_EXECUTEONCHANGE = 8, // unused for now. not sure if checking for this will be more expensive than doing it.
+	FLAG_EXECUTECHECKPC = 16, // may read / write list pc or downcount.
};

struct CommandTableEntry {
@@ -295,15 +296,15 @@ static const CommandTableEntry commandTable[] = {

// From Common. No flushing but definitely need execute.
{GE_CMD_OFFSETADDR, FLAG_EXECUTE},
-	{GE_CMD_ORIGIN, FLAG_EXECUTE}, // Really?
+	{GE_CMD_ORIGIN, FLAG_EXECUTECHECKPC}, // Really?
{GE_CMD_PRIM, FLAG_EXECUTE},
-	{GE_CMD_JUMP, FLAG_EXECUTE},
-	{GE_CMD_CALL, FLAG_EXECUTE},
-	{GE_CMD_RET, FLAG_EXECUTE},
-	{GE_CMD_END, FLAG_EXECUTE}, // Flush?
+	{GE_CMD_JUMP, FLAG_EXECUTECHECKPC},
+	{GE_CMD_CALL, FLAG_EXECUTECHECKPC},
+	{GE_CMD_RET, FLAG_EXECUTECHECKPC},
+	{GE_CMD_END, FLAG_EXECUTECHECKPC}, // Flush?
{GE_CMD_VADDR, FLAG_EXECUTE},
{GE_CMD_IADDR, FLAG_EXECUTE},
-	{GE_CMD_BJUMP, FLAG_EXECUTE}, // EXECUTE
+	{GE_CMD_BJUMP, FLAG_EXECUTECHECKPC},
{GE_CMD_BOUNDINGBOX, FLAG_EXECUTE}, // + FLUSHBEFORE when we implement

// Changing the vertex type requires us to flush.
@@ -605,8 +606,11 @@ void GLES_GPU::CopyDisplayToOutputInternal() {
// Maybe should write this in ASM...
void GLES_GPU::FastRunLoop(DisplayList &list) {
const u8 *commandFlags = commandFlags_;
-	for (; downcount > 0; --downcount) {
-	const u32 op = Memory::ReadUnchecked_U32(list.pc);
+	const u32 *pc = (const u32 *)Memory::GetPointerUnchecked(list.pc);
+	const u32 *begin = pc;
+	const u32 *end = pc + downcount;
+	while (pc < end) {
+	const u32 op = *pc;
const u32 cmd = op >> 24;
const u8 cmdFlags = commandFlags[cmd];
const u32 diff = op ^ gstate.cmdmem[cmd];
@@ -615,11 +619,24 @@ void GLES_GPU::FastRunLoop(DisplayList &list) {
transformDraw_.Flush();
}
gstate.cmdmem[cmd] = op;
-	if (cmdFlags & FLAG_EXECUTE)
+	if (cmdFlags & FLAG_EXECUTE) {
ExecuteOpInternal(op, diff);
+	} else if (cmdFlags & FLAG_EXECUTECHECKPC) {
+	// Update the downcount and list pc before the call.
+	downcount -= (pc - begin);
+	list.pc += (pc - begin) * 4;
+	ExecuteOpInternal(op, diff);
+	// Now, update our variables so that we stop correctly.
+	pc = (const u32 *)Memory::GetPointerUnchecked(list.pc);
+	begin = pc;
+	end = pc + downcount;
+	}

-	list.pc += 4;
+	++pc;
}
+
+	// Okay, we hit end, update the list.pc before returning.
+	list.pc += (pc - begin) * 4;
}

void GLES_GPU::ProcessEvent(GPUEvent ev) {
```

-[Unknown]