aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs214
1 files changed, 122 insertions, 92 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
index 5d41dafd..88f2e8fe 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
@@ -1,9 +1,6 @@
-using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.State;
-using System;
-using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Engine
{
@@ -11,9 +8,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
private bool _drawIndexed;
- private int _firstIndex;
- private int _indexCount;
-
private bool _instancedDrawPending;
private bool _instancedIndexed;
@@ -26,23 +20,35 @@ namespace Ryujinx.Graphics.Gpu.Engine
private int _instanceIndex;
- private BufferHandle _inlineIndexBuffer = BufferHandle.Null;
- private int _inlineIndexBufferSize;
- private int _inlineIndexCount;
+ private IbStreamer _ibStreamer;
/// <summary>
- /// Primitive type of the current draw.
+ /// Primitive topology of the current draw.
/// </summary>
- public PrimitiveType PrimitiveType { get; private set; }
+ public PrimitiveTopology Topology { get; private set; }
/// <summary>
- /// Finishes draw call.
+ /// Finishes the draw call.
/// This draws geometry on the bound buffers based on the current GPU state.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
private void DrawEnd(GpuState state, int argument)
{
+ var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
+
+ DrawEnd(state, indexBuffer.First, indexBuffer.Count);
+ }
+
+ /// <summary>
+ /// Finishes the draw call.
+ /// This draws geometry on the bound buffers based on the current GPU state.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
+ /// <param name="indexCount">Number of index buffer elements used on the draw</param>
+ private void DrawEnd(GpuState state, int firstIndex, int indexCount)
+ {
ConditionalRenderEnabled renderEnable = GetRenderEnable(state);
if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
@@ -62,7 +68,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
return;
}
- UpdateState(state);
+ UpdateState(state, firstIndex, indexCount);
bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
@@ -72,11 +78,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
_instancedIndexed = _drawIndexed;
- _instancedFirstIndex = _firstIndex;
- _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
+ _instancedFirstIndex = firstIndex;
+ _instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
_instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
- _instancedIndexCount = _indexCount;
+ _instancedIndexCount = indexCount;
var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
@@ -95,31 +101,31 @@ namespace Ryujinx.Graphics.Gpu.Engine
int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
- if (_inlineIndexCount != 0)
+ int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount();
+
+ if (inlineIndexCount != 0)
{
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
- BufferRange br = new BufferRange(_inlineIndexBuffer, 0, _inlineIndexCount * 4);
+ BufferRange br = new BufferRange(_ibStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
_context.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt);
_context.Renderer.Pipeline.DrawIndexed(
- _inlineIndexCount,
+ inlineIndexCount,
1,
- _firstIndex,
+ firstIndex,
firstVertex,
firstInstance);
-
- _inlineIndexCount = 0;
}
else if (_drawIndexed)
{
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
_context.Renderer.Pipeline.DrawIndexed(
- _indexCount,
+ indexCount,
1,
- _firstIndex,
+ firstIndex,
firstVertex,
firstInstance);
}
@@ -150,22 +156,46 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// <param name="argument">Method call argument</param>
private void DrawBegin(GpuState state, int argument)
{
- if ((argument & (1 << 26)) != 0)
+ bool incrementInstance = (argument & (1 << 26)) != 0;
+ bool resetInstance = (argument & (1 << 27)) == 0;
+
+ PrimitiveType type = (PrimitiveType)(argument & 0xffff);
+
+ PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
+
+ if (typeOverride != PrimitiveTypeOverride.Invalid)
+ {
+ DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
+ }
+ else
+ {
+ DrawBegin(incrementInstance, resetInstance, type.Convert());
+ }
+ }
+
+ /// <summary>
+ /// Starts draw.
+ /// This sets primitive type and instanced draw parameters.
+ /// </summary>
+ /// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
+ /// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
+ /// <param name="topology">Primitive topology</param>
+ private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
+ {
+ if (incrementInstance)
{
_instanceIndex++;
}
- else if ((argument & (1 << 27)) == 0)
+ else if (resetInstance)
{
PerformDeferredDraws();
_instanceIndex = 0;
}
- PrimitiveType type = (PrimitiveType)(argument & 0xffff);
-
- _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert());
+ _context.Renderer.Pipeline.SetPrimitiveTopology(topology);
- PrimitiveType = type;
+ Topology = topology;
}
/// <summary>
@@ -180,100 +210,100 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
/// <summary>
- /// Pushes four 8-bit index buffer elements.
+ /// Performs a indexed draw with a low number of index buffer elements.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
- private void VbElementU8(GpuState state, int argument)
+ private void DrawIndexedSmall(GpuState state, int argument)
{
- byte i0 = (byte)argument;
- byte i1 = (byte)(argument >> 8);
- byte i2 = (byte)(argument >> 16);
- byte i3 = (byte)(argument >> 24);
-
- Span<uint> data = stackalloc uint[4];
-
- data[0] = i0;
- data[1] = i1;
- data[2] = i2;
- data[3] = i3;
+ DrawIndexedSmall(state, argument, false);
+ }
- int offset = _inlineIndexCount * 4;
+ /// <summary>
+ /// Performs a indexed draw with a low number of index buffer elements.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="argument">Method call argument</param>
+ private void DrawIndexedSmall2(GpuState state, int argument)
+ {
+ DrawIndexedSmall(state, argument);
+ }
- _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
+ /// <summary>
+ /// Performs a indexed draw with a low number of index buffer elements,
+ /// while also pre-incrementing the current instance value.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="argument">Method call argument</param>
+ private void DrawIndexedSmallIncInstance(GpuState state, int argument)
+ {
+ DrawIndexedSmall(state, argument, true);
+ }
- _inlineIndexCount += 4;
+ /// <summary>
+ /// Performs a indexed draw with a low number of index buffer elements,
+ /// while also pre-incrementing the current instance value.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="argument">Method call argument</param>
+ private void DrawIndexedSmallIncInstance2(GpuState state, int argument)
+ {
+ DrawIndexedSmallIncInstance(state, argument);
}
/// <summary>
- /// Pushes two 16-bit index buffer elements.
+ /// Performs a indexed draw with a low number of index buffer elements,
+ /// while optionally also pre-incrementing the current instance value.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
- private void VbElementU16(GpuState state, int argument)
+ /// <param name="instanced">True to increment the current instance value, false otherwise</param>
+ private void DrawIndexedSmall(GpuState state, int argument, bool instanced)
{
- ushort i0 = (ushort)argument;
- ushort i1 = (ushort)(argument >> 16);
+ PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
+
+ DrawBegin(instanced, !instanced, typeOverride.Convert());
- Span<uint> data = stackalloc uint[2];
+ int firstIndex = argument & 0xffff;
+ int indexCount = (argument >> 16) & 0xfff;
- data[0] = i0;
- data[1] = i1;
+ bool oldDrawIndexed = _drawIndexed;
- int offset = _inlineIndexCount * 4;
+ _drawIndexed = true;
- _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
+ DrawEnd(state, firstIndex, indexCount);
- _inlineIndexCount += 2;
+ _drawIndexed = oldDrawIndexed;
}
/// <summary>
- /// Pushes one 32-bit index buffer element.
+ /// Pushes four 8-bit index buffer elements.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
- private void VbElementU32(GpuState state, int argument)
+ private void VbElementU8(GpuState state, int argument)
{
- uint i0 = (uint)argument;
-
- Span<uint> data = stackalloc uint[1];
-
- data[0] = i0;
-
- int offset = _inlineIndexCount++ * 4;
-
- _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
+ _ibStreamer.VbElementU8(_context.Renderer, argument);
}
/// <summary>
- /// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>.
+ /// Pushes two 16-bit index buffer elements.
/// </summary>
- /// <param name="offset">Offset where the data will be written</param>
- /// <returns>Buffer handle</returns>
- private BufferHandle GetInlineIndexBuffer(int offset)
+ /// <param name="state">Current GPU state</param>
+ /// <param name="argument">Method call argument</param>
+ private void VbElementU16(GpuState state, int argument)
{
- // Calculate a reasonable size for the buffer that can fit all the data,
- // and that also won't require frequent resizes if we need to push more data.
- int size = BitUtils.AlignUp(offset + 0x10, 0x200);
-
- if (_inlineIndexBuffer == BufferHandle.Null)
- {
- _inlineIndexBuffer = _context.Renderer.CreateBuffer(size);
- _inlineIndexBufferSize = size;
- }
- else if (_inlineIndexBufferSize < size)
- {
- BufferHandle oldBuffer = _inlineIndexBuffer;
- int oldSize = _inlineIndexBufferSize;
-
- _inlineIndexBuffer = _context.Renderer.CreateBuffer(size);
- _inlineIndexBufferSize = size;
-
- _context.Renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize);
- _context.Renderer.DeleteBuffer(oldBuffer);
- }
+ _ibStreamer.VbElementU16(_context.Renderer, argument);
+ }
- return _inlineIndexBuffer;
+ /// <summary>
+ /// Pushes one 32-bit index buffer element.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ /// <param name="argument">Method call argument</param>
+ private void VbElementU32(GpuState state, int argument)
+ {
+ _ibStreamer.VbElementU32(_context.Renderer, argument);
}
/// <summary>