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:
parent
0e59573f2b
commit
7e967d796c
19 changed files with 192 additions and 164 deletions
|
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
BufferHandle CreateBuffer(int size);
|
BufferHandle CreateBuffer(int size);
|
||||||
|
|
||||||
IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors);
|
IProgram CreateProgram(IShader[] shaders);
|
||||||
|
|
||||||
ISampler CreateSampler(SamplerCreateInfo info);
|
ISampler CreateSampler(SamplerCreateInfo info);
|
||||||
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
||||||
|
|
|
@ -7,14 +7,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
|
||||||
public ThreadedProgram Threaded { get; set; }
|
public ThreadedProgram Threaded { get; set; }
|
||||||
|
|
||||||
private IShader[] _shaders;
|
private IShader[] _shaders;
|
||||||
private TransformFeedbackDescriptor[] _transformFeedbackDescriptors;
|
|
||||||
|
|
||||||
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders)
|
||||||
{
|
{
|
||||||
Threaded = program;
|
Threaded = program;
|
||||||
|
|
||||||
_shaders = shaders;
|
_shaders = shaders;
|
||||||
_transformFeedbackDescriptors = transformFeedbackDescriptors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram Create(IRenderer renderer)
|
public IProgram Create(IRenderer renderer)
|
||||||
|
@ -26,7 +24,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
|
||||||
return threaded?.Base;
|
return threaded?.Base;
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
return renderer.CreateProgram(shaders, _transformFeedbackDescriptors);
|
return renderer.CreateProgram(shaders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
public IProgram CreateProgram(IShader[] shaders)
|
||||||
{
|
{
|
||||||
var program = new ThreadedProgram(this);
|
var program = new ThreadedProgram(this);
|
||||||
SourceProgramRequest request = new SourceProgramRequest(program, shaders, transformFeedbackDescriptors);
|
SourceProgramRequest request = new SourceProgramRequest(program, shaders);
|
||||||
Programs.Add(request);
|
Programs.Add(request);
|
||||||
|
|
||||||
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
private readonly ReadOnlyMemory<byte> _cb1Data;
|
private readonly ReadOnlyMemory<byte> _cb1Data;
|
||||||
private readonly GuestGpuAccessorHeader _header;
|
private readonly GuestGpuAccessorHeader _header;
|
||||||
private readonly Dictionary<int, GuestTextureDescriptor> _textureDescriptors;
|
private readonly Dictionary<int, GuestTextureDescriptor> _textureDescriptors;
|
||||||
|
private readonly TransformFeedbackDescriptor[] _tfd;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the cached GPU state accessor for shader translation.
|
/// 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> data,
|
||||||
ReadOnlyMemory<byte> cb1Data,
|
ReadOnlyMemory<byte> cb1Data,
|
||||||
GuestGpuAccessorHeader header,
|
GuestGpuAccessorHeader header,
|
||||||
IReadOnlyDictionary<int, GuestTextureDescriptor> guestTextureDescriptors) : base(context)
|
IReadOnlyDictionary<int, GuestTextureDescriptor> guestTextureDescriptors,
|
||||||
|
TransformFeedbackDescriptor[] tfd) : base(context)
|
||||||
{
|
{
|
||||||
_data = data;
|
_data = data;
|
||||||
_cb1Data = cb1Data;
|
_cb1Data = cb1Data;
|
||||||
|
@ -38,6 +40,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
_textureDescriptors.Add(guestTextureDescriptor.Key, guestTextureDescriptor.Value);
|
_textureDescriptors.Add(guestTextureDescriptor.Key, guestTextureDescriptor.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_tfd = tfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -177,6 +181,35 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return textureDescriptor;
|
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>
|
/// <summary>
|
||||||
/// Queries if host state forces early depth testing.
|
/// Queries if host state forces early depth testing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -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>
|
/// <summary>
|
||||||
/// Queries if host state forces early depth testing.
|
/// Queries if host state forces early depth testing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TessMode TessellationMode { get; }
|
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>
|
/// <summary>
|
||||||
/// Creates a new instance of the GPU accessor state.
|
/// Creates a new instance of the GPU accessor state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -61,6 +66,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
EarlyZForce = earlyZForce;
|
EarlyZForce = earlyZForce;
|
||||||
Topology = topology;
|
Topology = topology;
|
||||||
TessellationMode = tessellationMode;
|
TessellationMode = tessellationMode;
|
||||||
|
TransformFeedbackDescriptors = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the codegen (to be changed when codegen or guest format change).
|
/// Version of the codegen (to be changed when codegen or guest format change).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const ulong ShaderCodeGenVersion = 2972;
|
private const ulong ShaderCodeGenVersion = 3012;
|
||||||
|
|
||||||
// Progress reporting helpers
|
// Progress reporting helpers
|
||||||
private volatile int _shaderCount;
|
private volatile int _shaderCount;
|
||||||
|
@ -227,7 +227,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
binaryCode,
|
binaryCode,
|
||||||
binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
|
binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
|
||||||
entry.Header.GpuAccessorHeader,
|
entry.Header.GpuAccessorHeader,
|
||||||
entry.TextureDescriptors);
|
entry.TextureDescriptors,
|
||||||
|
null);
|
||||||
|
|
||||||
var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags | TranslationFlags.Compute);
|
var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, DefaultFlags | TranslationFlags.Compute);
|
||||||
program = Translator.CreateContext(0, gpuAccessor, options).Translate(out shaderProgramInfo);
|
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.
|
// Compile shader and create program as the shader program binary got invalidated.
|
||||||
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
|
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) =>
|
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
||||||
{
|
{
|
||||||
|
@ -293,13 +294,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader);
|
TransformFeedbackDescriptor[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader);
|
||||||
|
|
||||||
TranslationFlags flags = DefaultFlags;
|
|
||||||
|
|
||||||
if (tfd != null)
|
|
||||||
{
|
|
||||||
flags |= TranslationFlags.Feedback;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslationCounts counts = new TranslationCounts();
|
TranslationCounts counts = new TranslationCounts();
|
||||||
|
|
||||||
HostShaderCacheEntry[] hostShaderEntries = null;
|
HostShaderCacheEntry[] hostShaderEntries = null;
|
||||||
|
@ -343,15 +337,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
binaryCode,
|
binaryCode,
|
||||||
binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
|
binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
|
||||||
entry.Header.GpuAccessorHeader,
|
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);
|
shaderContexts[i + 1] = Translator.CreateContext(0, gpuAccessor, options, counts);
|
||||||
|
|
||||||
if (entry.Header.SizeA != 0)
|
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);
|
shaderContexts[0] = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, options2, counts);
|
||||||
}
|
}
|
||||||
|
@ -431,7 +426,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
hostShaders.Add(hostShader);
|
hostShaders.Add(hostShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd);
|
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
|
||||||
|
|
||||||
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
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);
|
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);
|
cpShader = new ShaderBundle(hostProgram, shader);
|
||||||
|
|
||||||
|
@ -684,25 +679,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(ref state);
|
TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(ref state);
|
||||||
|
|
||||||
TranslationFlags flags = DefaultFlags;
|
gas.TransformFeedbackDescriptors = tfd;
|
||||||
|
|
||||||
if (tfd != null)
|
|
||||||
{
|
|
||||||
flags |= TranslationFlags.Feedback;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslationCounts counts = new TranslationCounts();
|
TranslationCounts counts = new TranslationCounts();
|
||||||
|
|
||||||
if (addresses.VertexA != 0)
|
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[1] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.Vertex, addresses.Vertex);
|
||||||
shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationControl, addresses.TessControl);
|
shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.TessellationControl, addresses.TessControl);
|
||||||
shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
|
shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
|
||||||
shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Geometry, addresses.Geometry);
|
shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.Geometry, addresses.Geometry);
|
||||||
shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Fragment, addresses.Fragment);
|
shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, DefaultFlags, ShaderStage.Fragment, addresses.Fragment);
|
||||||
|
|
||||||
bool isShaderCacheEnabled = _cacheManager != null;
|
bool isShaderCacheEnabled = _cacheManager != null;
|
||||||
bool isShaderCacheReadOnly = false;
|
bool isShaderCacheReadOnly = false;
|
||||||
|
@ -765,7 +755,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
hostShaders.Add(hostShader);
|
hostShaders.Add(hostShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd);
|
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
|
||||||
|
|
||||||
gpShaders = new ShaderBundle(hostProgram, shaders);
|
gpShaders = new ShaderBundle(hostProgram, shaders);
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.GAL
|
namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
public struct TransformFeedbackDescriptor
|
struct TransformFeedbackDescriptor
|
||||||
{
|
{
|
||||||
public int BufferIndex { get; }
|
public int BufferIndex { get; }
|
||||||
public int Stride { get; }
|
public int Stride { get; }
|
|
@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
|
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
|
||||||
private IShader[] _shaders;
|
private IShader[] _shaders;
|
||||||
|
|
||||||
public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
public Program(IShader[] shaders)
|
||||||
{
|
{
|
||||||
Handle = GL.CreateProgram();
|
Handle = GL.CreateProgram();
|
||||||
|
|
||||||
|
@ -42,54 +42,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
GL.AttachShader(Handle, shaderHandle);
|
GL.AttachShader(Handle, shaderHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transformFeedbackDescriptors != null)
|
|
||||||
{
|
|
||||||
List<string> varyings = new List<string>();
|
|
||||||
|
|
||||||
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);
|
GL.LinkProgram(Handle);
|
||||||
|
|
||||||
_shaders = shaders;
|
_shaders = shaders;
|
||||||
|
|
|
@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return Buffer.Create(size);
|
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)
|
public ISampler CreateSampler(SamplerCreateInfo info)
|
||||||
|
|
|
@ -103,6 +103,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
return _info.Functions[id];
|
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()
|
private void UpdateIndentation()
|
||||||
{
|
{
|
||||||
_indentation = GetIndentation(_level);
|
_indentation = GetIndentation(_level);
|
||||||
|
|
|
@ -191,6 +191,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
context.AppendLine();
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -514,7 +528,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
string pass = (context.Config.PassthroughAttributes & (1 << attr)) != 0 ? "passthrough, " : string.Empty;
|
string pass = (context.Config.PassthroughAttributes & (1 << attr)) != 0 ? "passthrough, " : string.Empty;
|
||||||
string name = $"{DefaultNames.IAttributePrefix}{attr}";
|
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++)
|
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 suffix = OperandManager.IsArrayAttribute(context.Config.Stage, isOutAttr: true) ? "[]" : string.Empty;
|
||||||
string name = $"{DefaultNames.OAttributePrefix}{attr}{suffix}";
|
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++)
|
for (int c = 0; c < 4; c++)
|
||||||
{
|
{
|
||||||
char swzMask = "xyzw"[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
|
else
|
||||||
|
|
|
@ -194,7 +194,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
return name + $"[{(value >> 4)}]." + swzMask;
|
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}";
|
string name = $"{prefix}{(value >> 4)}_{swzMask}";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -131,6 +131,21 @@ namespace Ryujinx.Graphics.Shader
|
||||||
return TextureFormat.R8G8B8A8Unorm;
|
return TextureFormat.R8G8B8A8Unorm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QueryTransformFeedbackEnabled()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> QueryTransformFeedbackVaryingLocations(int bufferIndex)
|
||||||
|
{
|
||||||
|
return ReadOnlySpan<byte>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QueryTransformFeedbackStride(int bufferIndex)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool QueryEarlyZForce()
|
bool QueryEarlyZForce()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -64,6 +64,24 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
context.LeaveFunction();
|
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;
|
return context.Info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,35 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
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
|
class StructuredProgramInfo
|
||||||
{
|
{
|
||||||
public List<StructuredFunction> Functions { get; }
|
public List<StructuredFunction> Functions { get; }
|
||||||
|
|
||||||
public HelperFunctionsMask HelperFunctionsMask { get; set; }
|
public HelperFunctionsMask HelperFunctionsMask { get; set; }
|
||||||
|
|
||||||
|
public TransformFeedbackOutput[] TransformFeedbackOutputs { get; }
|
||||||
|
|
||||||
public StructuredProgramInfo()
|
public StructuredProgramInfo()
|
||||||
{
|
{
|
||||||
Functions = new List<StructuredFunction>();
|
Functions = new List<StructuredFunction>();
|
||||||
|
|
||||||
|
TransformFeedbackOutputs = new TransformFeedbackOutput[0x80];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,6 +33,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
public TranslationOptions Options { get; }
|
public TranslationOptions Options { get; }
|
||||||
|
|
||||||
|
public bool TransformFeedbackEnabled { get; }
|
||||||
|
|
||||||
public int Size { get; private set; }
|
public int Size { get; private set; }
|
||||||
|
|
||||||
public byte ClipDistancesWritten { get; private set; }
|
public byte ClipDistancesWritten { get; private set; }
|
||||||
|
@ -128,6 +130,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
OmapTargets = header.OmapTargets;
|
OmapTargets = header.OmapTargets;
|
||||||
OmapSampleMask = header.OmapSampleMask;
|
OmapSampleMask = header.OmapSampleMask;
|
||||||
OmapDepth = header.OmapDepth;
|
OmapDepth = header.OmapDepth;
|
||||||
|
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetDepthRegister()
|
public int GetDepthRegister()
|
||||||
|
|
|
@ -9,7 +9,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
VertexA = 1 << 0,
|
VertexA = 1 << 0,
|
||||||
Compute = 1 << 1,
|
Compute = 1 << 1,
|
||||||
Feedback = 1 << 2,
|
DebugMode = 1 << 2
|
||||||
DebugMode = 1 << 3
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in a new issue