From ae97ac95259edfa4ef67916bdbc2e0660380cc37 Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Sun, 11 Oct 2026 01:38:46 +0300 Subject: [PATCH] [GPU] Advance a binding epoch when helper passes bind their own state --- src/SharpEmu.Libs/Gpu/Buffers/BdaFaultProcessor.cs | 1 + .../Gpu/Images/ColorToMultisampleDepthBlit.cs | 1 + src/SharpEmu.Libs/Gpu/Images/GpuTiler.cs | 9 ++++++++- src/SharpEmu.Libs/Gpu/Vulkan/NativeBindingEpoch.cs | 13 +++++++++++++ .../VideoOut/VulkanVideoPresenter.Present.Hdr.cs | 1 + .../VideoOut/VulkanVideoPresenter.RenderLoop.cs | 1 + 6 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/SharpEmu.Libs/Gpu/Vulkan/NativeBindingEpoch.cs diff --git a/src/SharpEmu.Libs/Gpu/Buffers/BdaFaultProcessor.cs b/src/SharpEmu.Libs/Gpu/Buffers/BdaFaultProcessor.cs index febe4ce..5b9458b 100644 --- a/src/SharpEmu.Libs/Gpu/Buffers/BdaFaultProcessor.cs +++ b/src/SharpEmu.Libs/Gpu/Buffers/BdaFaultProcessor.cs @@ -216,6 +216,7 @@ public sealed unsafe class BdaFaultProcessor : IDisposable vk.CmdBindPipeline(command, PipelineBindPoint.Compute, _pipeline); var set = _sets[_currentArea]; vk.CmdBindDescriptorSets(command, PipelineBindPoint.Compute, _pipelineLayout, 0, 1, &set, 0, null); + NativeBindingEpoch.Advance(); var threads = _pageCount / 32; vk.CmdDispatch(command, (uint)((threads + 63) / 64), 1, 1); VulkanSynchronization.PipelineBarrier(vk, diff --git a/src/SharpEmu.Libs/Gpu/Images/ColorToMultisampleDepthBlit.cs b/src/SharpEmu.Libs/Gpu/Images/ColorToMultisampleDepthBlit.cs index 89c81e4..64f8fc2 100644 --- a/src/SharpEmu.Libs/Gpu/Images/ColorToMultisampleDepthBlit.cs +++ b/src/SharpEmu.Libs/Gpu/Images/ColorToMultisampleDepthBlit.cs @@ -304,6 +304,7 @@ public sealed unsafe class ColorToMultisampleDepthBlit : IDisposable vk.CmdBindDescriptorSets(command, PipelineBindPoint.Graphics, _pipelineLayout, 0, 1, &set, 0, null); vk.CmdBindPipeline(command, PipelineBindPoint.Graphics, cached.Pipeline); Vulkan.GraphicsDynamicStateEpoch.Advance(); + Vulkan.NativeBindingEpoch.Advance(); var viewport = new Viewport(0.0f, 0.0f, extent.Width, extent.Height, 0.0f, 1.0f); var scissor = new Rect2D(new Offset2D(0, 0), extent); vk.CmdSetViewport(command, 0, 1, &viewport); diff --git a/src/SharpEmu.Libs/Gpu/Images/GpuTiler.cs b/src/SharpEmu.Libs/Gpu/Images/GpuTiler.cs index 72a42cd..eca0c58 100644 --- a/src/SharpEmu.Libs/Gpu/Images/GpuTiler.cs +++ b/src/SharpEmu.Libs/Gpu/Images/GpuTiler.cs @@ -540,8 +540,11 @@ public sealed unsafe class GpuTiler : IDisposable return set; } - private void BindDescriptorSet(CommandBuffer command, DescriptorSet set) => + private void BindDescriptorSet(CommandBuffer command, DescriptorSet set) + { _device.Vk.CmdBindDescriptorSets(command, PipelineBindPoint.Compute, _pipelineLayout, 0, 1, &set, 0, null); + Vulkan.NativeBindingEpoch.Advance(); + } private void Record(bool tile, VkBuffer source, ulong sourceOffset, ulong sourceCapacity, VkBuffer target, ulong targetOffset, ulong targetCapacity, List dispatches, bool clearTarget) { @@ -587,6 +590,7 @@ public sealed unsafe class GpuTiler : IDisposable infos[2] = new DescriptorBufferInfo(dispatch.ArgumentsBuffer, dispatch.ArgumentsOffset, TileTransferArguments.Size); BindDescriptorSet(command, WriteDescriptorSet(infos, 2)); vk.CmdBindPipeline(command, PipelineBindPoint.Compute, GetPipeline(dispatch.PipelineSlot)); + Vulkan.NativeBindingEpoch.Advance(); vk.CmdDispatch(command, (dispatch.Arguments.Width + 7) / 8, (dispatch.Arguments.Height + 7) / 8, dispatch.Arguments.Depth); } @@ -697,6 +701,7 @@ public sealed unsafe class GpuTiler : IDisposable fixed (TileTransferArguments* pointer = &arguments) { _device.Vk.CmdPushConstants(command, _pipelineLayout, ShaderStageFlags.ComputeBit, 0, TileTransferArguments.Size, pointer); + Vulkan.NativeBindingEpoch.Advance(); } } @@ -743,6 +748,7 @@ public sealed unsafe class GpuTiler : IDisposable AccessFlags.ShaderReadBit | AccessFlags.ShaderWriteBit); VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 2, barriers, 0, null); vk.CmdBindPipeline(command, PipelineBindPoint.Compute, pipeline); + Vulkan.NativeBindingEpoch.Advance(); var descriptorAlignment = StorageAlignment; var groupLimit = _device.MaxComputeWorkGroupCount; @@ -830,6 +836,7 @@ public sealed unsafe class GpuTiler : IDisposable var command = new CommandBuffer(_scheduler.Current.Handle); VulkanSynchronization.PipelineBarrier(vk,command, PipelineStageFlags.AllCommandsBit | PipelineStageFlags.HostBit, PipelineStageFlags.ComputeShaderBit, 0, 0, null, 2, barriers, 0, null); vk.CmdBindPipeline(command, PipelineBindPoint.Compute, _swapBgra16); + Vulkan.NativeBindingEpoch.Advance(); BindDescriptorSet(command, WriteDescriptorSet(infos, -1)); PushArguments(command, new TileTransferArguments { SourceBase = inputBinding.Base, DestinationBase = outputBinding.Base, Width = pixels }); vk.CmdDispatch(command, (pixels + 63) / 64, 1, 1); diff --git a/src/SharpEmu.Libs/Gpu/Vulkan/NativeBindingEpoch.cs b/src/SharpEmu.Libs/Gpu/Vulkan/NativeBindingEpoch.cs new file mode 100644 index 0000000..91be64c --- /dev/null +++ b/src/SharpEmu.Libs/Gpu/Vulkan/NativeBindingEpoch.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2026 SharpEmu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +namespace SharpEmu.Libs.Gpu.Vulkan; + +internal static class NativeBindingEpoch +{ + private static long _value; + + public static long Value => Volatile.Read(ref _value); + + public static void Advance() => Interlocked.Increment(ref _value); +} diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Present.Hdr.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Present.Hdr.cs index ce28660..7c8d072 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Present.Hdr.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Present.Hdr.cs @@ -358,6 +358,7 @@ internal static unsafe partial class VulkanVideoPresenter PipelineBindPoint.Graphics, isHdr ? _hdrPqPipeline : _hdrPipeline); SharpEmu.Libs.Gpu.Vulkan.GraphicsDynamicStateEpoch.Advance(); + SharpEmu.Libs.Gpu.Vulkan.NativeBindingEpoch.Advance(); var descriptorSet = isHdr ? _hdrPqDescriptorSets[imageIndex] : _hdrDescriptorSets[imageIndex]; diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.RenderLoop.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.RenderLoop.cs index a238d2b..f6d0c6d 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.RenderLoop.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.RenderLoop.cs @@ -408,6 +408,7 @@ internal static unsafe partial class VulkanVideoPresenter PipelineBindPoint.Graphics, _barycentricPipeline); SharpEmu.Libs.Gpu.Vulkan.GraphicsDynamicStateEpoch.Advance(); + SharpEmu.Libs.Gpu.Vulkan.NativeBindingEpoch.Advance(); _vk.CmdDraw(_commandBuffer, 3, 1, 0, 0); _vk.CmdEndRenderPass(_commandBuffer); waitStage = PipelineStageFlags.ColorAttachmentOutputBit;