diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index f4fef145..f266bbb4 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 1964; + private const ulong ShaderCodeGenVersion = 1961; /// /// 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 a6109a95..dd3c8196 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 276544fc..37a1cd89 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 637ce8fe..b1fd6470 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 1218d591..ff5932e1 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);