From 788ca6a411762035a6a7a88100c4b582b47ee82d Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Wed, 15 Jul 2020 00:01:10 -0300
Subject: Initial transform feedback support (#1370)

* Initial transform feedback support

* Some nits and fixes

* Update ReportCounterType and Write method

* Can't change shader or TFB bindings while TFB is active

* Fix geometry shader input names with new naming
---
 Ryujinx.Graphics.Gpu/Engine/Methods.cs | 44 +++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

(limited to 'Ryujinx.Graphics.Gpu/Engine/Methods.cs')

diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index d5b11c2c..093f9048 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -40,6 +40,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private bool _forceShaderUpdate;
 
+        private bool _prevTfEnable;
+
         /// <summary>
         /// Creates a new instance of the GPU methods class.
         /// </summary>
@@ -124,6 +126,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
         /// <param name="state">Guest GPU state</param>
         private void UpdateState(GpuState state)
         {
+            bool tfEnable = state.Get<Boolean32>(MethodOffset.TfEnable);
+
+            if (!tfEnable && _prevTfEnable)
+            {
+                _context.Renderer.Pipeline.EndTransformFeedback();
+                _prevTfEnable = false;
+            }
+
             // Shaders must be the first one to be updated if modified, because
             // some of the other state depends on information from the currently
             // bound shaders.
@@ -134,6 +144,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 UpdateShaderState(state);
             }
 
+            if (state.QueryModified(MethodOffset.TfBufferState))
+            {
+                UpdateTfBufferState(state);
+            }
+
             if (state.QueryModified(MethodOffset.ClipDistanceEnable))
             {
                 UpdateUserClipState(state);
@@ -258,6 +273,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
             }
 
             CommitBindings();
+
+            if (tfEnable && !_prevTfEnable)
+            {
+                _context.Renderer.Pipeline.BeginTransformFeedback(PrimitiveType.Convert());
+                _prevTfEnable = true;
+            }
         }
 
         /// <summary>
@@ -318,7 +339,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
         /// </summary>
         /// <param name="state">Current GPU state</param>
         /// <param name="useControl">Use draw buffers information from render target control register</param>
-        /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param> 
+        /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
         private void UpdateRenderTargetState(GpuState state, bool useControl, int singleUse = -1)
         {
             var rtControl = state.Get<RtControl>(MethodOffset.RtControl);
@@ -1003,6 +1024,27 @@ namespace Ryujinx.Graphics.Gpu.Engine
             _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
         }
 
+        /// <summary>
+        /// Updates transform feedback buffer state based on the guest GPU state.
+        /// </summary>
+        /// <param name="state">Current GPU state</param>
+        private void UpdateTfBufferState(GpuState state)
+        {
+            for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
+            {
+                TfBufferState tfb = state.Get<TfBufferState>(MethodOffset.TfBufferState, index);
+
+                if (!tfb.Enable)
+                {
+                    BufferManager.SetTransformFeedbackBuffer(index, 0, 0);
+
+                    continue;
+                }
+
+                BufferManager.SetTransformFeedbackBuffer(index, tfb.Address.Pack(), (uint)tfb.Size);
+            }
+        }
+
         /// <summary>
         /// Updates user-defined clipping based on the guest GPU state.
         /// </summary>
-- 
cgit v1.2.3-70-g09d2