diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CachedImages.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CachedImages.cs index 4d1a7ad..18d37c3 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CachedImages.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CachedImages.cs @@ -1048,6 +1048,8 @@ internal static unsafe partial class VulkanVideoPresenter continue; } + _commandBuffer = BeginBatchedGuestCommands(); + var initialized = texture.HostMoviePlane == 0 ? _hostMovieImageInitialized : _hostMovieChromaImageInitialized; var toTransfer = new ImageMemoryBarrier2 { diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs index 0d8b614..77b714d 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.CommandStream.cs @@ -541,6 +541,12 @@ internal static unsafe partial class VulkanVideoPresenter } EndRendering(); + if (BatchBarriers) + { + RequestGuestMemoryBarrier(GlobalMemoryBarrier); + return; + } + RecordGlobalBarrier(BeginBatchedGuestCommands()); } diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs index 0473fb0..b888a05 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs @@ -842,7 +842,7 @@ internal static unsafe partial class VulkanVideoPresenter using var profileScope = RenderPhaseProfile.MeasureDetail(RenderPhaseProfile.Phase.DescriptorCommit); var preparation = RequirePreparation(); var entry = RequirePipelineEntry(in pipeline); - var command = BeginBatchedGuestCommands(); + var command = BeginBatchedGuestStateCommands(); _commandBuffer = command; var writeCount = 0; var bufferCount = 0; diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.GuestSubmissions.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.GuestSubmissions.cs index 43d2010..b838735 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.GuestSubmissions.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.GuestSubmissions.cs @@ -47,13 +47,32 @@ internal static unsafe partial class VulkanVideoPresenter private CommandBuffer BeginBatchedGuestCommands() { var commandBuffer = CurrentRecordingBuffer(); + OpenGuestBatch(); + return commandBuffer; + } + + private CommandBuffer BeginBatchedGuestStateCommands() + { + var recording = CurrentRecording(); + OpenGuestBatch(); + return new CommandBuffer(recording.StateHandle); + } + + private void RequestGuestMemoryBarrier(in MemoryBarrierRequest request) + { + var recording = CurrentRecording(); + OpenGuestBatch(); + _scheduler.MemoryBarrierRecorder ??= RecordRequestedMemoryBarrier; + recording.RequestMemoryBarrier(request); + } + + private void OpenGuestBatch() + { if (!_batchOpen) { _batchOpen = true; _batchDrawCount = 0; } - - return commandBuffer; } // Submits the current recording buffer with everything the batch lists own. diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs index c1faff6..3f9fb8e 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs @@ -856,12 +856,17 @@ internal static unsafe partial class VulkanVideoPresenter } EndRendering(); - var command = BeginBatchedGuestCommands(); - _commandBuffer = command; - if (DeferGlobalBarriers) + if (DeferGlobalBarriers && BatchBarriers) { // A guest cache flush inside this scope may be deferred to its end; this keeps // everything recorded before the scope ordered before its draws either way. + RequestGuestMemoryBarrier(GlobalMemoryBarrier); + } + + var command = BeginBatchedGuestCommands(); + _commandBuffer = command; + if (DeferGlobalBarriers && !BatchBarriers) + { RecordGlobalBarrier(command); } @@ -986,7 +991,7 @@ internal static unsafe partial class VulkanVideoPresenter public void BindPipeline(PipelineBindPoint bindPoint, in PipelineHandle pipeline) { var entry = RequirePipelineEntry(in pipeline); - var command = BeginBatchedGuestCommands(); + var command = BeginBatchedGuestStateCommands(); if (bindPoint == PipelineBindPoint.Graphics) { _boundGraphicsPipeline = entry; @@ -1149,9 +1154,24 @@ internal static unsafe partial class VulkanVideoPresenter return true; } + private static readonly bool BatchBarriers = + Environment.GetEnvironmentVariable("SHARPEMU_BATCH_BARRIERS") != "0"; + + private static readonly MemoryBarrierRequest GlobalMemoryBarrier = new( + PipelineStageFlags.AllCommandsBit, + PipelineStageFlags.AllCommandsBit, + AccessFlags.MemoryWriteBit, + AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit); + private void RecordMemoryBarrier(PipelineStageFlags sourceStages, PipelineStageFlags destinationStages, AccessFlags sourceAccess, AccessFlags destinationAccess) { EndRendering(); + if (BatchBarriers) + { + RequestGuestMemoryBarrier(new MemoryBarrierRequest(sourceStages, destinationStages, sourceAccess, destinationAccess)); + return; + } + var command = BeginBatchedGuestCommands(); var barrier = new MemoryBarrier2 {