From 31ed061beae779b0a750e1344c76a75af8275f91 Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Sat, 17 Feb 2024 03:21:37 +0000
Subject: Vulkan: Improve texture barrier usage, timing and batching (#6240)

* WIP barrier batch

* Add store op to image usage barrier

* Dispose the barrier batch

* Fix encoding?

* Handle read and write on the load op barrier.

Load op consumes read accesses but does not add one, as the only other operation that can read is another load.

* Simplify null check

* Insert barriers on program change in case stale bindings are reintroduced

* Not sure how I messed this one up

* Improve location of bindings barrier update

This is also important for emergency deferred clear

* Update src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs

Co-authored-by: Mary Guillemard <thog@protonmail.com>

---------

Co-authored-by: Mary Guillemard <thog@protonmail.com>
---
 src/Ryujinx.Graphics.Vulkan/TextureStorage.cs | 120 +++++++++-----------------
 1 file changed, 43 insertions(+), 77 deletions(-)

(limited to 'src/Ryujinx.Graphics.Vulkan/TextureStorage.cs')

diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs
index bba65921..230dbd4e 100644
--- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs
+++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs
@@ -433,99 +433,65 @@ namespace Ryujinx.Graphics.Vulkan
             return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint;
         }
 
-        public void SetModification(AccessFlags accessFlags, PipelineStageFlags stage)
+        public void QueueLoadOpBarrier(CommandBufferScoped cbs, bool depthStencil)
         {
-            _lastModificationAccess = accessFlags;
-            _lastModificationStage = stage;
-        }
+            PipelineStageFlags srcStageFlags = _lastReadStage | _lastModificationStage;
+            PipelineStageFlags dstStageFlags = depthStencil ?
+                PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit :
+                PipelineStageFlags.ColorAttachmentOutputBit;
 
-        public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags, bool insideRenderPass)
-        {
-            var lastReadStage = _lastReadStage;
+            AccessFlags srcAccessFlags = _lastModificationAccess | _lastReadAccess;
+            AccessFlags dstAccessFlags = depthStencil ?
+                AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.DepthStencilAttachmentReadBit :
+                AccessFlags.ColorAttachmentWriteBit | AccessFlags.ColorAttachmentReadBit;
 
-            if (insideRenderPass)
+            if (srcAccessFlags != AccessFlags.None)
             {
-                // We can't have barrier from compute inside a render pass,
-                // as it is invalid to specify compute in the subpass dependency stage mask.
-
-                lastReadStage &= ~PipelineStageFlags.ComputeShaderBit;
-            }
+                ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
+                ImageMemoryBarrier barrier = TextureView.GetImageBarrier(
+                    _imageAuto.Get(cbs).Value,
+                    srcAccessFlags,
+                    dstAccessFlags,
+                    aspectFlags,
+                    0,
+                    0,
+                    _info.GetLayers(),
+                    _info.Levels);
 
-            if (lastReadStage != PipelineStageFlags.None)
-            {
-                // This would result in a validation error, but is
-                // required on MoltenVK as the generic barrier results in
-                // severe texture flickering in some scenarios.
-                if (_gd.IsMoltenVk)
-                {
-                    ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
-                    TextureView.InsertImageBarrier(
-                        _gd.Api,
-                        cbs.CommandBuffer,
-                        _imageAuto.Get(cbs).Value,
-                        _lastReadAccess,
-                        dstAccessFlags,
-                        _lastReadStage,
-                        dstStageFlags,
-                        aspectFlags,
-                        0,
-                        0,
-                        _info.GetLayers(),
-                        _info.Levels);
-                }
-                else
-                {
-                    TextureView.InsertMemoryBarrier(
-                        _gd.Api,
-                        cbs.CommandBuffer,
-                        _lastReadAccess,
-                        dstAccessFlags,
-                        lastReadStage,
-                        dstStageFlags);
-                }
+                _gd.Barriers.QueueBarrier(barrier, srcStageFlags, dstStageFlags);
 
-                _lastReadAccess = AccessFlags.None;
                 _lastReadStage = PipelineStageFlags.None;
+                _lastReadAccess = AccessFlags.None;
             }
+
+            _lastModificationStage = depthStencil ?
+                PipelineStageFlags.LateFragmentTestsBit :
+                PipelineStageFlags.ColorAttachmentOutputBit;
+
+            _lastModificationAccess = depthStencil ?
+                AccessFlags.DepthStencilAttachmentWriteBit :
+                AccessFlags.ColorAttachmentWriteBit;
         }
 
-        public void InsertWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
+        public void QueueWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
         {
             _lastReadAccess |= dstAccessFlags;
             _lastReadStage |= dstStageFlags;
 
             if (_lastModificationAccess != AccessFlags.None)
             {
-                // This would result in a validation error, but is
-                // required on MoltenVK as the generic barrier results in
-                // severe texture flickering in some scenarios.
-                if (_gd.IsMoltenVk)
-                {
-                    ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
-                    TextureView.InsertImageBarrier(
-                        _gd.Api,
-                        cbs.CommandBuffer,
-                        _imageAuto.Get(cbs).Value,
-                        _lastModificationAccess,
-                        dstAccessFlags,
-                        _lastModificationStage,
-                        dstStageFlags,
-                        aspectFlags,
-                        0,
-                        0,
-                        _info.GetLayers(),
-                        _info.Levels);
-                }
-                else
-                {
-                    TextureView.InsertMemoryBarrier(
-                        _gd.Api,
-                        cbs.CommandBuffer,
-                        _lastModificationAccess,
-                        dstAccessFlags,
-                        _lastModificationStage,
-                        dstStageFlags);
-                }
+                ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
+                ImageMemoryBarrier barrier = TextureView.GetImageBarrier(
+                    _imageAuto.Get(cbs).Value,
+                    _lastModificationAccess,
+                    dstAccessFlags,
+                    aspectFlags,
+                    0,
+                    0,
+                    _info.GetLayers(),
+                    _info.Levels);
+
+                _gd.Barriers.QueueBarrier(barrier, _lastModificationStage, dstStageFlags);
 
                 _lastModificationAccess = AccessFlags.None;
             }
-- 
cgit v1.2.3-70-g09d2