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
This commit is contained in:
gdkchan 2022-01-21 12:35:21 -03:00 committed by GitHub
parent 4c4bd46cc3
commit 73d10233ef
19 changed files with 192 additions and 164 deletions

View file

@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly ReadOnlyMemory<byte> _cb1Data;
private readonly GuestGpuAccessorHeader _header;
private readonly Dictionary<int, GuestTextureDescriptor> _textureDescriptors;
private readonly TransformFeedbackDescriptor[] _tfd;
/// <summary>
/// Creates a new instance of the cached GPU state accessor for shader translation.
@ -27,7 +28,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
ReadOnlyMemory<byte> data,
ReadOnlyMemory<byte> cb1Data,
GuestGpuAccessorHeader header,
IReadOnlyDictionary<int, GuestTextureDescriptor> guestTextureDescriptors) : base(context)
IReadOnlyDictionary<int, GuestTextureDescriptor> 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;
}
/// <summary>
@ -177,6 +181,35 @@ namespace Ryujinx.Graphics.Gpu.Shader
return textureDescriptor;
}
/// <summary>
/// Queries transform feedback enable state.
/// </summary>
/// <returns>True if the shader uses transform feedback, false otherwise</returns>
public bool QueryTransformFeedbackEnabled()
{
return _tfd != null;
}
/// <summary>
/// Queries the varying locations that should be written to the transform feedback buffer.
/// </summary>
/// <param name="bufferIndex">Index of the transform feedback buffer</param>
/// <returns>Varying locations for the specified buffer</returns>
public ReadOnlySpan<byte> QueryTransformFeedbackVaryingLocations(int bufferIndex)
{
return _tfd[bufferIndex].VaryingLocations;
}
/// <summary>
/// Queries the stride (in bytes) of the per vertex data written into the transform feedback buffer.
/// </summary>
/// <param name="bufferIndex">Index of the transform feedback buffer</param>
/// <returns>Stride for the specified buffer</returns>
public int QueryTransformFeedbackStride(int bufferIndex)
{
return _tfd[bufferIndex].Stride;
}
/// <summary>
/// Queries if host state forces early depth testing.
/// </summary>

View file

@ -222,6 +222,35 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
}
/// <summary>
/// Queries transform feedback enable state.
/// </summary>
/// <returns>True if the shader uses transform feedback, false otherwise</returns>
public bool QueryTransformFeedbackEnabled()
{
return _state.TransformFeedbackDescriptors != null;
}
/// <summary>
/// Queries the varying locations that should be written to the transform feedback buffer.
/// </summary>
/// <param name="bufferIndex">Index of the transform feedback buffer</param>
/// <returns>Varying locations for the specified buffer</returns>
public ReadOnlySpan<byte> QueryTransformFeedbackVaryingLocations(int bufferIndex)
{
return _state.TransformFeedbackDescriptors[bufferIndex].VaryingLocations;
}
/// <summary>
/// Queries the stride (in bytes) of the per vertex data written into the transform feedback buffer.
/// </summary>
/// <param name="bufferIndex">Index of the transform feedback buffer</param>
/// <returns>Stride for the specified buffer</returns>
public int QueryTransformFeedbackStride(int bufferIndex)
{
return _state.TransformFeedbackDescriptors[bufferIndex].Stride;
}
/// <summary>
/// Queries if host state forces early depth testing.
/// </summary>

View file

@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
public TessMode TessellationMode { get; }
/// <summary>
/// Transform feedback information, if the shader uses transform feedback. Otherwise, should be null.
/// </summary>
public TransformFeedbackDescriptor[] TransformFeedbackDescriptors { get; set; }
/// <summary>
/// Creates a new instance of the GPU accessor state.
/// </summary>
@ -61,6 +66,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
EarlyZForce = earlyZForce;
Topology = topology;
TessellationMode = tessellationMode;
TransformFeedbackDescriptors = null;
}
}
}

View file

@ -40,7 +40,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 = 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);

View file

@ -0,0 +1,19 @@
using System;
namespace Ryujinx.Graphics.Gpu.Shader
{
struct TransformFeedbackDescriptor
{
public int BufferIndex { get; }
public int Stride { get; }
public byte[] VaryingLocations { get; }
public TransformFeedbackDescriptor(int bufferIndex, int stride, byte[] varyingLocations)
{
BufferIndex = bufferIndex;
Stride = stride;
VaryingLocations = varyingLocations ?? throw new ArgumentNullException(nameof(varyingLocations));
}
}
}