mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Core: Handle CORE_REENTER_DISPATCH in Core_NextFrame
"Core_NextFrame called with wrong core state N/A" is CORE_REENTER_DISPATCH - the one CoreState missing from CoreStateToString, so it printed as N/A. Core_ReenterDispatcher() sets that state to bounce out of the dispatcher and back in, so pending jit cache invalidations get applied, and normally nothing can observe it: both run loops have coreState == CORE_RUNNING_CPU in their loop condition, so they bail at once and Core_RunLoopUntil resets it. CoreTiming::ProcessEvents() is the exception. It drains every due event in one loop without returning to the dispatcher in between, so if one callback invalidates the icache and EnterVBlank is behind it in the same batch, __DisplayFlip reaches Core_NextFrame while we're still in REENTER_DISPATCH. The likeliest source is hleCheat: for the JitInvalidationHack games it invalidates on every tick, at a 2ms interval against a 16.7ms vblank. Before, that meant Core_NextFrame refused, so the flip was skipped entirely - a dropped frame plus an alarming error log. Treat it like CORE_RUNNING_CPU instead: CORE_NEXTFRAME bounces out of the dispatcher just as well, and MIPSState::RunLoopUntil() calls ProcessPendingInvalidates() on every entry regardless of state, so nothing is lost. Also add the missing case to CoreStateToString.
This commit is contained in:
1 parent
2820fa9467
commit
097788aaea
1 file changed
+11
-1
+11
-1
@@ -275,6 +275,7 @@ const char *CoreStateToString(CoreState state) {
|
||||
switch (state) {
|
||||
case CORE_RUNNING_CPU: return "RUNNING_CPU";
|
||||
case CORE_NEXTFRAME: return "NEXTFRAME";
|
||||
case CORE_REENTER_DISPATCH: return "REENTER_DISPATCH";
|
||||
case CORE_STEPPING_CPU: return "STEPPING_CPU";
|
||||
case CORE_POWERDOWN: return "POWERDOWN";
|
||||
case CORE_RUNTIME_ERROR: return "RUNTIME_ERROR";
|
||||
@@ -727,7 +728,16 @@ bool Core_NextFrame() {
|
||||
|
||||
_dbg_assert_(coreState != CORE_STEPPING_GE && coreState != CORE_RUNNING_GE);
|
||||
|
||||
if (coreState == CORE_RUNNING_CPU) {
|
||||
if (coreState == CORE_RUNNING_CPU || coreState == CORE_REENTER_DISPATCH) {
|
||||
// REENTER_DISPATCH is just a request to bounce out of the dispatcher and come back in,
|
||||
// so that pending jit cache invalidations get applied. Switching to NEXTFRAME instead
|
||||
// bounces out just as well, and MIPSState::RunLoopUntil() calls ProcessPendingInvalidates()
|
||||
// on every entry regardless of state, so they're still applied when we resume.
|
||||
//
|
||||
// This happens when a CoreTiming event invalidates the icache (a cheat writing code, an
|
||||
// async io notify, ...) and the vblank event follows it in the same ProcessEvents() batch:
|
||||
// event callbacks run back to back without returning to the dispatcher in between, so the
|
||||
// state is still REENTER_DISPATCH when __DisplayFlip gets here.
|
||||
::coreState = CORE_NEXTFRAME;
|
||||
return true;
|
||||
} else if (coreState == CORE_STEPPING_CPU) {
|
||||
|
||||
Reference in new issue
Block a user