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.OpenGL/Program.cs | 54 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)

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

diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs
index 8b4f6e24..a0f8eb01 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -2,6 +2,10 @@ using OpenTK.Graphics.OpenGL;
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Shader;
+using Ryujinx.Graphics.Shader.CodeGen.Glsl;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace Ryujinx.Graphics.OpenGL
 {
@@ -31,7 +35,7 @@ namespace Ryujinx.Graphics.OpenGL
         private int[] _textureUnits;
         private int[] _imageUnits;
 
-        public Program(IShader[] shaders)
+        public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
         {
             _ubBindingPoints = new int[UbsPerStage  * ShaderStages];
             _sbBindingPoints = new int[SbsPerStage  * ShaderStages];
@@ -67,6 +71,54 @@ namespace Ryujinx.Graphics.OpenGL
                 GL.AttachShader(Handle, shaderHandle);
             }
 
+            if (transformFeedbackDescriptors != null)
+            {
+                List<string> varyings = new List<string>();
+
+                int cbi = 0;
+
+                foreach (var tfd in transformFeedbackDescriptors.OrderBy(x => x.BufferIndex))
+                {
+                    if (tfd.VaryingLocations.Length == 0)
+                    {
+                        continue;
+                    }
+
+                    while (cbi < tfd.BufferIndex)
+                    {
+                        varyings.Add("gl_NextBuffer");
+
+                        cbi++;
+                    }
+
+                    int stride = Math.Min(128 * 4, (tfd.Stride + 3) & ~3);
+
+                    int j = 0;
+
+                    for (; j < tfd.VaryingLocations.Length && j * 4 < stride; j++)
+                    {
+                        byte location = tfd.VaryingLocations[j];
+
+                        varyings.Add(Varying.GetName(location) ?? "gl_SkipComponents1");
+
+                        j += Varying.GetSize(location) - 1;
+                    }
+
+                    int feedbackBytes = j * 4;
+
+                    while (feedbackBytes < stride)
+                    {
+                        int bytes = Math.Min(16, stride - feedbackBytes);
+
+                        varyings.Add($"gl_SkipComponents{(bytes / 4)}");
+
+                        feedbackBytes += bytes;
+                    }
+                }
+
+                GL.TransformFeedbackVaryings(Handle, varyings.Count, varyings.ToArray(), TransformFeedbackMode.InterleavedAttribs);
+            }
+
             GL.LinkProgram(Handle);
 
             for (int index = 0; index < shaders.Length; index++)
-- 
cgit v1.2.3-70-g09d2