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)