From 79aa764d03744a3d2ad08487303f24902a2970af Mon Sep 17 00:00:00 2001 From: kuba Date: Fri, 31 Jul 2026 11:08:56 +0200 Subject: [PATCH] Metal: skip waitUntilCompleted when the command buffer is already Completed (#709) Tiny write-back batches often finish before the wait; checking status avoids redundant ordered-queue round-trips. --- .../Gpu/Metal/MetalVideoPresenter.Compute.cs | 2 +- .../Gpu/Metal/MetalVideoPresenter.Draws.cs | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Compute.cs b/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Compute.cs index 97f1b3dd..04d44b74 100644 --- a/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Compute.cs +++ b/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Compute.cs @@ -253,7 +253,7 @@ internal static partial class MetalVideoPresenter if (writeBackBuffers.Count > 0) { var committed = FlushBatchedGuestCommands(); - MetalNative.SendVoid(committed, MetalNative.Selector("waitUntilCompleted")); + WaitForCommittedCommandBuffer(committed); WriteBuffersBackToGuest(writeBackBuffers); } diff --git a/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Draws.cs b/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Draws.cs index 5214e501..502d4bef 100644 --- a/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Draws.cs +++ b/src/SharpEmu.Libs/Gpu/Metal/MetalVideoPresenter.Draws.cs @@ -580,7 +580,7 @@ internal static partial class MetalVideoPresenter if (writeBackBuffers.Count > 0) { var committed = FlushBatchedGuestCommands(); - MetalNative.SendVoid(committed, MetalNative.Selector("waitUntilCompleted")); + WaitForCommittedCommandBuffer(committed); WriteBuffersBackToGuest(writeBackBuffers); } @@ -668,7 +668,7 @@ internal static partial class MetalVideoPresenter TagSnapshotResources(commandBuffer); if (writeBackBuffers.Count > 0) { - MetalNative.SendVoid(commandBuffer, MetalNative.Selector("waitUntilCompleted")); + WaitForCommittedCommandBuffer(commandBuffer); WriteBuffersBackToGuest(writeBackBuffers); } @@ -2082,6 +2082,30 @@ internal static partial class MetalVideoPresenter } } + + /// + /// Blocks until a committed command buffer finishes. Skips the ObjC wait + /// when status is already Completed (common for tiny label/writeback + /// batches), avoiding redundant waitUntilCompleted round-trips on the + /// ordered queue. + /// + private static void WaitForCommittedCommandBuffer(nint commandBuffer) + { + if (commandBuffer == 0) + { + return; + } + + // MTLCommandBufferStatusCompleted = 4. + const nint completed = 4; + if (MetalNative.Send(commandBuffer, MetalNative.Selector("status")) >= completed) + { + return; + } + + MetalNative.SendVoid(commandBuffer, MetalNative.Selector("waitUntilCompleted")); + } + private static void ReturnPooledGuestData(TranslatedGuestDraw draw) { foreach (var buffer in draw.GlobalMemoryBuffers)