Support swizzled framebuffer downloads.

Used in God Eater 2 when showing the load save screen.
This commit is contained in:
Unknown W. Brackets 2014-05-26 16:49:32 -07:00
parent 64f6012dba
commit b73c575418
3 changed files with 64 additions and 0 deletions

View File

@ -142,6 +142,42 @@ static int Replace_memcpy16() {
return 10 + bytes / 4; // approximation
}
static int Replace_memcpy_swizzled() {
u32 destPtr = PARAM(0);
u32 srcPtr = PARAM(1);
u32 pitch = PARAM(2);
u32 h = PARAM(4);
if (Memory::IsVRAMAddress(srcPtr)) {
// Cheat a bit to force a download of the framebuffer.
// VRAM + 0x00400000 is simply a VRAM mirror.
gpu->UpdateMemory(srcPtr ^ 0x00400000, srcPtr, pitch * h);
}
u8 *dstp = Memory::GetPointerUnchecked(destPtr);
const u8 *srcp = Memory::GetPointerUnchecked(srcPtr);
const u8 *ysrcp = srcp;
for (u32 y = 0; y < h; y += 8) {
const u8 *xsrcp = ysrcp;
for (u32 x = 0; x < pitch; x += 16) {
const u8 *src = xsrcp;
for (int n = 0; n < 8; ++n) {
memcpy(dstp, src, 16);
src += pitch;
dstp += 16;
}
xsrcp += 16;
}
ysrcp += 8 * pitch;
}
RETURN(0);
#ifndef MOBILE_DEVICE
CBreakPoints::ExecMemCheck(srcPtr, false, pitch * h, currentMIPS->pc);
CBreakPoints::ExecMemCheck(destPtr, true, pitch * h, currentMIPS->pc);
#endif
return 10 + (pitch * h) / 4; // approximation
}
static int Replace_memmove() {
u32 destPtr = PARAM(0);
u32 srcPtr = PARAM(1);
@ -420,6 +456,7 @@ static const ReplacementTableEntry entries[] = {
{ "ceilf", &Replace_ceilf, 0, 0},
{ "memcpy", &Replace_memcpy, 0, 0},
{ "memcpy16", &Replace_memcpy16, 0, 0},
{ "memcpy_swizzled", &Replace_memcpy_swizzled, 0, 0},
{ "memmove", &Replace_memmove, 0, 0},
{ "memset", &Replace_memset, 0, 0},
{ "strlen", &Replace_strlen, 0, 0},

View File

@ -220,6 +220,7 @@ static const HardHashTableEntry hardcodedHashes[] = {
{ 0x6301fa5149bd973a, 120, "wcscat", },
{ 0x658b07240a690dbd, 36, "strlen", },
{ 0x66122f0ab50b2ef9, 296, "dl_write_dither_matrix_5", },
{ 0x66f7f1beccbc104a, 256, "memcpy_swizzled", }, // God Eater 2
{ 0x679e647e34ecf7f1, 132, "roundf", },
{ 0x67afe74d9ec72f52, 4380, "_strtod_r", },
{ 0x68b22c2aa4b8b915, 400, "sqrt", },
@ -738,6 +739,7 @@ skip:
bool looking = false;
bool end = false;
bool isStraightLeaf = true;
bool decreasedSp = false;
u32 addr;
u32 addrNextSym = 0;
@ -761,6 +763,8 @@ skip:
furthestBranch = 0;
looking = false;
end = false;
isStraightLeaf = false;
decreasedSp = false;
continue;
}
@ -771,6 +775,7 @@ skip:
if (target > furthestBranch) {
furthestBranch = target;
}
// j X
} else if ((op & 0xFC000000) == 0x08000000) {
u32 sureTarget = GetJumpTarget(addr);
// Check for a tail call. Might not even have a jr ra.
@ -782,6 +787,18 @@ skip:
end = true;
}
} else if (sureTarget != INVALIDTARGET && sureTarget > addr && sureTarget > furthestBranch) {
static const u32 MAX_JUMP_FORWARD = 128;
// If it's a nearby forward jump, and not a stackless leaf, assume not a tail call.
if (sureTarget <= addr + MAX_JUMP_FORWARD && decreasedSp) {
// But let's check the delay slot.
MIPSOpcode op = Memory::Read_Instruction(addr + 4);
// addiu sp, sp, +X
if ((op & 0xFFFF8000) != 0x27BD0000) {
furthestBranch = sureTarget;
continue;
}
}
// A jump later. Probably tail, but let's check if it jumps back.
u32 knownEnd = furthestBranch == 0 ? addr : furthestBranch;
u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd);
@ -806,6 +823,14 @@ skip:
end = true;
}
}
// addiu sp, sp, -X
if ((op & 0xFFFF8000) == 0x27BD8000) {
decreasedSp = true;
}
// addiu sp, sp, +X
if ((op & 0xFFFF8000) == 0x27BD0000) {
decreasedSp = false;
}
if (looking) {
if (addr >= furthestBranch) {
@ -838,6 +863,7 @@ skip:
looking = false;
end = false;
isStraightLeaf = true;
decreasedSp = false;
currentFunction.start = addr+4;
}
}

View File

@ -140,6 +140,7 @@
6301fa5149bd973a:120 = wcscat
658b07240a690dbd:36 = strlen
66122f0ab50b2ef9:296 = dl_write_dither_matrix_5
66f7f1beccbc104a:256 = memcpy_swizzled
679e647e34ecf7f1:132 = roundf
67afe74d9ec72f52:4380 = _strtod_r
68b22c2aa4b8b915:400 = sqrt