Merge pull request #1192 from unknownbrackets/dlist-parts

Improve displaylist signals
This commit is contained in:
Henrik Rydgård 2013-04-06 15:54:51 -07:00
commit 8271027fef
5 changed files with 119 additions and 27 deletions

View File

@ -54,13 +54,37 @@ public:
return false;
}
gpu->InterruptStart();
gpu->InterruptStart(intrdata.listid);
u32 cmd = Memory::ReadUnchecked_U32(intrdata.pc - 4) >> 24;
int subintr = dl->subIntrBase | (cmd == GE_CMD_FINISH ? PSP_GE_SUBINTR_FINISH : PSP_GE_SUBINTR_SIGNAL);
SubIntrHandler* handler = get(subintr);
int subintr = -1;
if (dl->subIntrBase >= 0)
{
switch (dl->signal)
{
case PSP_GE_SIGNAL_SYNC:
case PSP_GE_SIGNAL_JUMP:
case PSP_GE_SIGNAL_CALL:
case PSP_GE_SIGNAL_RET:
// Do nothing.
break;
if(handler != NULL)
case PSP_GE_SIGNAL_HANDLER_PAUSE:
if (cmd == GE_CMD_FINISH)
subintr = dl->subIntrBase | PSP_GE_SUBINTR_SIGNAL;
break;
default:
if (cmd == GE_CMD_SIGNAL)
subintr = dl->subIntrBase | PSP_GE_SUBINTR_SIGNAL;
else
subintr = dl->subIntrBase | PSP_GE_SUBINTR_FINISH;
break;
}
}
SubIntrHandler* handler = get(subintr);
if (handler != NULL)
{
DEBUG_LOG(CPU, "Entering interrupt handler %08x", handler->handlerAddress);
currentMIPS->pc = handler->handlerAddress;
@ -74,7 +98,7 @@ public:
}
ge_pending_cb.pop_front();
gpu->InterruptEnd();
gpu->InterruptEnd(intrdata.listid);
WARN_LOG(HLE, "Ignoring interrupt for display list %d, already been released.", intrdata.listid);
return false;
@ -109,7 +133,7 @@ public:
dl->signal = PSP_GE_SIGNAL_NONE;
gpu->InterruptEnd();
gpu->InterruptEnd(intrdata.listid);
}
};

View File

@ -353,6 +353,10 @@ u32 GPUCommon::Break(int mode)
bool GPUCommon::InterpretList(DisplayList &list)
{
// TODO: This has to be right... but it freezes right now?
//if (list.state == PSP_GE_DL_STATE_PAUSED)
// return false;
time_update();
double start = time_now_d();
currentList = &list;
@ -441,9 +445,6 @@ bool GPUCommon::ProcessDLQueue()
}
else
{
l.shouldWait = false;
__KernelTriggerWait(WAITTYPE_GELISTSYNC, *iter, 0, "GeListSync");
//At the end, we can remove it from the queue and continue
dlQueue.erase(iter);
//this invalidated the iterator, let's fix it
@ -547,6 +548,7 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
SignalBehavior behaviour = static_cast<SignalBehavior>((prev >> 16) & 0xFF);
int signal = prev & 0xFFFF;
int enddata = data & 0xFFFF;
bool trigger = true;
currentList->subIntrToken = signal;
switch (behaviour) {
@ -561,36 +563,94 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
ERROR_LOG(G3D, "Signal without wait. signal/end: %04x %04x", signal, enddata);
break;
case PSP_GE_SIGNAL_HANDLER_PAUSE:
ERROR_LOG(G3D, "Signal with Pause UNIMPLEMENTED! signal/end: %04x %04x", signal, enddata);
currentList->state = PSP_GE_DL_STATE_PAUSED;
currentList->signal = behaviour;
ERROR_LOG_REPORT(G3D, "Signal with Pause UNIMPLEMENTED! signal/end: %04x %04x", signal, enddata);
break;
case PSP_GE_SIGNAL_SYNC:
ERROR_LOG(G3D, "Signal with Sync UNIMPLEMENTED! signal/end: %04x %04x", signal, enddata);
currentList->signal = behaviour;
DEBUG_LOG(G3D, "Signal with Sync. signal/end: %04x %04x", signal, enddata);
break;
case PSP_GE_SIGNAL_JUMP:
ERROR_LOG_REPORT(G3D, "Signal with Jump UNIMPLEMENTED! signal/end: %04x %04x", signal, enddata);
{
trigger = false;
currentList->signal = behaviour;
// pc will be increased after we return, counteract that.
u32 target = ((signal << 16) | enddata) - 4;
if (!Memory::IsValidAddress(target)) {
ERROR_LOG_REPORT(G3D, "Signal with Jump: bad address. signal/end: %04x %04x", signal, enddata);
} else {
currentList->pc = target;
DEBUG_LOG(G3D, "Signal with Jump. signal/end: %04x %04x", signal, enddata);
}
}
break;
case PSP_GE_SIGNAL_CALL:
ERROR_LOG_REPORT(G3D, "Signal with Call UNIMPLEMENTED! signal/end: %04x %04x", signal, enddata);
{
trigger = false;
currentList->signal = behaviour;
// pc will be increased after we return, counteract that.
u32 target = ((signal << 16) | enddata) - 4;
if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) {
ERROR_LOG_REPORT(G3D, "Signal with Call: stack full. signal/end: %04x %04x", signal, enddata);
} else if (!Memory::IsValidAddress(target)) {
ERROR_LOG_REPORT(G3D, "Signal with Call: bad address. signal/end: %04x %04x", signal, enddata);
} else {
// TODO: This might save/restore other state...
currentList->stack[currentList->stackptr++] = currentList->pc;
currentList->pc = target;
DEBUG_LOG(G3D, "Signal with Call. signal/end: %04x %04x", signal, enddata);
}
}
break;
case PSP_GE_SIGNAL_RET:
ERROR_LOG_REPORT(G3D, "Signal with Return UNIMPLEMENTED! signal/end: %04x %04x", signal, enddata);
{
trigger = false;
currentList->signal = behaviour;
if (currentList->stackptr == 0) {
ERROR_LOG_REPORT(G3D, "Signal with Return: stack empty. signal/end: %04x %04x", signal, enddata);
} else {
// TODO: This might save/restore other state...
currentList->pc = currentList->stack[--currentList->stackptr];
DEBUG_LOG(G3D, "Signal with Return. signal/end: %04x %04x", signal, enddata);
}
}
break;
default:
ERROR_LOG_REPORT(G3D, "UNKNOWN Signal UNIMPLEMENTED %i ! signal/end: %04x %04x", behaviour, signal, enddata);
break;
}
if (interruptsEnabled_) {
// TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe?
if (interruptsEnabled_ && trigger) {
if (__GeTriggerInterrupt(currentList->id, currentList->pc))
gpuState = GPUSTATE_INTERRUPT;
}
}
break;
case GE_CMD_FINISH:
currentList->state = PSP_GE_DL_STATE_COMPLETED;
gpuState = GPUSTATE_DONE;
currentList->subIntrToken = prev & 0xFFFF;
if (interruptsEnabled_)
__GeTriggerInterrupt(currentList->id, currentList->pc);
switch (currentList->signal) {
case PSP_GE_SIGNAL_HANDLER_PAUSE:
if (interruptsEnabled_) {
if (__GeTriggerInterrupt(currentList->id, currentList->pc))
gpuState = GPUSTATE_INTERRUPT;
}
break;
case PSP_GE_SIGNAL_SYNC:
currentList->signal = PSP_GE_SIGNAL_NONE;
// TODO: Technically this should still cause an interrupt. Probably for memory sync.
break;
default:
currentList->subIntrToken = prev & 0xFFFF;
currentList->state = PSP_GE_DL_STATE_COMPLETED;
gpuState = GPUSTATE_DONE;
if (!interruptsEnabled_ || !__GeTriggerInterrupt(currentList->id, currentList->pc)) {
currentList->shouldWait = false;
__KernelTriggerWait(WAITTYPE_GELISTSYNC, currentList->id, 0, "GeListSync", true);
}
break;
}
break;
default:
DEBUG_LOG(G3D,"Ah, not finished: %06x", prev & 0xFFFFFF);
@ -626,13 +686,21 @@ void GPUCommon::DoState(PointerWrap &p) {
p.DoMarker("GPUCommon");
}
void GPUCommon::InterruptStart()
void GPUCommon::InterruptStart(int listid)
{
interruptRunning = true;
}
void GPUCommon::InterruptEnd()
void GPUCommon::InterruptEnd(int listid)
{
interruptRunning = false;
isbreak = false;
DisplayList &dl = dls[listid];
// TODO: Unless the signal handler could change it?
if (dl.state == PSP_GE_DL_STATE_COMPLETED) {
dl.shouldWait = false;
__KernelTriggerWait(WAITTYPE_GELISTSYNC, listid, 0, "GeListSync", true);
}
ProcessDLQueue();
}

View File

@ -8,8 +8,8 @@ public:
GPUCommon();
virtual ~GPUCommon() {}
virtual void InterruptStart();
virtual void InterruptEnd();
virtual void InterruptStart(int listid);
virtual void InterruptEnd(int listid);
virtual void EnableInterrupts(bool enable) {
interruptsEnabled_ = enable;
}

View File

@ -145,8 +145,8 @@ public:
virtual u32 Continue() = 0;
virtual u32 Break(int mode) = 0;
virtual void InterruptStart() = 0;
virtual void InterruptEnd() = 0;
virtual void InterruptStart(int listid) = 0;
virtual void InterruptEnd(int listid) = 0;
virtual void PreExecuteOp(u32 op, u32 diff) = 0;
virtual void ExecuteOp(u32 op, u32 diff) = 0;

2
native

@ -1 +1 @@
Subproject commit 7ebbe209043808982b227a4971f3d26a1d5cd419
Subproject commit 8e06b06d7efb3299d8c6139651d99616273d6aa7