From d6f8615d2a045daaf37e8657a93b8fc43871afdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 28 Sep 2026 14:52:50 -0600 Subject: [PATCH] SoftGPU: Fix block transfer and self-render overlap tracking - The block transfer overlap check passed the stride in pixels where bytes are expected, so it only covered part of the rectangle. - A selfrender/selfdepth flush in UpdateState dropped the current draw's pending writes and reads, so later transfers didn't wait for it. Co-Authored-By: Claude Opus 5.5 (1M context) --- GPU/Software/BinManager.cpp | 15 +++++++++++++-- GPU/Software/SoftGpu.cpp | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 6430fad5ed..cd2c553ab1 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -246,21 +246,32 @@ void BinManager::UpdateState() { if (newMaxTasks > MAX_POSSIBLE_TASKS) newMaxTasks = MAX_POSSIBLE_TASKS; // We don't want to overlap wrong, so flush any pending. + bool flushed = false; if (maxTasks_ != newMaxTasks) { maxTasks_ = newMaxTasks; Flush("selfrender"); + flushed = true; } - pendingOverlap_ = pendingOverlap_ || selfRender; // Lastly, we have to check if we're newly writing depth we were texturing before. // This happens in Call of Duty (depth clear after depth texture), for example. - if (!hadDepth && state.pixelID.depthWrite) { + if (!flushed && !hadDepth && state.pixelID.depthWrite) { for (size_t i = 0; i < states_.Size(); ++i) { if (HasTextureWrite(states_.Peek(i))) { Flush("selfdepth"); + flushed = true; + break; } } } + + if (flushed) { + // The flush forgot what this draw writes and reads, so record it again. + MarkPendingWrites(state); + MarkPendingReads(state); + ClearDirty(SoftDirty::BINNER_RANGE); + } + pendingOverlap_ = pendingOverlap_ || selfRender; ClearDirty(SoftDirty::BINNER_OVERLAP); } } diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index e84dc2a9d6..5cb910ae92 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -826,8 +826,8 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) { // Need to flush both source and target, so we overwrite properly. if (Memory::IsValidRange(src, srcSize) && Memory::IsValidRange(dst, dstSize)) { - drawEngine_->transformUnit.FlushIfOverlap(this, "blockxfer", false, src, srcStride, width * bpp, height); - drawEngine_->transformUnit.FlushIfOverlap(this, "blockxfer", true, dst, dstStride, width * bpp, height); + drawEngine_->transformUnit.FlushIfOverlap(this, "blockxfer", false, src, srcStride * bpp, width * bpp, height); + drawEngine_->transformUnit.FlushIfOverlap(this, "blockxfer", true, dst, dstStride * bpp, width * bpp, height); } else { drawEngine_->transformUnit.Flush(this, "blockxfer_wrap"); }