Fix transform feedback errors caused by host pause/resume and multiple uses (#1634)
* Fix transform feedback errors caused by host pause/resume * Fix TFB being used as something else issue with copies * This is supposed to be StreamCopy
This commit is contained in:
parent
cf0f0fc4e7
commit
812e32f775
7 changed files with 92 additions and 30 deletions
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);
|
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);
|
||||||
|
|
||||||
public BufferRange Empty => _empty;
|
public static BufferRange Empty => _empty;
|
||||||
|
|
||||||
public BufferHandle Handle { get; }
|
public BufferHandle Handle { get; }
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
void SetTexture(int index, ShaderStage stage, ITexture texture);
|
void SetTexture(int index, ShaderStage stage, ITexture texture);
|
||||||
|
|
||||||
void SetTransformFeedbackBuffer(int index, BufferRange buffer);
|
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||||
void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer);
|
void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer);
|
||||||
|
|
||||||
void SetUserClipDistance(int index, bool enableClip);
|
void SetUserClipDistance(int index, bool enableClip);
|
||||||
|
|
|
@ -587,21 +587,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
_transformFeedbackBuffersDirty = false;
|
_transformFeedbackBuffersDirty = false;
|
||||||
|
|
||||||
|
Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||||
{
|
{
|
||||||
BufferBounds tfb = _transformFeedbackBuffers[index];
|
BufferBounds tfb = _transformFeedbackBuffers[index];
|
||||||
|
|
||||||
if (tfb.Address == 0)
|
if (tfb.Address == 0)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetTransformFeedbackBuffer(index, new BufferRange(BufferHandle.Null, 0, 0));
|
tfbs[index] = BufferRange.Empty;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferRange buffer = GetBufferRange(tfb.Address, tfb.Size);
|
tfbs[index] = GetBufferRange(tfb.Address, tfb.Size);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetTransformFeedbackBuffer(index, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
static class Buffer
|
static class Buffer
|
||||||
{
|
{
|
||||||
|
public static BufferHandle Create()
|
||||||
|
{
|
||||||
|
return Handle.FromInt32<BufferHandle>(GL.GenBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
public static BufferHandle Create(int size)
|
public static BufferHandle Create(int size)
|
||||||
{
|
{
|
||||||
int handle = GL.GenBuffer();
|
int handle = GL.GenBuffer();
|
||||||
|
@ -40,6 +45,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Resize(BufferHandle handle, int size)
|
||||||
|
{
|
||||||
|
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
|
||||||
|
GL.BufferData(BufferTarget.CopyWriteBuffer, size, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
public static void SetData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer.ToInt32());
|
GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer.ToInt32());
|
||||||
|
|
|
@ -6,5 +6,6 @@
|
||||||
public const int MaxViewports = 16;
|
public const int MaxViewports = 16;
|
||||||
public const int MaxVertexAttribs = 16;
|
public const int MaxVertexAttribs = 16;
|
||||||
public const int MaxVertexBuffers = 16;
|
public const int MaxVertexBuffers = 16;
|
||||||
|
public const int MaxTransformFeedbackBuffers = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ using Ryujinx.Graphics.OpenGL.Image;
|
||||||
using Ryujinx.Graphics.OpenGL.Queries;
|
using Ryujinx.Graphics.OpenGL.Queries;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.OpenGL
|
namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
|
@ -49,6 +48,10 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
private bool _scissor0Enable = false;
|
private bool _scissor0Enable = false;
|
||||||
|
|
||||||
private bool _tfEnabled;
|
private bool _tfEnabled;
|
||||||
|
private TransformFeedbackPrimitiveType _tfTopology;
|
||||||
|
|
||||||
|
private readonly BufferHandle[] _tfbs;
|
||||||
|
private readonly BufferRange[] _tfbTargets;
|
||||||
|
|
||||||
private ColorF _blendConstant;
|
private ColorF _blendConstant;
|
||||||
|
|
||||||
|
@ -74,6 +77,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
_cpRenderScale[index] = 1f;
|
_cpRenderScale[index] = 1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
|
||||||
|
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Barrier()
|
public void Barrier()
|
||||||
|
@ -83,7 +89,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public void BeginTransformFeedback(PrimitiveTopology topology)
|
public void BeginTransformFeedback(PrimitiveTopology topology)
|
||||||
{
|
{
|
||||||
GL.BeginTransformFeedback(topology.ConvertToTfType());
|
GL.BeginTransformFeedback(_tfTopology = topology.ConvertToTfType());
|
||||||
_tfEnabled = true;
|
_tfEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +181,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareForDraw();
|
PreDraw();
|
||||||
|
|
||||||
if (_primitiveType == PrimitiveType.Quads)
|
if (_primitiveType == PrimitiveType.Quads)
|
||||||
{
|
{
|
||||||
|
@ -190,7 +196,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
|
DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
_framebuffer.SignalModified();
|
PostDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawQuadsImpl(
|
private void DrawQuadsImpl(
|
||||||
|
@ -293,7 +299,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareForDraw();
|
PreDraw();
|
||||||
|
|
||||||
int indexElemSize = 1;
|
int indexElemSize = 1;
|
||||||
|
|
||||||
|
@ -335,7 +341,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
firstInstance);
|
firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
_framebuffer.SignalModified();
|
PostDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawQuadsIndexedImpl(
|
private void DrawQuadsIndexedImpl(
|
||||||
|
@ -790,9 +796,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
if (_tfEnabled)
|
if (_tfEnabled)
|
||||||
{
|
{
|
||||||
GL.PauseTransformFeedback();
|
GL.EndTransformFeedback();
|
||||||
_program.Bind();
|
_program.Bind();
|
||||||
GL.ResumeTransformFeedback();
|
GL.BeginTransformFeedback(_tfTopology);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -993,19 +999,39 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTransformFeedbackBuffer(int index, BufferRange buffer)
|
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||||
{
|
{
|
||||||
const BufferRangeTarget target = BufferRangeTarget.TransformFeedbackBuffer;
|
if (_tfEnabled)
|
||||||
|
{
|
||||||
|
GL.EndTransformFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = Math.Min(buffers.Length, Constants.MaxTransformFeedbackBuffers);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
BufferRange buffer = buffers[i];
|
||||||
|
_tfbTargets[i] = buffer;
|
||||||
|
|
||||||
|
if (buffer.Handle == BufferHandle.Null)
|
||||||
|
{
|
||||||
|
GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tfbs[i] == BufferHandle.Null)
|
||||||
|
{
|
||||||
|
_tfbs[i] = Buffer.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer.Resize(_tfbs[i], buffer.Size);
|
||||||
|
Buffer.Copy(buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size);
|
||||||
|
GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i].ToInt32());
|
||||||
|
}
|
||||||
|
|
||||||
if (_tfEnabled)
|
if (_tfEnabled)
|
||||||
{
|
{
|
||||||
GL.PauseTransformFeedback();
|
GL.BeginTransformFeedback(_tfTopology);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,7 +1130,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
? BufferRangeTarget.ShaderStorageBuffer
|
? BufferRangeTarget.ShaderStorageBuffer
|
||||||
: BufferRangeTarget.UniformBuffer;
|
: BufferRangeTarget.UniformBuffer;
|
||||||
|
|
||||||
if (buffer.Handle == null)
|
if (buffer.Handle == BufferHandle.Null)
|
||||||
{
|
{
|
||||||
GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
|
GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
|
||||||
return;
|
return;
|
||||||
|
@ -1237,7 +1263,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrepareForDraw()
|
private void PreDraw()
|
||||||
{
|
{
|
||||||
_vertexArray.Validate();
|
_vertexArray.Validate();
|
||||||
|
|
||||||
|
@ -1247,6 +1273,22 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PostDraw()
|
||||||
|
{
|
||||||
|
_framebuffer?.SignalModified();
|
||||||
|
|
||||||
|
if (_tfEnabled)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
|
||||||
|
{
|
||||||
|
if (_tfbTargets[i].Handle != BufferHandle.Null)
|
||||||
|
{
|
||||||
|
Buffer.Copy(_tfbs[i], _tfbTargets[i].Handle, 0, _tfbTargets[i].Offset, _tfbTargets[i].Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void RestoreComponentMask(int index)
|
private void RestoreComponentMask(int index)
|
||||||
{
|
{
|
||||||
GL.ColorMask(
|
GL.ColorMask(
|
||||||
|
@ -1319,6 +1361,15 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
|
||||||
|
{
|
||||||
|
if (_tfbs[i] != BufferHandle.Null)
|
||||||
|
{
|
||||||
|
Buffer.Delete(_tfbs[i]);
|
||||||
|
_tfbs[i] = BufferHandle.Null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_framebuffer?.Dispose();
|
_framebuffer?.Dispose();
|
||||||
_vertexArray?.Dispose();
|
_vertexArray?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,8 +131,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
CheckProgramLink();
|
CheckProgramLink();
|
||||||
|
|
||||||
Bind();
|
|
||||||
|
|
||||||
int ubBindingPoint = 0;
|
int ubBindingPoint = 0;
|
||||||
int sbBindingPoint = 0;
|
int sbBindingPoint = 0;
|
||||||
int textureUnit = 0;
|
int textureUnit = 0;
|
||||||
|
@ -189,7 +187,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.Uniform1(location, textureUnit);
|
GL.ProgramUniform1(Handle, location, textureUnit);
|
||||||
|
|
||||||
int uIndex = (int)shader.Stage << TexStageShift | samplerIndex++;
|
int uIndex = (int)shader.Stage << TexStageShift | samplerIndex++;
|
||||||
|
|
||||||
|
@ -209,7 +207,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.Uniform1(location, imageUnit);
|
GL.ProgramUniform1(Handle, location, imageUnit);
|
||||||
|
|
||||||
int uIndex = (int)shader.Stage << ImgStageShift | imageIndex++;
|
int uIndex = (int)shader.Stage << ImgStageShift | imageIndex++;
|
||||||
|
|
||||||
|
|
Reference in a new issue