Initial transform feedback support (#1370)
* Initial transform feedback support * Some nits and fixes * Update ReportCounterType and Write method * Can't change shader or TFB bindings while TFB is active * Fix geometry shader input names with new naming
This commit is contained in:
@ -331,6 +331,31 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
return PrimitiveType.Points;
|
||||
}
|
||||
|
||||
public static TransformFeedbackPrimitiveType ConvertToTfType(this PrimitiveTopology topology)
|
||||
{
|
||||
switch (topology)
|
||||
{
|
||||
case PrimitiveTopology.Points:
|
||||
return TransformFeedbackPrimitiveType.Points;
|
||||
case PrimitiveTopology.Lines:
|
||||
case PrimitiveTopology.LineLoop:
|
||||
case PrimitiveTopology.LineStrip:
|
||||
case PrimitiveTopology.LinesAdjacency:
|
||||
case PrimitiveTopology.LineStripAdjacency:
|
||||
return TransformFeedbackPrimitiveType.Lines;
|
||||
case PrimitiveTopology.Triangles:
|
||||
case PrimitiveTopology.TriangleStrip:
|
||||
case PrimitiveTopology.TriangleFan:
|
||||
case PrimitiveTopology.TrianglesAdjacency:
|
||||
case PrimitiveTopology.TriangleStripAdjacency:
|
||||
return TransformFeedbackPrimitiveType.Triangles;
|
||||
}
|
||||
|
||||
Logger.PrintDebug(LogClass.Gpu, $"Invalid {nameof(PrimitiveTopology)} enum value: {topology}.");
|
||||
|
||||
return TransformFeedbackPrimitiveType.Points;
|
||||
}
|
||||
|
||||
public static OpenTK.Graphics.OpenGL.StencilOp Convert(this GAL.StencilOp op)
|
||||
{
|
||||
switch (op)
|
||||
|
@ -45,6 +45,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
private bool _scissor0Enable = false;
|
||||
|
||||
private bool _tfEnabled;
|
||||
|
||||
ColorF _blendConstant = new ColorF(0, 0, 0, 0);
|
||||
|
||||
internal Pipeline()
|
||||
@ -76,6 +78,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.AllBarrierBits);
|
||||
}
|
||||
|
||||
public void BeginTransformFeedback(PrimitiveTopology topology)
|
||||
{
|
||||
GL.BeginTransformFeedback(topology.ConvertToTfType());
|
||||
_tfEnabled = true;
|
||||
}
|
||||
|
||||
public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
|
||||
{
|
||||
GL.ColorMask(
|
||||
@ -512,6 +520,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
public void EndTransformFeedback()
|
||||
{
|
||||
GL.EndTransformFeedback();
|
||||
_tfEnabled = false;
|
||||
}
|
||||
|
||||
public void SetBlendState(int index, BlendDescriptor blend)
|
||||
{
|
||||
if (!blend.Enable)
|
||||
@ -713,7 +727,17 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
public void SetProgram(IProgram program)
|
||||
{
|
||||
_program = (Program)program;
|
||||
_program.Bind();
|
||||
|
||||
if (_tfEnabled)
|
||||
{
|
||||
GL.PauseTransformFeedback();
|
||||
_program.Bind();
|
||||
GL.ResumeTransformFeedback();
|
||||
}
|
||||
else
|
||||
{
|
||||
_program.Bind();
|
||||
}
|
||||
|
||||
SetRenderTargetScale(_fpRenderScale[0]);
|
||||
}
|
||||
@ -904,6 +928,22 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTransformFeedbackBuffer(int index, BufferRange buffer)
|
||||
{
|
||||
const BufferRangeTarget target = BufferRangeTarget.TransformFeedbackBuffer;
|
||||
|
||||
if (_tfEnabled)
|
||||
{
|
||||
GL.PauseTransformFeedback();
|
||||
GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
GL.ResumeTransformFeedback();
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer)
|
||||
{
|
||||
SetBuffer(index, stage, buffer, isStorage: false);
|
||||
@ -1132,7 +1172,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
// If the event has been flushed, then just use the values on the CPU.
|
||||
// The query object may already be repurposed for another draw (eg. begin + end).
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compare == 0 && evt.Type == QueryTarget.SamplesPassed && evt.ClearCounter)
|
||||
@ -1145,7 +1185,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
// The GPU will flush the queries to CPU and evaluate the condition there instead.
|
||||
|
||||
GL.Flush(); // The thread will be stalled manually flushing the counter, so flush GL commands now.
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
|
||||
|
@ -2,6 +2,10 @@ using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
@ -31,7 +35,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
private int[] _textureUnits;
|
||||
private int[] _imageUnits;
|
||||
|
||||
public Program(IShader[] shaders)
|
||||
public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
||||
{
|
||||
_ubBindingPoints = new int[UbsPerStage * ShaderStages];
|
||||
_sbBindingPoints = new int[SbsPerStage * ShaderStages];
|
||||
@ -67,6 +71,54 @@ 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);
|
||||
|
||||
for (int index = 0; index < shaders.Length; index++)
|
||||
|
@ -44,9 +44,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
return Buffer.Create(size);
|
||||
}
|
||||
|
||||
public IProgram CreateProgram(IShader[] shaders)
|
||||
public IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
||||
{
|
||||
return new Program(shaders);
|
||||
return new Program(shaders, transformFeedbackDescriptors);
|
||||
}
|
||||
|
||||
public ISampler CreateSampler(SamplerCreateInfo info)
|
||||
|
Reference in New Issue
Block a user