mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
GE: Complete lists dropped on error, flush before immediate draws
- A list dropped for a bad pc or a GE error stayed RUNNING: its ID was never freed and sceGeListSync on it never returned. Complete it like a finished one. - FlushImm switches to through mode and another vertex decoder, so flush the queued draws first even when the immediate flags match. - Clear leftover temporary GE breakpoints when setting or clearing the next break, so a step that never got there doesn't trip later. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
16ea2cbf88
commit
507bb0801b
2 files changed
+25
-2
No files matched your search
+24
-2
@@ -957,6 +957,7 @@ DLResult GPUCommon::ProcessDLQueue() {
|
|||||||
// Nothing to execute here, and leaving it at the head of the queue would block everything
|
// Nothing to execute here, and leaving it at the head of the queue would block everything
|
||||||
// behind it for good. Treat it like a list that ran into an error.
|
// behind it for good. Treat it like a list that ran into an error.
|
||||||
ERROR_LOG(Log::G3D, "Display list %d has a bad pc %08x (state %d), dropping it", listIndex, list.pc, (int)list.state);
|
ERROR_LOG(Log::G3D, "Display list %d has a bad pc %08x (state %d), dropping it", listIndex, list.pc, (int)list.state);
|
||||||
|
CompleteFailedList(list);
|
||||||
dlQueue.erase(std::remove(dlQueue.begin(), dlQueue.end(), listIndex), dlQueue.end());
|
dlQueue.erase(std::remove(dlQueue.begin(), dlQueue.end(), listIndex), dlQueue.end());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1045,7 +1046,8 @@ DLResult GPUCommon::ProcessDLQueue() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GPUSTATE_ERROR:
|
case GPUSTATE_ERROR:
|
||||||
// don't do anything - though dunno about error...
|
// The list can't continue. It's removed from the queue below.
|
||||||
|
CompleteFailedList(list);
|
||||||
break;
|
break;
|
||||||
case GPUSTATE_STALL:
|
case GPUSTATE_STALL:
|
||||||
// Resume work on this same display list later. The GE is still busy with what it has
|
// Resume work on this same display list later. The GE is still busy with what it has
|
||||||
@@ -1390,6 +1392,20 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A list dropped on an error still has to complete like a finished one, or its ID is never freed and
|
||||||
|
// sceGeListSync on it never returns.
|
||||||
|
void GPUCommon::CompleteFailedList(DisplayList &list) {
|
||||||
|
if (list.started && list.context.IsValid()) {
|
||||||
|
gstate.Restore(list.context);
|
||||||
|
ReapplyGfxState();
|
||||||
|
list.started = false;
|
||||||
|
}
|
||||||
|
list.state = PSP_GE_DL_STATE_COMPLETED;
|
||||||
|
list.waitUntilTicks = startingTicks + cyclesExecuted;
|
||||||
|
busyTicks = std::max(busyTicks, list.waitUntilTicks);
|
||||||
|
__GeTriggerSync(GPU_SYNC_LIST, list.id, list.waitUntilTicks);
|
||||||
|
}
|
||||||
|
|
||||||
void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
|
void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
|
||||||
// Just resetting, nothing to check bounds for.
|
// Just resetting, nothing to check bounds for.
|
||||||
const u32 count = op & 0xFFFF;
|
const u32 count = op & 0xFFFF;
|
||||||
@@ -1552,8 +1568,10 @@ void GPUCommon::FlushImm() {
|
|||||||
|
|
||||||
bool changed = texturing != prevTexturing || cullEnable != prevCullEnable || dither != prevDither;
|
bool changed = texturing != prevTexturing || cullEnable != prevCullEnable || dither != prevDither;
|
||||||
changed = changed || prevShading != shading || prevFog != fog;
|
changed = changed || prevShading != shading || prevFog != fog;
|
||||||
|
// Always flush, even if the flags match: DispatchSubmitImm switches to through mode and a different
|
||||||
|
// vertex decoder, which would otherwise apply to the draws already queued.
|
||||||
|
Flush();
|
||||||
if (changed) {
|
if (changed) {
|
||||||
Flush();
|
|
||||||
gstate.antiAliasEnable = (GE_CMD_ANTIALIASENABLE << 24) | (int)antialias;
|
gstate.antiAliasEnable = (GE_CMD_ANTIALIASENABLE << 24) | (int)antialias;
|
||||||
gstate.shademodel = (GE_CMD_SHADEMODE << 24) | (int)shading;
|
gstate.shademodel = (GE_CMD_SHADEMODE << 24) | (int)shading;
|
||||||
gstate.cullfaceEnable = (GE_CMD_CULLFACEENABLE << 24) | (int)cullEnable;
|
gstate.cullfaceEnable = (GE_CMD_CULLFACEENABLE << 24) | (int)cullEnable;
|
||||||
@@ -2290,12 +2308,16 @@ bool GPUCommon::NeedsSlowInterpreter() const {
|
|||||||
void GPUCommon::ClearBreakNext() {
|
void GPUCommon::ClearBreakNext() {
|
||||||
breakNext_ = GPUDebug::BreakNext::NONE;
|
breakNext_ = GPUDebug::BreakNext::NONE;
|
||||||
breakAtCount_ = -1;
|
breakAtCount_ = -1;
|
||||||
|
// A step that never reached its target leaves these behind, and they'd trip unexpectedly later.
|
||||||
|
breakpoints_.ClearTempBreakpoints();
|
||||||
GPUStepping::ResumeFromStepping();
|
GPUStepping::ResumeFromStepping();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) {
|
void GPUCommon::SetBreakNext(GPUDebug::BreakNext next) {
|
||||||
breakNext_ = next;
|
breakNext_ = next;
|
||||||
breakAtCount_ = -1;
|
breakAtCount_ = -1;
|
||||||
|
// Drop the ones from a previous step that didn't get there, before adding this one's.
|
||||||
|
breakpoints_.ClearTempBreakpoints();
|
||||||
switch (next) {
|
switch (next) {
|
||||||
case GPUDebug::BreakNext::TEX:
|
case GPUDebug::BreakNext::TEX:
|
||||||
breakpoints_.AddTextureChangeTempBreakpoint();
|
breakpoints_.AddTextureChangeTempBreakpoint();
|
||||||
|
|||||||
@@ -452,4 +452,5 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void DoExecuteCall(u32 target);
|
void DoExecuteCall(u32 target);
|
||||||
void PopDLQueue();
|
void PopDLQueue();
|
||||||
|
void CompleteFailedList(DisplayList &list);
|
||||||
};
|
};
|
||||||
Reference in new issue
Block a user