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);
|
||||
|
||||
IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors);
|
||||
IProgram CreateProgram(IShader[] shaders);
|
||||
|
||||
ISampler CreateSampler(SamplerCreateInfo info);
|
||||
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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; }
|
|
@ -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<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);
|
||||
|
||||
_shaders = shaders;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}";
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
bool QueryTransformFeedbackEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> QueryTransformFeedbackVaryingLocations(int bufferIndex)
|
||||
{
|
||||
return ReadOnlySpan<byte>.Empty;
|
||||
}
|
||||
|
||||
int QueryTransformFeedbackStride(int bufferIndex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool QueryEarlyZForce()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<StructuredFunction> Functions { get; }
|
||||
|
||||
public HelperFunctionsMask HelperFunctionsMask { get; set; }
|
||||
|
||||
public TransformFeedbackOutput[] TransformFeedbackOutputs { get; }
|
||||
|
||||
public StructuredProgramInfo()
|
||||
{
|
||||
Functions = new List<StructuredFunction>();
|
||||
|
||||
TransformFeedbackOutputs = new TransformFeedbackOutput[0x80];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
VertexA = 1 << 0,
|
||||
Compute = 1 << 1,
|
||||
Feedback = 1 << 2,
|
||||
DebugMode = 1 << 3
|
||||
DebugMode = 1 << 2
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue