From 9034cfbfd3fc09ffdb41d8270e367dc340c60179 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 20 Dec 2012 21:54:40 -0800 Subject: [PATCH] Defer HLE interrupts, vblank only when enabled. Based on tests, vblank doesn't queue up (makes sense) while interrupts are disabled. I'm not 100% sure about the GPU stuff but it seems to only come from HLE via sceGe, so this should fix those return values. --- Core/HLE/HLE.cpp | 11 +++++++++ Core/HLE/HLE.h | 2 ++ Core/HLE/sceDisplay.cpp | 2 +- Core/HLE/sceKernelAlarm.cpp | 4 +--- Core/HLE/sceKernelInterrupt.cpp | 36 +++++++++++++++++++++-------- Core/HLE/sceKernelInterrupt.h | 13 +++++++++-- GPU/GLES/DisplayListInterpreter.cpp | 6 +++-- GPU/Null/NullGpu.cpp | 6 +++-- 8 files changed, 60 insertions(+), 20 deletions(-) diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 69af4be0c0..9bfce5b5a7 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -26,6 +26,7 @@ #include "sceAudio.h" #include "sceKernelMemory.h" #include "sceKernelThread.h" +#include "sceKernelInterrupt.h" #include "../MIPS/MIPSCodeUtils.h" enum @@ -40,6 +41,8 @@ enum HLE_AFTER_ALL_CALLBACKS = 0x04, // Reschedule and process current thread's callbacks after the syscall. HLE_AFTER_RESCHED_CALLBACKS = 0x08, + // Run interrupts (and probably reschedule) after the syscall. + HLE_AFTER_RUN_INTERRUPTS = 0x10, }; static std::vector moduleDB; @@ -231,11 +234,19 @@ void hleReSchedule(bool callbacks, const char *reason) hleAfterSyscall |= HLE_AFTER_RESCHED_CALLBACKS; } +void hleRunInterrupts() +{ + hleAfterSyscall |= HLE_AFTER_RUN_INTERRUPTS; +} + inline void hleFinishSyscall() { if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0) __KernelForceCallbacks(); + if ((hleAfterSyscall & HLE_AFTER_RUN_INTERRUPTS) != 0) + __RunOnePendingInterrupt(); + // Rescheduling will also do HLE_AFTER_ALL_CALLBACKS. if ((hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) != 0) __KernelReSchedule(true, hleAfterSyscallReschedReason); diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 83633b134f..05ff70c612 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -81,6 +81,8 @@ void hleCheckAllCallbacks(); void hleReSchedule(const char *reason); // Reschedule and go into a callback processing state after the syscall finishes. void hleReSchedule(bool callbacks, const char *reason); +// Run interrupts after the syscall finishes. +void hleRunInterrupts(); void HLEInit(); void HLEShutdown(); diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 39c673b5c8..8b0fca887e 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -151,7 +151,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate) vblankWaitingThreads.clear(); // Trigger VBlank interrupt handlers. - __TriggerInterrupt(PSP_VBLANK_INTR); + __TriggerInterrupt(PSP_INTR_IMMEDIATE | PSP_INTR_ONLY_IF_ENABLED, PSP_VBLANK_INTR); CoreTiming::ScheduleEvent(msToCycles(vblankMs) - cyclesLate, leaveVblankEvent, vbCount+1); diff --git a/Core/HLE/sceKernelAlarm.cpp b/Core/HLE/sceKernelAlarm.cpp index 964c0f9746..ee6657e670 100644 --- a/Core/HLE/sceKernelAlarm.cpp +++ b/Core/HLE/sceKernelAlarm.cpp @@ -88,10 +88,8 @@ void __KernelTriggerAlarm(u64 userdata, int cyclesLate) u32 error; Alarm *alarm = kernelObjects.Get(uid, error); - - // TODO: Need to find out the return value. if (alarm) - __TriggerInterrupt(PSP_SYSTIMER0_INTR, uid); + __TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER0_INTR, uid); } void __KernelScheduleAlarm(Alarm *alarm, int ticks) diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 77c59fd96f..1c44b069d6 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -273,20 +273,36 @@ bool __RunOnePendingInterrupt() } } -void __TriggerInterrupt(PSPInterrupt intno, int subintr) +void __TriggerInterrupt(int type, PSPInterrupt intno, int subintr) { - intrHandlers[intno].queueUp(subintr); - DEBUG_LOG(HLE, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, pendingInterrupts.size()); - if (!inInterrupt) - __RunOnePendingInterrupt(); + if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0) + { + intrHandlers[intno].queueUp(subintr); + DEBUG_LOG(HLE, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, pendingInterrupts.size()); + if (!inInterrupt) + { + if ((type & PSP_INTR_HLE) != 0) + hleRunInterrupts(); + else + __RunOnePendingInterrupt(); + } + } } -void __TriggerInterruptWithArg(PSPInterrupt intno, int subintr, int arg) +void __TriggerInterruptWithArg(int type, PSPInterrupt intno, int subintr, int arg) { - intrHandlers[intno].queueUpWithArg(subintr, arg); - DEBUG_LOG(HLE, "Triggering subinterrupts for interrupt %i sub %i with arg %i (%i in queue)", intno, subintr, arg, pendingInterrupts.size()); - if (!inInterrupt) - __RunOnePendingInterrupt(); + if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0) + { + intrHandlers[intno].queueUpWithArg(subintr, arg); + DEBUG_LOG(HLE, "Triggering subinterrupts for interrupt %i sub %i with arg %i (%i in queue)", intno, subintr, arg, pendingInterrupts.size()); + if (!inInterrupt) + { + if ((type & PSP_INTR_HLE) != 0) + hleRunInterrupts(); + else + __RunOnePendingInterrupt(); + } + } } void __KernelReturnFromInterrupt() diff --git a/Core/HLE/sceKernelInterrupt.h b/Core/HLE/sceKernelInterrupt.h index adf0f4399b..1e553ed472 100644 --- a/Core/HLE/sceKernelInterrupt.h +++ b/Core/HLE/sceKernelInterrupt.h @@ -54,6 +54,15 @@ enum PSPGeSubInterrupts { PSP_GE_SUBINTR_SIGNAL = 15 }; +enum PSPInterruptTriggerType { + // Trigger immediately, for CoreTiming events. + PSP_INTR_IMMEDIATE = 0x0, + // Trigger after the HLE syscall finishes. + PSP_INTR_HLE = 0x1, + // Only trigger (as above) if interrupts are not suspended. + PSP_INTR_ONLY_IF_ENABLED = 0x2, +}; + class AllegrexInterruptHandler; struct PendingInterrupt { @@ -91,8 +100,8 @@ public: bool __IsInInterrupt(); void __InterruptsInit(); void __InterruptsShutdown(); -void __TriggerInterrupt(PSPInterrupt intno, int subInterrupts = -1); -void __TriggerInterruptWithArg(PSPInterrupt intno, int subintr, int arg); // For GE "callbacks" +void __TriggerInterrupt(int type, PSPInterrupt intno, int subInterrupts = -1); +void __TriggerInterruptWithArg(int type, PSPInterrupt intno, int subintr, int arg); // For GE "callbacks" bool __RunOnePendingInterrupt(); void __KernelReturnFromInterrupt(); diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 3f317513eb..7a4e5d952c 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -488,8 +488,9 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_FINISH: DEBUG_LOG(G3D,"DL CMD FINISH"); + // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0); break; case GE_CMD_END: @@ -525,8 +526,9 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) ERROR_LOG(G3D, "UNKNOWN Signal UNIMPLEMENTED %i ! signal/end: %04x %04x", behaviour, signal, enddata); break; } + // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal); } break; case GE_CMD_FINISH: diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index 7174166e66..f983d6b688 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -206,8 +206,9 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) int behaviour = (data >> 16) & 0xFF; int signal = data & 0xFFFF; + // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal); } break; @@ -237,8 +238,9 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_FINISH: DEBUG_LOG(G3D,"DL CMD FINISH"); + // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0); break; case GE_CMD_END: