aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-08-11 20:21:56 -0300
committerGitHub <noreply@github.com>2022-08-11 20:21:56 -0300
commite8f1ca84277240c4d6215eb9cd85713aab73e2f7 (patch)
tree9cc785a705678a3e7e00232a2bd3b00279cdac04
parentad47bd2d4ef72e4489f037056ead0a5d021694cc (diff)
OpenGL: Limit vertex buffer range for non-indexed draws (#3542)1.1.213
* Limit vertex buffer range for non-indexed draws * Fix typo
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs21
-rw-r--r--Ryujinx.Graphics.OpenGL/VertexArray.cs109
-rw-r--r--Ryujinx.Graphics.OpenGL/VertexBuffer.cs19
3 files changed, 125 insertions, 24 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index fc28c86e..d7cd6fbd 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -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();
}
diff --git a/Ryujinx.Graphics.OpenGL/VertexArray.cs b/Ryujinx.Graphics.OpenGL/VertexArray.cs
index bdf14481..d466199d 100644
--- a/Ryujinx.Graphics.OpenGL/VertexArray.cs
+++ b/Ryujinx.Graphics.OpenGL/VertexArray.cs
@@ -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++)
diff --git a/Ryujinx.Graphics.OpenGL/VertexBuffer.cs b/Ryujinx.Graphics.OpenGL/VertexBuffer.cs
deleted file mode 100644
index 19a58053..00000000
--- a/Ryujinx.Graphics.OpenGL/VertexBuffer.cs
+++ /dev/null
@@ -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;
- }
- }
-}