From 4dd77316f722f6b429063784b56ddced7883ea1d Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 24 Apr 2023 03:34:38 -0300 Subject: [PATCH] Use vector transform feedback outputs with fragment shaders (#4708) * Use vector transform feedback outputs with fragment shaders * Shader cache version bump * Fix missing outputs when vector transform feedback outputs are used --- .../Shader/DiskCache/DiskCacheHostStorage.cs | 2 +- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- .../CodeGen/Glsl/Declarations.cs | 44 ++++++++++++------- .../CodeGen/Glsl/OperandManager.cs | 2 +- .../CodeGen/Spirv/CodeGenContext.cs | 2 +- .../CodeGen/Spirv/Declarations.cs | 2 +- .../StructuredIr/StructuredProgram.cs | 2 +- .../Translation/ShaderConfig.cs | 11 +---- .../Translation/TranslatorContext.cs | 4 +- 9 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 48464f8326..cad2341b23 100644 --- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 4703; + private const uint CodeGenVersion = 4707; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 11f7085d3e..e1ab93278c 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -449,7 +449,7 @@ namespace Ryujinx.Graphics.Gpu.Shader if (translatorContexts[i] != null) { translatorContexts[i].SetGeometryShaderLayerInputAttribute(info.GpLayerInputAttribute); - translatorContexts[i].SetLastInVertexPipeline(translatorContexts[5] != null); + translatorContexts[i].SetLastInVertexPipeline(); break; } } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index 9032ca59ec..5e53d62a14 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -569,7 +569,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl if (context.Config.TransformFeedbackEnabled && context.Config.Stage == ShaderStage.Fragment) { - for (int c = 0; c < 4; c++) + int attrOffset = AttributeConsts.UserAttributeBase + attr * 16; + int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset); + + if (components > 1) + { + string type = components switch + { + 2 => "vec2", + 3 => "vec3", + 4 => "vec4", + _ => "float" + }; + + context.AppendLine($"layout (location = {attr}) in {type} {name};"); + } + + for (int c = components > 1 ? components : 0; c < 4; c++) { char swzMask = "xyzw"[c]; @@ -642,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline) { int attrOffset = AttributeConsts.UserAttributeBase + attr * 16; - int components = context.Config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1; + int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset); if (components > 1) { @@ -664,22 +680,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine($"layout (location = {attr}{xfb}) out {type} {name};"); } - else + + for (int c = components > 1 ? components : 0; c < 4; c++) { - for (int c = 0; c < 4; c++) + char swzMask = "xyzw"[c]; + + string xfb = string.Empty; + + var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4); + if (tfOutput.Valid) { - char swzMask = "xyzw"[c]; - - string xfb = string.Empty; - - var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4); - if (tfOutput.Valid) - { - xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}"; - } - - context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};"); + xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}"; } + + context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};"); } } else diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs index ce1ab50e04..ec761fa664 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs @@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl ((config.LastInVertexPipeline && isOutAttr) || (config.Stage == ShaderStage.Fragment && !isOutAttr))) { - int components = config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1; + int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset); string name = components > 1 ? $"{prefix}{(value >> 4)}" : $"{prefix}{(value >> 4)}_{swzMask}"; if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr)) diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs index 41afdf1884..e693307da2 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs @@ -341,7 +341,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv attrOffset = attr; type = elemType; - if (Config.LastInPipeline && isOutAttr) + if (isOutAttr) { int components = Info.GetTransformFeedbackOutputComponents(attr); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index df42a13cb7..fdca5e890b 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs @@ -673,7 +673,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv int components = 1; var type = attrInfo.Type & AggregateType.ElementTypeMask; - if (context.Config.LastInPipeline && isOutAttr) + if (isOutAttr) { components = context.Info.GetTransformFeedbackOutputComponents(attr); diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index ec989cca55..b8d38fa659 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr context.LeaveFunction(); } - if (config.TransformFeedbackEnabled && config.LastInVertexPipeline) + if (config.TransformFeedbackEnabled && (config.LastInVertexPipeline || config.Stage == ShaderStage.Fragment)) { for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++) { diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index 2caa8f6389..15eb7ed1f2 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -17,7 +17,6 @@ namespace Ryujinx.Graphics.Shader.Translation public ShaderStage Stage { get; } public bool GpPassthrough { get; } - public bool LastInPipeline { get; private set; } public bool LastInVertexPipeline { get; private set; } public bool HasLayerInputAttribute { get; private set; } @@ -145,7 +144,6 @@ namespace Ryujinx.Graphics.Shader.Translation OmapSampleMask = header.OmapSampleMask; OmapDepth = header.OmapDepth; TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled(); - LastInPipeline = true; LastInVertexPipeline = header.Stage < ShaderStage.Fragment; } @@ -253,13 +251,8 @@ namespace Ryujinx.Graphics.Shader.Translation GpLayerInputAttribute = attr; } - public void SetLastInVertexPipeline(bool hasFragment) + public void SetLastInVertexPipeline() { - if (!hasFragment) - { - LastInPipeline = true; - } - LastInVertexPipeline = true; } @@ -331,8 +324,6 @@ namespace Ryujinx.Graphics.Shader.Translation config._perPatchAttributeLocations = locationsMap; } - LastInPipeline = false; - // We don't consider geometry shaders using the geometry shader passthrough feature // as being the last because when this feature is used, it can't actually modify any of the outputs, // so the stage that comes before it is the last one that can do modifications. diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs index 3b88fdbabc..856b16b7d3 100644 --- a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs +++ b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs @@ -143,9 +143,9 @@ namespace Ryujinx.Graphics.Shader.Translation _config.SetGeometryShaderLayerInputAttribute(attr); } - public void SetLastInVertexPipeline(bool hasFragment) + public void SetLastInVertexPipeline() { - _config.SetLastInVertexPipeline(hasFragment); + _config.SetLastInVertexPipeline(); } public ShaderProgram Translate(TranslatorContext other = null)