diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 9d27d21047..c34b65d87a 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include #include #include @@ -67,7 +68,8 @@ public: bool run(PendingInterrupt& pend) override { if (ge_pending_cb.empty()) { - ERROR_LOG_REPORT(Log::sceGe, "Unable to run GE interrupt: no pending interrupt"); + // sceGeBreak(1) got there first. If interrupts were off, this one had already been raised. + DEBUG_LOG(Log::sceGe, "Ignoring GE interrupt, nothing pending anymore"); return false; } @@ -291,6 +293,15 @@ bool __GeTriggerSync(GPUSyncType type, int id, u64 atTicks) { return true; } +void __GeClearPendingInterrupts(bool interruptRunning) { + if (interruptRunning && !ge_pending_cb.empty()) { + ge_pending_cb.erase(std::next(ge_pending_cb.begin()), ge_pending_cb.end()); + } else { + ge_pending_cb.clear(); + } + CoreTiming::RemoveEvent(geInterruptEvent); +} + bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks) { GeInterruptData intrdata; intrdata.listid = listid; diff --git a/Core/HLE/sceGe.h b/Core/HLE/sceGe.h index 91fe03491a..74d0bec317 100644 --- a/Core/HLE/sceGe.h +++ b/Core/HLE/sceGe.h @@ -52,6 +52,9 @@ void __GeDoState(PointerWrap &p); void __GeShutdown(); bool __GeTriggerSync(GPUSyncType waitType, int id, u64 atTicks); bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks); +// Forgets the interrupts that haven't been delivered yet, as resetting the GE does. +// The one being handled right now, if any, is still needed when its handler returns. +void __GeClearPendingInterrupts(bool interruptRunning); void __GeWaitCurrentThread(GPUSyncType type, SceUID waitId, const char *reason); bool __GeTriggerWait(GPUSyncType type, SceUID waitId); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index b2e475067d..dc002b1ed1 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -579,7 +579,11 @@ u32 GPUCommon::Break(int mode) { { dls[i].state = PSP_GE_DL_STATE_NONE; dls[i].signal = PSP_GE_SIGNAL_NONE; + dls[i].pendingInterrupt = false; } + // This resets the GE, and an interrupt that hasn't been taken yet goes with it: no callback + // for a list that reached its FINISH just before. + __GeClearPendingInterrupts(interruptRunning); nextListID = 0; currentList = NULL; @@ -1487,7 +1491,7 @@ struct DisplayList_v2 { }; void GPUCommon::DoState(PointerWrap &p) { - auto s = p.Section("GPUCommon", 1, 6); + auto s = p.Section("GPUCommon", 1, 7); if (!s) return; @@ -1544,6 +1548,17 @@ void GPUCommon::DoState(PointerWrap &p) { dls[i].stackAddr = 0; } } + if (s < 7 && p.mode == PointerWrap::MODE_READ) { + // We didn't use to mark a PAUSE signal as delivered, which sceGeContinue now goes by. + // Back then, a list was only PAUSED with that signal set once it had reached its FINISH, + // and if the interrupt for that is still to come, it'll take care of this. + for (DisplayList &dl : dls) { + if (dl.state == PSP_GE_DL_STATE_PAUSED && dl.signal == PSP_GE_SIGNAL_HANDLER_PAUSE && !dl.pendingInterrupt) { + dl.signal = PSP_GE_SIGNAL_HANDLER_SUSPEND; + } + } + } + int currentID = 0; if (currentList != nullptr) { currentID = (int)(currentList - &dls[0]); diff --git a/pspautotests b/pspautotests index ba4d116e8c..c698aef2c0 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit ba4d116e8c15f23d3f98a7df12348547a1ead0a6 +Subproject commit c698aef2c021f71b3d17544e5f4078b0bf088fbf diff --git a/test.py b/test.py index cd17e34022..859d6e11da 100755 --- a/test.py +++ b/test.py @@ -204,6 +204,7 @@ tests_good = [ "gpu/ge/context", "gpu/ge/edram", "gpu/ge/enqueueparam", + "gpu/ge/intrsuspend", "gpu/ge/queue", "gpu/ge/queue2", "gpu/primitives/indices", @@ -478,6 +479,8 @@ tests_next = [ "gpu/reflection/reflection", "gpu/rendertarget/rendertarget", "gpu/signals/continue", + # Old SDK: a stall update from inside a SUSPEND handler is remembered, but not applied to the GE. See docs/sceGe.md. + "gpu/signals/handlercalls", "gpu/signals/jumps", "gpu/signals/simple", "gpu/simple/simple",