From 812e32f7753d452f5c6776fa18e2b2a26b4ff3bb Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sun, 25 Oct 2020 17:23:42 -0300
Subject: Fix transform feedback errors caused by host pause/resume and
 multiple uses (#1634)

* Fix transform feedback errors caused by host pause/resume

* Fix TFB being used as something else issue with copies

* This is supposed to be StreamCopy
---
 Ryujinx.Graphics.OpenGL/Pipeline.cs | 87 +++++++++++++++++++++++++++++--------
 1 file changed, 69 insertions(+), 18 deletions(-)

(limited to 'Ryujinx.Graphics.OpenGL/Pipeline.cs')

diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 2650e9ee..6277fe16 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -5,7 +5,6 @@ using Ryujinx.Graphics.OpenGL.Image;
 using Ryujinx.Graphics.OpenGL.Queries;
 using Ryujinx.Graphics.Shader;
 using System;
-using System.Threading;
 
 namespace Ryujinx.Graphics.OpenGL
 {
@@ -49,6 +48,10 @@ namespace Ryujinx.Graphics.OpenGL
         private bool _scissor0Enable = false;
 
         private bool _tfEnabled;
+        private TransformFeedbackPrimitiveType _tfTopology;
+
+        private readonly BufferHandle[] _tfbs;
+        private readonly BufferRange[] _tfbTargets;
 
         private ColorF _blendConstant;
 
@@ -74,6 +77,9 @@ namespace Ryujinx.Graphics.OpenGL
             {
                 _cpRenderScale[index] = 1f;
             }
+
+            _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
+            _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
         }
 
         public void Barrier()
@@ -83,7 +89,7 @@ namespace Ryujinx.Graphics.OpenGL
 
         public void BeginTransformFeedback(PrimitiveTopology topology)
         {
-            GL.BeginTransformFeedback(topology.ConvertToTfType());
+            GL.BeginTransformFeedback(_tfTopology = topology.ConvertToTfType());
             _tfEnabled = true;
         }
 
@@ -175,7 +181,7 @@ namespace Ryujinx.Graphics.OpenGL
                 return;
             }
 
-            PrepareForDraw();
+            PreDraw();
 
             if (_primitiveType == PrimitiveType.Quads)
             {
@@ -190,7 +196,7 @@ namespace Ryujinx.Graphics.OpenGL
                 DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
             }
 
-            _framebuffer.SignalModified();
+            PostDraw();
         }
 
         private void DrawQuadsImpl(
@@ -293,7 +299,7 @@ namespace Ryujinx.Graphics.OpenGL
                 return;
             }
 
-            PrepareForDraw();
+            PreDraw();
 
             int indexElemSize = 1;
 
@@ -335,7 +341,7 @@ namespace Ryujinx.Graphics.OpenGL
                     firstInstance);
             }
 
-            _framebuffer.SignalModified();
+            PostDraw();
         }
 
         private void DrawQuadsIndexedImpl(
@@ -790,9 +796,9 @@ namespace Ryujinx.Graphics.OpenGL
 
             if (_tfEnabled)
             {
-                GL.PauseTransformFeedback();
+                GL.EndTransformFeedback();
                 _program.Bind();
-                GL.ResumeTransformFeedback();
+                GL.BeginTransformFeedback(_tfTopology);
             }
             else
             {
@@ -993,19 +999,39 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
-        public void SetTransformFeedbackBuffer(int index, BufferRange buffer)
+        public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
         {
-            const BufferRangeTarget target = BufferRangeTarget.TransformFeedbackBuffer;
-
             if (_tfEnabled)
             {
-                GL.PauseTransformFeedback();
-                GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
-                GL.ResumeTransformFeedback();
+                GL.EndTransformFeedback();
             }
-            else
+
+            int count = Math.Min(buffers.Length, Constants.MaxTransformFeedbackBuffers);
+
+            for (int i = 0; i < count; i++)
             {
-                GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
+                BufferRange buffer = buffers[i];
+                _tfbTargets[i] = buffer;
+
+                if (buffer.Handle == BufferHandle.Null)
+                {
+                    GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, 0);
+                    continue;
+                }
+
+                if (_tfbs[i] == BufferHandle.Null)
+                {
+                    _tfbs[i] = Buffer.Create();
+                }
+
+                Buffer.Resize(_tfbs[i], buffer.Size);
+                Buffer.Copy(buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size);
+                GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i].ToInt32());
+            }
+
+            if (_tfEnabled)
+            {
+                GL.BeginTransformFeedback(_tfTopology);
             }
         }
 
@@ -1104,7 +1130,7 @@ namespace Ryujinx.Graphics.OpenGL
                 ? BufferRangeTarget.ShaderStorageBuffer
                 : BufferRangeTarget.UniformBuffer;
 
-            if (buffer.Handle == null)
+            if (buffer.Handle == BufferHandle.Null)
             {
                 GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
                 return;
@@ -1237,7 +1263,7 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
-        private void PrepareForDraw()
+        private void PreDraw()
         {
             _vertexArray.Validate();
 
@@ -1247,6 +1273,22 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
+        private void PostDraw()
+        {
+            _framebuffer?.SignalModified();
+
+            if (_tfEnabled)
+            {
+                for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
+                {
+                    if (_tfbTargets[i].Handle != BufferHandle.Null)
+                    {
+                        Buffer.Copy(_tfbs[i], _tfbTargets[i].Handle, 0, _tfbTargets[i].Offset, _tfbTargets[i].Size);
+                    }
+                }
+            }
+        }
+
         private void RestoreComponentMask(int index)
         {
             GL.ColorMask(
@@ -1319,6 +1361,15 @@ namespace Ryujinx.Graphics.OpenGL
 
         public void Dispose()
         {
+            for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
+            {
+                if (_tfbs[i] != BufferHandle.Null)
+                {
+                    Buffer.Delete(_tfbs[i]);
+                    _tfbs[i] = BufferHandle.Null;
+                }
+            }
+
             _framebuffer?.Dispose();
             _vertexArray?.Dispose();
         }
-- 
cgit v1.2.3-70-g09d2