diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index fd59923dcc..a22cbab840 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -55,6 +55,11 @@ public: { GeInterruptData intrdata = ge_pending_cb.front(); DisplayList* dl = gpu->getList(intrdata.listid); + if (!dl->interruptsEnabled) + { + ERROR_LOG_REPORT(HLE, "Unable to run GE interrupt: list has interrupts disabled, should not happen"); + return false; + } if (dl == NULL) { @@ -120,6 +125,11 @@ public: ge_pending_cb.pop_front(); DisplayList* dl = gpu->getList(intrdata.listid); + if (!dl->interruptsEnabled) + { + ERROR_LOG_REPORT(HLE, "Unable to finish GE interrupt: list has interrupts disabled, should not happen"); + return; + } switch (dl->signal) { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 697f902b57..16541e302e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -187,13 +187,13 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) { // return 0x80000021; //} } - if (dls[i].state == PSP_GE_DL_STATE_NONE) + if (dls[i].state == PSP_GE_DL_STATE_NONE && !dls[i].pendingInterrupt) { // Prefer a list that isn't used id = i; break; } - if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && dls[i].waitTicks < currentTicks) + if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && !dls[i].pendingInterrupt && dls[i].waitTicks < currentTicks) { id = i; } @@ -806,8 +806,10 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { } // TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe? if (currentList->interruptsEnabled && trigger) { - if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) + if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + currentList->pendingInterrupt = true; UpdateState(GPUSTATE_INTERRUPT); + } } } break; @@ -815,8 +817,10 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { switch (currentList->signal) { case PSP_GE_SIGNAL_HANDLER_PAUSE: if (currentList->interruptsEnabled) { - if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) + if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + currentList->pendingInterrupt = true; UpdateState(GPUSTATE_INTERRUPT); + } } break; @@ -829,7 +833,9 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { currentList->subIntrToken = prev & 0xFFFF; currentList->state = PSP_GE_DL_STATE_COMPLETED; UpdateState(GPUSTATE_DONE); - if (!currentList->interruptsEnabled || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + if (currentList->interruptsEnabled && __GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + currentList->pendingInterrupt = true; + } else { currentList->waitTicks = startingTicks + cyclesExecuted; busyTicks = std::max(busyTicks, currentList->waitTicks); __GeTriggerSync(WAITTYPE_GELISTSYNC, currentList->id, currentList->waitTicks); @@ -883,6 +889,7 @@ void GPUCommon::InterruptEnd(int listid) { isbreak = false; DisplayList &dl = dls[listid]; + dl.pendingInterrupt = false; // TODO: Unless the signal handler could change it? if (dl.state == PSP_GE_DL_STATE_COMPLETED || dl.state == PSP_GE_DL_STATE_NONE) { dl.waitTicks = 0; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 0776279bfb..5089423b69 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -129,6 +129,7 @@ struct DisplayList bool interrupted; u64 waitTicks; bool interruptsEnabled; + bool pendingInterrupt; }; enum GPUInvalidationType {