From a37e1f36609f6701afd0da6dfd3268ca7e15bf16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 16 Oct 2026 11:12:27 +0200 Subject: [PATCH] GPU: Finish the depth raster when a list ends, before the CPU runs again Syphon Filter reads its depth buffer back on the CPU for the light flares as soon as a list has ended, without a DrawSync, and saw it before the worker had drawn the walls, so flares behind them flickered. Now returning to the CPU after an END waits for the batches already submitted. Returning at a stall doesn't wait, as Wipeout does that about 300 times a frame. Wipeout on a Galaxy S8: 11% less wall time than before the worker (16% without the wait). Co-Authored-By: Claude Opus 5.5 (1M context) --- GPU/Common/DepthRaster.cpp | 4 ++++ GPU/Common/DepthRaster.h | 2 ++ GPU/Common/DrawEngineCommon.cpp | 6 ++++++ GPU/Common/DrawEngineCommon.h | 2 ++ GPU/GPUCommon.cpp | 13 +++++++++++++ GPU/GPUCommon.h | 2 ++ 6 files changed, 29 insertions(+) diff --git a/GPU/Common/DepthRaster.cpp b/GPU/Common/DepthRaster.cpp index b3f2a56d20..87255f16a3 100644 --- a/GPU/Common/DepthRaster.cpp +++ b/GPU/Common/DepthRaster.cpp @@ -752,6 +752,10 @@ void DepthRasterWorker::Submit() { void DepthRasterWorker::Wait() { Submit(); + WaitForSubmitted(); +} + +void DepthRasterWorker::WaitForSubmitted() { if (!busy_) { return; } diff --git a/GPU/Common/DepthRaster.h b/GPU/Common/DepthRaster.h index 941da558db..d2baa4f1e0 100644 --- a/GPU/Common/DepthRaster.h +++ b/GPU/Common/DepthRaster.h @@ -93,6 +93,8 @@ public: void Submit(); // Submits the current batch and waits until all are rasterized. void Wait(); + // Waits until the batches already submitted are rasterized. + void WaitForSubmitted(); // Waits only if a batch being rasterized may write to [addr, addr + size). void WaitIfWriting(u32 addr, u32 size); diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 1d23403867..828b353ab1 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -1365,6 +1365,12 @@ void DrawEngineCommon::FlushQueuedDepth() { depthWorker_->TakeTimes(&gpuStats.perFrame.msCullDepth, &gpuStats.perFrame.msRasterizeDepth); } +void DrawEngineCommon::WaitForSubmittedDepth() { + if (depthWorker_) { + depthWorker_->WaitForSubmitted(); + } +} + void DrawEngineCommon::WaitForDepthWrites(u32 addr, u32 size) { if (depthWorker_) { depthWorker_->WaitIfWriting(addr, size); diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 9d7947e6de..5d1f98472b 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -164,6 +164,8 @@ public: void FlushQueuedDepth(); // Starts rasterizing the queued depth draws, without waiting. void SubmitQueuedDepth(); + // Waits for the depth draws already submitted, leaving the queued ones queued. + void WaitForSubmittedDepth(); // Waits if depth rasterization in progress may write to these bytes. void WaitForDepthWrites(u32 addr, u32 size); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 2072085c53..aaca88a931 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -908,6 +908,18 @@ inline void GPUCommon::UpdateState(GPURunState state) { // This is now called when coreState == CORE_RUNNING_GE, in addition to from the various sceGe commands. DLResult GPUCommon::ProcessDLQueue() { + const DLResult result = RunDLQueue(); + // Games read the depth buffer back on the CPU once a list has ended, without waiting for the GE + // (Syphon Filter's light flares). So the depth rasterizer has to be done by then. Not at a stall, + // though, which some games hit hundreds of times a frame. + if (listEndedSinceDepthWait_) { + listEndedSinceDepthWait_ = false; + drawEngineCommon_->WaitForSubmittedDepth(); + } + return result; +} + +DLResult GPUCommon::RunDLQueue() { if (!resumingFromDebugBreak_) { startingTicks = CoreTiming::GetTicks(currentMIPS); cyclesExecuted = 0; @@ -1213,6 +1225,7 @@ void GPUCommon::Execute_Ret(u32 op, u32 diff) { void GPUCommon::Execute_End(u32 op, u32 diff) { if (flushOnParams_) { drawEngineCommon_->SubmitQueuedDepth(); + listEndedSinceDepthWait_ = true; Flush(); } diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 04a57ba4e2..e430196495 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -316,6 +316,7 @@ public: void NotifyFlush(); protected: + DLResult RunDLQueue(); // While debugging is active, these may block. void NotifyDisplay(u32 framebuf, u32 stride, int format); @@ -377,6 +378,7 @@ protected: TextureCacheCommon *textureCache_ = nullptr; bool flushOnParams_ = true; + bool listEndedSinceDepthWait_ = false; GraphicsContext *gfxCtx_; Draw::DrawContext *draw_ = nullptr;