From f93089a64f9586863e8a261af932d125e78230df Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Fri, 29 Jan 2021 00:38:51 -0300
Subject: [PATCH] Implement geometry shader passthrough (#1961)

* Implement geometry shader passthrough

* Cache version change
---
 Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs    |  2 +-
 .../CodeGen/Glsl/Declarations.cs              | 52 +++++++++++++------
 .../CodeGen/Glsl/GlslGenerator.cs             |  3 +-
 .../Translation/ShaderConfig.cs               |  4 ++
 .../Translation/ShaderHeader.cs               |  4 ++
 5 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index f4fef14513..f266bbb449 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <summary>
         /// Version of the codegen (to be changed when codegen or guest format change).
         /// </summary>
-        private const ulong ShaderCodeGenVersion = 1964;
+        private const ulong ShaderCodeGenVersion = 1961;
 
         /// <summary>
         /// Creates a new instance of the shader cache.
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index a6109a9597..dd3c8196bc 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -26,6 +26,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                 context.AppendLine("#extension GL_ARB_compute_shader : enable");
             }
 
+            if (context.Config.GpPassthrough)
+            {
+                context.AppendLine("#extension GL_NV_geometry_shader_passthrough : enable");
+            }
+
             context.AppendLine("#pragma optionNV(fastmath off)");
 
             context.AppendLine();
@@ -33,20 +38,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
             context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
             context.AppendLine();
 
-            if (context.Config.Stage == ShaderStage.Geometry)
-            {
-                string inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology().ToGlslString();
-
-                context.AppendLine($"layout ({inPrimitive}) in;");
-
-                string outPrimitive = context.Config.OutputTopology.ToGlslString();
-
-                int maxOutputVertices = context.Config.MaxOutputVertices;
-
-                context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
-                context.AppendLine();
-            }
-
             if (context.Config.Stage == ShaderStage.Compute)
             {
                 int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
@@ -109,6 +100,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
             if (context.Config.Stage != ShaderStage.Compute)
             {
+                if (context.Config.Stage == ShaderStage.Geometry)
+                {
+                    string inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology().ToGlslString();
+
+                    context.AppendLine($"layout ({inPrimitive}) in;");
+
+                    if (context.Config.GpPassthrough)
+                    {
+                        context.AppendLine($"layout (passthrough) in gl_PerVertex");
+                        context.EnterScope();
+                        context.AppendLine("vec4 gl_Position;");
+                        context.AppendLine("float gl_PointSize;");
+                        context.AppendLine("float gl_ClipDistance[];");
+                        context.LeaveScope(";");
+                    }
+                    else
+                    {
+                        string outPrimitive = context.Config.OutputTopology.ToGlslString();
+
+                        int maxOutputVertices = context.Config.MaxOutputVertices;
+
+                        context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
+                    }
+
+                    context.AppendLine();
+                }
+
                 if (info.IAttributes.Count != 0)
                 {
                     DeclareInputAttributes(context, info);
@@ -432,6 +450,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                     };
                 }
 
+                string pass = context.Config.GpPassthrough ? "passthrough, " : string.Empty;
+
                 string name = $"{DefaultNames.IAttributePrefix}{attr}";
 
                 if ((context.Config.Flags & TranslationFlags.Feedback) != 0)
@@ -440,12 +460,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                     {
                         char swzMask = "xyzw"[c];
 
-                        context.AppendLine($"layout (location = {attr}, component = {c}) {iq}in float {name}_{swzMask}{suffix};");
+                        context.AppendLine($"layout ({pass}location = {attr}, component = {c}) {iq}in float {name}_{swzMask}{suffix};");
                     }
                 }
                 else
                 {
-                    context.AppendLine($"layout (location = {attr}) {iq}in vec4 {name}{suffix};");
+                    context.AppendLine($"layout ({pass}location = {attr}) {iq}in vec4 {name}{suffix};");
                 }
             }
         }
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
index 276544fca6..37a1cd89cb 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
@@ -69,7 +69,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                 // compiler may eliminate them.
                 // (Not needed for fragment shader as it is the last stage).
                 if (context.Config.Stage != ShaderStage.Compute &&
-                    context.Config.Stage != ShaderStage.Fragment)
+                    context.Config.Stage != ShaderStage.Fragment &&
+                    !context.Config.GpPassthrough)
                 {
                     for (int attr = 0; attr < Declarations.MaxAttributes; attr++)
                     {
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 637ce8fe0f..b1fd6470ea 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.Shader.Translation
     {
         public ShaderStage Stage { get; }
 
+        public bool GpPassthrough { get; }
+
         public OutputTopology OutputTopology { get; }
 
         public int MaxOutputVertices { get; }
@@ -33,6 +35,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
         {
             Stage                  = ShaderStage.Compute;
+            GpPassthrough          = false;
             OutputTopology         = OutputTopology.PointList;
             MaxOutputVertices      = 0;
             LocalMemorySize        = 0;
@@ -51,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
         {
             Stage                  = header.Stage;
+            GpPassthrough          = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
             OutputTopology         = header.OutputTopology;
             MaxOutputVertices      = header.MaxOutputVertexCount;
             LocalMemorySize        = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
index 1218d591b9..ff5932e15a 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
@@ -81,6 +81,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public int SassVersion { get; }
 
+        public bool GpPassthrough { get; }
+
         public bool DoesLoadOrStore { get; }
         public bool DoesFp64        { get; }
 
@@ -136,6 +138,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 
             SassVersion = commonWord0.Extract(17, 4);
 
+            GpPassthrough = commonWord0.Extract(24);
+
             DoesLoadOrStore = commonWord0.Extract(26);
             DoesFp64        = commonWord0.Extract(27);