From f09bba82b9366e5912b639a610ae89cbb1cf352c Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 29 Aug 2023 21:10:34 -0300
Subject: Geometry shader emulation for macOS (#5551)

* Implement vertex and geometry shader conversion to compute

* Call InitializeReservedCounts for compute too

* PR feedback

* Set clip distance mask for geometry and tessellation shaders too

* Transform feedback emulation only for vertex
---
 .../Memory/SupportBufferUpdater.cs                 | 85 +++++++---------------
 1 file changed, 25 insertions(+), 60 deletions(-)

(limited to 'src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs')

diff --git a/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs b/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
index c1e91c54..fb141db4 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
@@ -9,56 +9,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
     /// <summary>
     /// Support buffer data updater.
     /// </summary>
-    class SupportBufferUpdater : IDisposable
+    class SupportBufferUpdater : BufferUpdater
     {
         private SupportBuffer _data;
-        private BufferHandle _handle;
-
-        private readonly IRenderer _renderer;
-        private int _startOffset = -1;
-        private int _endOffset = -1;
 
         /// <summary>
         /// Creates a new instance of the support buffer updater.
         /// </summary>
         /// <param name="renderer">Renderer that the support buffer will be used with</param>
-        public SupportBufferUpdater(IRenderer renderer)
+        public SupportBufferUpdater(IRenderer renderer) : base(renderer)
         {
-            _renderer = renderer;
-
             var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
             _data.RenderScale.AsSpan().Fill(defaultScale);
             DirtyRenderScale(0, SupportBuffer.RenderScaleMaxCount);
         }
 
-        /// <summary>
-        /// Mark a region of the support buffer as modified and needing to be sent to the GPU.
-        /// </summary>
-        /// <param name="startOffset">Start offset of the region in bytes</param>
-        /// <param name="byteSize">Size of the region in bytes</param>
-        private void MarkDirty(int startOffset, int byteSize)
-        {
-            int endOffset = startOffset + byteSize;
-
-            if (_startOffset == -1)
-            {
-                _startOffset = startOffset;
-                _endOffset = endOffset;
-            }
-            else
-            {
-                if (startOffset < _startOffset)
-                {
-                    _startOffset = startOffset;
-                }
-
-                if (endOffset > _endOffset)
-                {
-                    _endOffset = endOffset;
-                }
-            }
-        }
-
         /// <summary>
         /// Marks the fragment render scale count as being modified.
         /// </summary>
@@ -220,40 +185,40 @@ namespace Ryujinx.Graphics.Gpu.Memory
         }
 
         /// <summary>
-        /// Submits all pending buffer updates to the GPU.
+        /// Sets offset for the misaligned portion of a transform feedback buffer, and the buffer size, for transform feedback emulation.
         /// </summary>
-        public void Commit()
+        /// <param name="bufferIndex">Index of the transform feedback buffer</param>
+        /// <param name="offset">Misaligned offset of the buffer</param>
+        public void SetTfeOffset(int bufferIndex, int offset)
         {
-            if (_startOffset != -1)
-            {
-                if (_handle == BufferHandle.Null)
-                {
-                    _handle = _renderer.CreateBuffer(SupportBuffer.RequiredSize, BufferAccess.Stream);
-                    _renderer.Pipeline.ClearBuffer(_handle, 0, SupportBuffer.RequiredSize, 0);
+            ref int currentOffset = ref GetElementRef(ref _data.TfeOffset, bufferIndex);
 
-                    var range = new BufferRange(_handle, 0, SupportBuffer.RequiredSize);
-                    _renderer.Pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, range) });
-                }
-
-                ReadOnlySpan<byte> data = MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref _data, 1));
-
-                _renderer.SetBufferData(_handle, _startOffset, data[_startOffset.._endOffset]);
-
-                _startOffset = -1;
-                _endOffset = -1;
+            if (currentOffset != offset)
+            {
+                currentOffset = offset;
+                MarkDirty(SupportBuffer.TfeOffsetOffset + bufferIndex * sizeof(int), sizeof(int));
             }
         }
 
         /// <summary>
-        /// Destroys the support buffer.
+        /// Sets the vertex count used for transform feedback emulation with instanced draws.
         /// </summary>
-        public void Dispose()
+        /// <param name="vertexCount">Vertex count of the instanced draw</param>
+        public void SetTfeVertexCount(int vertexCount)
         {
-            if (_handle != BufferHandle.Null)
+            if (_data.TfeVertexCount.X != vertexCount)
             {
-                _renderer.DeleteBuffer(_handle);
-                _handle = BufferHandle.Null;
+                _data.TfeVertexCount.X = vertexCount;
+                MarkDirty(SupportBuffer.TfeVertexCountOffset, sizeof(int));
             }
         }
+
+        /// <summary>
+        /// Submits all pending buffer updates to the GPU.
+        /// </summary>
+        public void Commit()
+        {
+            Commit(MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref _data, 1)), SupportBuffer.Binding);
+        }
     }
 }
-- 
cgit v1.2.3-70-g09d2