From 7e967d796cf572377f21af3817a22755c5b01cb1 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 21 Jan 2022 12:35:21 -0300 Subject: [PATCH] Stop using glTransformFeedbackVaryings and use explicit layout on the shader (#3012) * Stop using glTransformFeedbackVarying and use explicit layout on the shader * This is no longer needed * Shader cache version bump * Fix gl_PerVertex output for tessellation control shaders --- Ryujinx.Graphics.GAL/IRenderer.cs | 2 +- .../Programs/SourceProgramRequest.cs | 6 +- .../Multithreading/ThreadedRenderer.cs | 4 +- .../Shader/CachedGpuAccessor.cs | 35 +++++++++- Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs | 29 ++++++++ .../Shader/GpuAccessorState.cs | 6 ++ Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 46 +++++-------- .../Shader}/TransformFeedbackDescriptor.cs | 4 +- Ryujinx.Graphics.OpenGL/Program.cs | 50 +------------- Ryujinx.Graphics.OpenGL/Renderer.cs | 4 +- .../CodeGen/Glsl/CodeGenContext.cs | 12 ++++ .../CodeGen/Glsl/Declarations.cs | 28 +++++++- .../CodeGen/Glsl/OperandManager.cs | 2 +- .../CodeGen/Glsl/Varying.cs | 69 ------------------- Ryujinx.Graphics.Shader/IGpuAccessor.cs | 15 ++++ .../StructuredIr/StructuredProgram.cs | 18 +++++ .../StructuredIr/StructuredProgramInfo.cs | 20 ++++++ .../Translation/ShaderConfig.cs | 3 + .../Translation/TranslationFlags.cs | 3 +- 19 files changed, 192 insertions(+), 164 deletions(-) rename {Ryujinx.Graphics.GAL => Ryujinx.Graphics.Gpu/Shader}/TransformFeedbackDescriptor.cs (85%) delete mode 100644 Ryujinx.Graphics.Shader/CodeGen/Glsl/Varying.cs diff --git a/Ryujinx.Graphics.GAL/IRenderer.cs b/Ryujinx.Graphics.GAL/IRenderer.cs index 7c0cb394..a1193208 100644 --- a/Ryujinx.Graphics.GAL/IRenderer.cs +++ b/Ryujinx.Graphics.GAL/IRenderer.cs @@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL BufferHandle CreateBuffer(int size); - IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors); + IProgram CreateProgram(IShader[] shaders); ISampler CreateSampler(SamplerCreateInfo info); ITexture CreateTexture(TextureCreateInfo info, float scale); diff --git a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs index d40ce6a4..8e4cd1d4 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs @@ -7,14 +7,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs public ThreadedProgram Threaded { get; set; } private IShader[] _shaders; - private TransformFeedbackDescriptor[] _transformFeedbackDescriptors; - public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors) + public SourceProgramRequest(ThreadedProgram program, IShader[] shaders) { Threaded = program; _shaders = shaders; - _transformFeedbackDescriptors = transformFeedbackDescriptors; } public IProgram Create(IRenderer renderer) @@ -26,7 +24,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs return threaded?.Base; }).ToArray(); - return renderer.CreateProgram(shaders, _transformFeedbackDescriptors); + return renderer.CreateProgram(shaders); } } } diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index 52197688..df46b428 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading return handle; } - public IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors) + public IProgram CreateProgram(IShader[] shaders) { var program = new ThreadedProgram(this); - SourceProgramRequest request = new SourceProgramRequest(program, shaders, transformFeedbackDescriptors); + SourceProgramRequest request = new SourceProgramRequest(program, shaders); Programs.Add(request); New().Set(Ref((IProgramRequest)request)); diff --git a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs index 21d08823..d65349a5 100644 --- a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs @@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Shader private readonly ReadOnlyMemory _cb1Data; private readonly GuestGpuAccessorHeader _header; private readonly Dictionary _textureDescriptors; + private readonly TransformFeedbackDescriptor[] _tfd; /// /// Creates a new instance of the cached GPU state accessor for shader translation. @@ -27,7 +28,8 @@ namespace Ryujinx.Graphics.Gpu.Shader ReadOnlyMemory data, ReadOnlyMemory cb1Data, GuestGpuAccessorHeader header, - IReadOnlyDictionary guestTextureDescriptors) : base(context) + IReadOnlyDictionary guestTextureDescriptors, + TransformFeedbackDescriptor[] tfd) : base(context) { _data = data; _cb1Data = cb1Data; @@ -38,6 +40,8 @@ namespace Ryujinx.Graphics.Gpu.Shader { _textureDescriptors.Add(guestTextureDescriptor.Key, guestTextureDescriptor.Value); } + + _tfd = tfd; } /// @@ -177,6 +181,35 @@ namespace Ryujinx.Graphics.Gpu.Shader return textureDescriptor; } + /// + /// Queries transform feedback enable state. + /// + /// True if the shader uses transform feedback, false otherwise + public bool QueryTransformFeedbackEnabled() + { + return _tfd != null; + } + + /// + /// Queries the varying locations that should be written to the transform feedback buffer. + /// + /// Index of the transform feedback buffer + /// Varying locations for the specified buffer + public ReadOnlySpan QueryTransformFeedbackVaryingLocations(int bufferIndex) + { + return _tfd[bufferIndex].VaryingLocations; + } + + /// + /// Queries the stride (in bytes) of the per vertex data written into the transform feedback buffer. + /// + /// Index of the transform feedback buffer + /// Stride for the specified buffer + public int QueryTransformFeedbackStride(int bufferIndex) + { + return _tfd[bufferIndex].Stride; + } + /// /// Queries if host state forces early depth testing. /// diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index 64604a99..a5c7575f 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -222,6 +222,35 @@ namespace Ryujinx.Graphics.Gpu.Shader } } + /// + /// Queries transform feedback enable state. + /// + /// True if the shader uses transform feedback, false otherwise + public bool QueryTransformFeedbackEnabled() + { + return _state.TransformFeedbackDescriptors != null; + } + + /// + /// Queries the varying locations that should be written to the transform feedback buffer. + /// + /// Index of the transform feedback buffer + /// Varying locations for the specified buffer + public ReadOnlySpan QueryTransformFeedbackVaryingLocations(int bufferIndex) + { + return _state.TransformFeedbackDescriptors[bufferIndex].VaryingLocations; + } + + /// + /// Queries the stride (in bytes) of the per vertex data written into the transform feedback buffer. + /// + /// Index of the transform feedback buffer + /// Stride for the specified buffer + public int QueryTransformFeedbackStride(int bufferIndex) + { + return _state.TransformFeedbackDescriptors[bufferIndex].Stride; + } + /// /// Queries if host state forces early depth testing. /// diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs index ebbf3b69..6818072b 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs @@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// public TessMode TessellationMode { get; } + /// + /// Transform feedback information, if the shader uses transform feedback. Otherwise, should be null. + /// + public TransformFeedbackDescriptor[] TransformFeedbackDescriptors { get; set; } + /// /// Creates a new instance of the GPU accessor state. /// @@ -61,6 +66,7 @@ namespace Ryujinx.Graphics.Gpu.Shader EarlyZForce = earlyZForce; Topology = topology; TessellationMode = tessellationMode; + TransformFeedbackDescriptors = null; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 4c6224e3..110115e7 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 2972; + private const ulong ShaderCodeGenVersion = 3012; // Progress reporting helpers private volatile int _shaderCount; @@ -227,7 +227,8 @@ namespace Ryujinx.Graphics.Gpu.Shader binaryCode, binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize), entry.Header.GpuAccessorHeader, - entry.TextureDescriptors); + entry.TextureDescriptors, + null); var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags | TranslationFlags.Compute); program = Translator.CreateContext(0, gpuAccessor, options).Translate(out shaderProgramInfo); @@ -251,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Shader // Compile shader and create program as the shader program binary got invalidated. shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code); - hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); + hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }); task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) => { @@ -293,13 +294,6 @@ namespace Ryujinx.Graphics.Gpu.Shader TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader); - TranslationFlags flags = DefaultFlags; - - if (tfd != null) - { - flags |= TranslationFlags.Feedback; - } - TranslationCounts counts = new TranslationCounts(); HostShaderCacheEntry[] hostShaderEntries = null; @@ -343,15 +337,16 @@ namespace Ryujinx.Graphics.Gpu.Shader binaryCode, binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize), entry.Header.GpuAccessorHeader, - entry.TextureDescriptors); + entry.TextureDescriptors, + tfd); - var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags); + var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags); shaderContexts[i + 1] = Translator.CreateContext(0, gpuAccessor, options, counts); if (entry.Header.SizeA != 0) { - var options2 = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags | TranslationFlags.VertexA); + var options2 = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags | TranslationFlags.VertexA); shaderContexts[0] = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, options2, counts); } @@ -431,7 +426,7 @@ namespace Ryujinx.Graphics.Gpu.Shader hostShaders.Add(hostShader); } - hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd); + hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray()); task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) => { @@ -622,7 +617,7 @@ namespace Ryujinx.Graphics.Gpu.Shader shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); - IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); + IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }); cpShader = new ShaderBundle(hostProgram, shader); @@ -684,25 +679,20 @@ namespace Ryujinx.Graphics.Gpu.Shader TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(ref state); - TranslationFlags flags = DefaultFlags; - - if (tfd != null) - { - flags |= TranslationFlags.Feedback; - } + gas.TransformFeedbackDescriptors = tfd; TranslationCounts counts = new TranslationCounts(); if (addresses.VertexA != 0) { - shaderContexts[0] = DecodeGraphicsShader(channel, gas, counts, flags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA); + shaderContexts[0] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA); } - shaderContexts[1] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Vertex, addresses.Vertex); - shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationControl, addresses.TessControl); - shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation); - shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Geometry, addresses.Geometry); - shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Fragment, addresses.Fragment); + shaderContexts[1] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.Vertex, addresses.Vertex); + shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.TessellationControl, addresses.TessControl); + shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation); + shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.Geometry, addresses.Geometry); + shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.Fragment, addresses.Fragment); bool isShaderCacheEnabled = _cacheManager != null; bool isShaderCacheReadOnly = false; @@ -765,7 +755,7 @@ namespace Ryujinx.Graphics.Gpu.Shader hostShaders.Add(hostShader); } - IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd); + IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray()); gpShaders = new ShaderBundle(hostProgram, shaders); diff --git a/Ryujinx.Graphics.GAL/TransformFeedbackDescriptor.cs b/Ryujinx.Graphics.Gpu/Shader/TransformFeedbackDescriptor.cs similarity index 85% rename from Ryujinx.Graphics.GAL/TransformFeedbackDescriptor.cs rename to Ryujinx.Graphics.Gpu/Shader/TransformFeedbackDescriptor.cs index 690b9108..eaa889cc 100644 --- a/Ryujinx.Graphics.GAL/TransformFeedbackDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/TransformFeedbackDescriptor.cs @@ -1,8 +1,8 @@ using System; -namespace Ryujinx.Graphics.GAL +namespace Ryujinx.Graphics.Gpu.Shader { - public struct TransformFeedbackDescriptor + struct TransformFeedbackDescriptor { public int BufferIndex { get; } public int Stride { get; } diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs index 785f2f00..95902990 100644 --- a/Ryujinx.Graphics.OpenGL/Program.cs +++ b/Ryujinx.Graphics.OpenGL/Program.cs @@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.OpenGL private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; private IShader[] _shaders; - public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors) + public Program(IShader[] shaders) { Handle = GL.CreateProgram(); @@ -42,54 +42,6 @@ namespace Ryujinx.Graphics.OpenGL GL.AttachShader(Handle, shaderHandle); } - if (transformFeedbackDescriptors != null) - { - List varyings = new List(); - - 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); _shaders = shaders; diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs index d725eb7c..ceacbf29 100644 --- a/Ryujinx.Graphics.OpenGL/Renderer.cs +++ b/Ryujinx.Graphics.OpenGL/Renderer.cs @@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL return Buffer.Create(size); } - public IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors) + public IProgram CreateProgram(IShader[] shaders) { - return new Program(shaders, transformFeedbackDescriptors); + return new Program(shaders); } public ISampler CreateSampler(SamplerCreateInfo info) diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs index f0f8ea35..b4823019 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/CodeGenContext.cs @@ -103,6 +103,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl return _info.Functions[id]; } + public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component) + { + int index = (AttributeConsts.UserAttributeBase / 4) + location * 4 + component; + return _info.TransformFeedbackOutputs[index]; + } + + public TransformFeedbackOutput GetTransformFeedbackOutput(int location) + { + int index = location / 4; + return _info.TransformFeedbackOutputs[index]; + } + private void UpdateIndentation() { _indentation = GetIndentation(_level); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index d8956567..55d5551c 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -191,6 +191,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine(); } + + if (context.Config.Stage != ShaderStage.Compute && + context.Config.Stage != ShaderStage.Fragment && + context.Config.TransformFeedbackEnabled) + { + var tfOutput = context.GetTransformFeedbackOutput(AttributeConsts.PositionX); + if (tfOutput.Valid) + { + context.AppendLine($"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) out gl_PerVertex"); + context.EnterScope(); + context.AppendLine("vec4 gl_Position;"); + context.LeaveScope(context.Config.Stage == ShaderStage.TessellationControl ? " gl_out[];" : ";"); + } + } } else { @@ -514,7 +528,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl string pass = (context.Config.PassthroughAttributes & (1 << attr)) != 0 ? "passthrough, " : string.Empty; string name = $"{DefaultNames.IAttributePrefix}{attr}"; - if ((context.Config.Options.Flags & TranslationFlags.Feedback) != 0) + if (context.Config.TransformFeedbackEnabled && context.Config.Stage != ShaderStage.Vertex) { for (int c = 0; c < 4; c++) { @@ -559,13 +573,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl string suffix = OperandManager.IsArrayAttribute(context.Config.Stage, isOutAttr: true) ? "[]" : string.Empty; string name = $"{DefaultNames.OAttributePrefix}{attr}{suffix}"; - if ((context.Config.Options.Flags & TranslationFlags.Feedback) != 0) + if (context.Config.TransformFeedbackEnabled && context.Config.Stage != ShaderStage.Fragment) { for (int c = 0; c < 4; c++) { char swzMask = "xyzw"[c]; - context.AppendLine($"layout (location = {attr}, component = {c}) out float {name}_{swzMask};"); + string xfb = string.Empty; + + var tfOutput = context.GetTransformFeedbackOutput(attr, c); + 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};"); } } else diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs index 9680df27..b1bd8188 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs @@ -194,7 +194,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl return name + $"[{(value >> 4)}]." + swzMask; } - else if (config.Options.Flags.HasFlag(TranslationFlags.Feedback)) + else if (config.TransformFeedbackEnabled && (config.Stage != ShaderStage.Vertex || isOutAttr)) { string name = $"{prefix}{(value >> 4)}_{swzMask}"; diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Varying.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Varying.cs deleted file mode 100644 index b9b2afb4..00000000 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Varying.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Ryujinx.Graphics.Shader.Translation; - -namespace Ryujinx.Graphics.Shader.CodeGen.Glsl -{ - public static class Varying - { - public static string GetName(int offset) - { - offset <<= 2; - - if (offset >= AttributeConsts.UserAttributeBase && - offset < AttributeConsts.UserAttributeEnd) - { - offset -= AttributeConsts.UserAttributeBase; - - string name = $"{ DefaultNames.OAttributePrefix}{(offset >> 4)}"; - - name += "_" + "xyzw"[(offset >> 2) & 3]; - - return name; - } - - switch (offset) - { - case AttributeConsts.PositionX: - case AttributeConsts.PositionY: - case AttributeConsts.PositionZ: - case AttributeConsts.PositionW: - return "gl_Position"; - case AttributeConsts.PointSize: - return "gl_PointSize"; - case AttributeConsts.ClipDistance0: - return "gl_ClipDistance[0]"; - case AttributeConsts.ClipDistance1: - return "gl_ClipDistance[1]"; - case AttributeConsts.ClipDistance2: - return "gl_ClipDistance[2]"; - case AttributeConsts.ClipDistance3: - return "gl_ClipDistance[3]"; - case AttributeConsts.ClipDistance4: - return "gl_ClipDistance[4]"; - case AttributeConsts.ClipDistance5: - return "gl_ClipDistance[5]"; - case AttributeConsts.ClipDistance6: - return "gl_ClipDistance[6]"; - case AttributeConsts.ClipDistance7: - return "gl_ClipDistance[7]"; - case AttributeConsts.VertexId: - return "gl_VertexID"; - } - - return null; - } - - public static int GetSize(int offset) - { - switch (offset << 2) - { - case AttributeConsts.PositionX: - case AttributeConsts.PositionY: - case AttributeConsts.PositionZ: - case AttributeConsts.PositionW: - return 4; - } - - return 1; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs index 27f6f53b..b2512868 100644 --- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -131,6 +131,21 @@ namespace Ryujinx.Graphics.Shader return TextureFormat.R8G8B8A8Unorm; } + bool QueryTransformFeedbackEnabled() + { + return false; + } + + ReadOnlySpan QueryTransformFeedbackVaryingLocations(int bufferIndex) + { + return ReadOnlySpan.Empty; + } + + int QueryTransformFeedbackStride(int bufferIndex) + { + return 0; + } + bool QueryEarlyZForce() { return false; diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index 61cc167a..31c71f20 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -64,6 +64,24 @@ namespace Ryujinx.Graphics.Shader.StructuredIr context.LeaveFunction(); } + if (config.TransformFeedbackEnabled) + { + for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++) + { + var locations = config.GpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex); + var stride = config.GpuAccessor.QueryTransformFeedbackStride(tfbIndex); + + for (int j = 0; j < locations.Length; j++) + { + byte location = locations[j]; + if (location < 0x80) + { + context.Info.TransformFeedbackOutputs[location] = new TransformFeedbackOutput(tfbIndex, j * 4, stride); + } + } + } + } + return context.Info; } diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs index aeaa03ec..933f265f 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs @@ -2,15 +2,35 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.StructuredIr { + struct TransformFeedbackOutput + { + public readonly bool Valid; + public readonly int Buffer; + public readonly int Offset; + public readonly int Stride; + + public TransformFeedbackOutput(int buffer, int offset, int stride) + { + Valid = true; + Buffer = buffer; + Offset = offset; + Stride = stride; + } + } + class StructuredProgramInfo { public List Functions { get; } public HelperFunctionsMask HelperFunctionsMask { get; set; } + public TransformFeedbackOutput[] TransformFeedbackOutputs { get; } + public StructuredProgramInfo() { Functions = new List(); + + TransformFeedbackOutputs = new TransformFeedbackOutput[0x80]; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index 9d5a4070..21f17041 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -33,6 +33,8 @@ namespace Ryujinx.Graphics.Shader.Translation public TranslationOptions Options { get; } + public bool TransformFeedbackEnabled { get; } + public int Size { get; private set; } public byte ClipDistancesWritten { get; private set; } @@ -128,6 +130,7 @@ namespace Ryujinx.Graphics.Shader.Translation OmapTargets = header.OmapTargets; OmapSampleMask = header.OmapSampleMask; OmapDepth = header.OmapDepth; + TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled(); } public int GetDepthRegister() diff --git a/Ryujinx.Graphics.Shader/Translation/TranslationFlags.cs b/Ryujinx.Graphics.Shader/Translation/TranslationFlags.cs index 9af95389..1874dec3 100644 --- a/Ryujinx.Graphics.Shader/Translation/TranslationFlags.cs +++ b/Ryujinx.Graphics.Shader/Translation/TranslationFlags.cs @@ -9,7 +9,6 @@ namespace Ryujinx.Graphics.Shader.Translation VertexA = 1 << 0, Compute = 1 << 1, - Feedback = 1 << 2, - DebugMode = 1 << 3 + DebugMode = 1 << 2 } } \ No newline at end of file