diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 98bc922aab..78f51b318d 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -1758,6 +1758,35 @@ static int Hook_ZZT3_select_hack() { return 0; } +// Bejeweled 2 only presents once mNextDrawTick has passed, and while the loading thread runs, it moves +// it 35-50ms on per present to hold the loading screen to 20fps. The PSP port presents every frame while +// loading, but still moves it on, so by the end of loading it's seconds ahead. +// Whether that's undone depends on a race: if mLoadingThreadCompleted is set during a present, the present +// ends by setting mNextDrawTick to now. If not, nothing is presented for those seconds while every frame +// still draws into the same display list, which overruns its 128KB into the game's globals and crashes. +// So, we do what the present would have, once loading has completed. +static int Hook_bejeweled2_draw_dirty_stuff() { + const u32 func = currentMIPS->pc; + const u32 app = currentMIPS->r[MIPS_REG_A0]; + // The hash masks immediates, so check the fields are where we expect. + if (Memory::Read_Instruction(func + 0x48).encoding != 0x90840411 || // lbu a0, 0x411(a0) - mLoadingThreadStarted + Memory::Read_Instruction(func + 0x58).encoding != 0x90840412 || // lbu a0, 0x412(a0) - mLoadingThreadCompleted + Memory::Read_Instruction(func + 0xC0).encoding != 0x8C8403C8 || // lw a0, 0x3C8(a0) - mLastDrawTick + Memory::Read_Instruction(func + 0xDC).encoding != 0x8C8403CC) { // lw a0, 0x3CC(a0) - mNextDrawTick + return 0; + } + if (!Memory::IsValidRange(app, 0x414) || Memory::ReadUnchecked_U8(app + 0x412) == 0) { + return 0; + } + // After loading, a present leaves mNextDrawTick at mLastDrawTick. + const u32 lastDrawTick = Memory::ReadUnchecked_U32(app + 0x3C8); + const u32 nextDrawTick = Memory::ReadUnchecked_U32(app + 0x3CC); + if ((s32)(nextDrawTick - lastDrawTick) > 1000) { + Memory::WriteUnchecked_U32(lastDrawTick, app + 0x3CC); + } + return 0; +} + #define JITFUNC(f) (&MIPSComp::MIPSFrontendInterface::f) // Can either replace with C functions or functions emitted in Asm/ArmAsm. @@ -1896,6 +1925,7 @@ static const ReplacementTableEntry entries[] = { { "resistance_draw_trail", &Hook_resistance_draw_trail, 0, REPFLAG_HOOKENTER, 0x198 }, { "resistance_update_trail", &Hook_resistance_update_trail, 0, REPFLAG_HOOKENTER, 0x438 }, { "resistance_muzzle_light", &Hook_resistance_muzzle_light, 0, REPFLAG_HOOKENTER, 0xF0 }, + { "bejeweled2_draw_dirty_stuff", &Hook_bejeweled2_draw_dirty_stuff, 0, REPFLAG_HOOKENTER, 0 }, {} }; diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index e910e31bf8..28324661c6 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -432,6 +432,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xc51519f5dab342d4, 224, "cosf", }, { 0xc52c14b9af8c3008, 76, "memcmp", }, { 0xc54eae62622f1e11, 164, "dl_write_bone_matrix_2", }, + { 0xc626403884cabcbf, 532, "bejeweled2_draw_dirty_stuff", }, // Bejeweled 2 { 0xc6b29de7d3245198, 656, "starocean_write_stencil" }, // Star Ocean 1 (US) { 0xc7b1113cfdfedab6, 104, "tonyhawkp8_upload_tutorial_frame", }, // Tony Hawk's Project 8 (US) { 0xc96e3a087ebf49a9, 100, "dl_write_light_color", },