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.
This commit is contained in:
Unknown W. Brackets 2012-12-20 21:54:40 -08:00
parent 99b24720b8
commit 9034cfbfd3
8 changed files with 60 additions and 20 deletions

View File

@ -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<HLEModule> 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);

View File

@ -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();

View File

@ -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);

View File

@ -88,10 +88,8 @@ void __KernelTriggerAlarm(u64 userdata, int cyclesLate)
u32 error;
Alarm *alarm = kernelObjects.Get<Alarm>(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)

View File

@ -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()

View File

@ -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();

View File

@ -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:

View File

@ -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: