forked from Mirror/Ryujinx
OpenGL: Limit vertex buffer range for non-indexed draws (#3542)
* Limit vertex buffer range for non-indexed draws * Fix typo
This commit is contained in:
parent
ad47bd2d4e
commit
e8f1ca8427
3 changed files with 125 additions and 24 deletions
|
@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return;
|
||||
}
|
||||
|
||||
PreDraw();
|
||||
PreDraw(vertexCount);
|
||||
|
||||
if (_primitiveType == PrimitiveType.Quads && !HwCapabilities.SupportsQuads)
|
||||
{
|
||||
|
@ -354,7 +354,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return;
|
||||
}
|
||||
|
||||
PreDraw();
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
int indexElemSize = 1;
|
||||
|
||||
|
@ -686,7 +686,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return;
|
||||
}
|
||||
|
||||
PreDraw();
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||
|
@ -709,7 +709,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return;
|
||||
}
|
||||
|
||||
PreDraw();
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
_vertexArray.SetRangeOfIndexBuffer();
|
||||
|
||||
|
@ -1515,11 +1515,22 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
_supportBuffer.Commit();
|
||||
}
|
||||
|
||||
private void PreDraw(int vertexCount)
|
||||
{
|
||||
_vertexArray.PreDraw(vertexCount);
|
||||
PreDraw();
|
||||
}
|
||||
|
||||
private void PreDrawVbUnbounded()
|
||||
{
|
||||
_vertexArray.PreDrawVbUnbounded();
|
||||
PreDraw();
|
||||
}
|
||||
|
||||
private void PreDraw()
|
||||
{
|
||||
DrawCount++;
|
||||
|
||||
_vertexArray.Validate();
|
||||
_unit0Texture?.Bind(0);
|
||||
_supportBuffer.Commit();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
|
@ -16,12 +17,16 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
private int _vertexAttribsCount;
|
||||
private int _vertexBuffersCount;
|
||||
private int _minVertexCount;
|
||||
|
||||
private uint _vertexAttribsInUse;
|
||||
private uint _vertexBuffersInUse;
|
||||
private uint _vertexBuffersLimited;
|
||||
|
||||
private BufferRange _indexBuffer;
|
||||
private BufferHandle _tempIndexBuffer;
|
||||
private BufferHandle _tempVertexBuffer;
|
||||
private int _tempVertexBufferSize;
|
||||
|
||||
public VertexArray()
|
||||
{
|
||||
|
@ -40,6 +45,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
|
||||
{
|
||||
int minVertexCount = int.MaxValue;
|
||||
|
||||
int bindingIndex;
|
||||
for (bindingIndex = 0; bindingIndex < vertexBuffers.Length; bindingIndex++)
|
||||
{
|
||||
|
@ -47,6 +54,12 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
if (vb.Buffer.Handle != BufferHandle.Null)
|
||||
{
|
||||
int vertexCount = vb.Stride <= 0 ? 0 : vb.Buffer.Size / vb.Stride;
|
||||
if (minVertexCount > vertexCount)
|
||||
{
|
||||
minVertexCount = vertexCount;
|
||||
}
|
||||
|
||||
GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride);
|
||||
GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
|
||||
_vertexBuffersInUse |= 1u << bindingIndex;
|
||||
|
@ -64,6 +77,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
|
||||
_vertexBuffersCount = bindingIndex;
|
||||
_minVertexCount = minVertexCount;
|
||||
_needsAttribsUpdate = true;
|
||||
}
|
||||
|
||||
|
@ -143,6 +157,101 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.Handle.ToInt32());
|
||||
}
|
||||
|
||||
public void PreDraw(int vertexCount)
|
||||
{
|
||||
LimitVertexBuffers(vertexCount);
|
||||
Validate();
|
||||
}
|
||||
|
||||
public void PreDrawVbUnbounded()
|
||||
{
|
||||
UnlimitVertexBuffers();
|
||||
Validate();
|
||||
}
|
||||
|
||||
public void LimitVertexBuffers(int vertexCount)
|
||||
{
|
||||
// Is it possible for the draw to fetch outside the bounds of any vertex buffer currently bound?
|
||||
|
||||
if (vertexCount <= _minVertexCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the draw can fetch out of bounds, let's ensure that it will only fetch zeros rather than memory garbage.
|
||||
|
||||
int currentTempVbOffset = 0;
|
||||
uint buffersInUse = _vertexBuffersInUse;
|
||||
|
||||
while (buffersInUse != 0)
|
||||
{
|
||||
int vbIndex = BitOperations.TrailingZeroCount(buffersInUse);
|
||||
|
||||
ref var vb = ref _vertexBuffers[vbIndex];
|
||||
|
||||
int requiredSize = vertexCount * vb.Stride;
|
||||
|
||||
if (vb.Buffer.Size < requiredSize)
|
||||
{
|
||||
BufferHandle tempVertexBuffer = EnsureTempVertexBufferSize(currentTempVbOffset + requiredSize);
|
||||
|
||||
Buffer.Copy(vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size);
|
||||
Buffer.Clear(tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, requiredSize - vb.Buffer.Size, 0);
|
||||
|
||||
GL.BindVertexBuffer(vbIndex, tempVertexBuffer.ToInt32(), (IntPtr)currentTempVbOffset, vb.Stride);
|
||||
|
||||
currentTempVbOffset += requiredSize;
|
||||
_vertexBuffersLimited |= 1u << vbIndex;
|
||||
}
|
||||
|
||||
buffersInUse &= ~(1u << vbIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private BufferHandle EnsureTempVertexBufferSize(int size)
|
||||
{
|
||||
BufferHandle tempVertexBuffer = _tempVertexBuffer;
|
||||
|
||||
if (_tempVertexBufferSize < size)
|
||||
{
|
||||
_tempVertexBufferSize = size;
|
||||
|
||||
if (tempVertexBuffer == BufferHandle.Null)
|
||||
{
|
||||
tempVertexBuffer = Buffer.Create(size);
|
||||
_tempVertexBuffer = tempVertexBuffer;
|
||||
return tempVertexBuffer;
|
||||
}
|
||||
|
||||
Buffer.Resize(_tempVertexBuffer, size);
|
||||
}
|
||||
|
||||
return tempVertexBuffer;
|
||||
}
|
||||
|
||||
public void UnlimitVertexBuffers()
|
||||
{
|
||||
uint buffersLimited = _vertexBuffersLimited;
|
||||
|
||||
if (buffersLimited == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (buffersLimited != 0)
|
||||
{
|
||||
int vbIndex = BitOperations.TrailingZeroCount(buffersLimited);
|
||||
|
||||
ref var vb = ref _vertexBuffers[vbIndex];
|
||||
|
||||
GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride);
|
||||
|
||||
buffersLimited &= ~(1u << vbIndex);
|
||||
}
|
||||
|
||||
_vertexBuffersLimited = 0;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
for (int attribIndex = 0; attribIndex < _vertexAttribsCount; attribIndex++)
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
struct VertexBuffer
|
||||
{
|
||||
public BufferRange Range { get; }
|
||||
|
||||
public int Divisor { get; }
|
||||
public int Stride { get; }
|
||||
|
||||
public VertexBuffer(BufferRange range, int divisor, int stride)
|
||||
{
|
||||
Range = range;
|
||||
Divisor = divisor;
|
||||
Stride = stride;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue