From 3f01c0e91cd6ce41a39f828ef084ae064682c7f5 Mon Sep 17 00:00:00 2001 From: Astellou Date: Fri, 9 Oct 2026 18:21:35 +0200 Subject: [PATCH] [GPU] Record a frame's draws before its boundary returns to the guest With the command stream on its own thread, a frame boundary only posted its flush, so the guest resumed while up to 64 items of the frame were still queued for the render thread. The guest then rewrote per-draw memory (descriptor tables, rings) that those draws read when recorded, which showed as black frames and flicker. The boundary now waits for the render thread to run everything queued before it. --- .../Gpu/GpuCommands/CommandStreamQueue.cs | 2 +- .../Gpu/GpuCommands/ICommandStreamHost.cs | 4 ++++ .../VideoOut/VulkanVideoPresenter.CommandStream.cs | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/SharpEmu.Libs/Gpu/GpuCommands/CommandStreamQueue.cs b/src/SharpEmu.Libs/Gpu/GpuCommands/CommandStreamQueue.cs index 1db6ec3..2c6fd44 100644 --- a/src/SharpEmu.Libs/Gpu/GpuCommands/CommandStreamQueue.cs +++ b/src/SharpEmu.Libs/Gpu/GpuCommands/CommandStreamQueue.cs @@ -529,7 +529,7 @@ public sealed class CommandStreamQueue if (submission.Kind == CommandSubmissionKind.FrameBoundary) { SlicesRun++; - _host.Flush(); + _host.FlushFrame(); return true; } diff --git a/src/SharpEmu.Libs/Gpu/GpuCommands/ICommandStreamHost.cs b/src/SharpEmu.Libs/Gpu/GpuCommands/ICommandStreamHost.cs index 74eda4d..460ed63 100644 --- a/src/SharpEmu.Libs/Gpu/GpuCommands/ICommandStreamHost.cs +++ b/src/SharpEmu.Libs/Gpu/GpuCommands/ICommandStreamHost.cs @@ -100,6 +100,10 @@ public interface ICommandStreamHost void Flush(); + // A frame boundary: submits what the frame recorded. The submitter resumes once it returns, so a + // host that runs the stream ahead of its recording returns only after the frame is recorded. + void FlushFrame() => Flush(); + void FlushAndWait(); void SynchronizeGpu(); diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs index 874a27d..0d8b614 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs @@ -467,6 +467,19 @@ internal static unsafe partial class VulkanVideoPresenter FlushBatchedGuestCommands(); } + // The guest reuses the frame's memory (descriptor tables, rings) once the boundary returns, + // so the draws queued before it are recorded first. + public void FlushFrame() + { + if (OnCommandThread) + { + _commandThread!.Run(Flush); + return; + } + + Flush(); + } + public void FlushAndWait() { if (OnCommandThread)