diff --git a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
index 794323956..f6a99440e 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
@@ -74,7 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (_isLinear && _params.LineCount == 1)
{
- ulong address = _context.MemoryManager.Translate( _params.DstAddress.Pack());
+ ulong address = _context.MemoryManager.Translate(_params.DstAddress.Pack());
_context.PhysicalMemory.Write(address, data);
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
index d70402e92..5d41dafd7 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
@@ -1,5 +1,9 @@
-using Ryujinx.Graphics.Gpu.State;
+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
{
@@ -22,6 +26,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
private int _instanceIndex;
+ private BufferHandle _inlineIndexBuffer = BufferHandle.Null;
+ private int _inlineIndexBufferSize;
+ private int _inlineIndexCount;
+
///
/// Primitive type of the current draw.
///
@@ -87,10 +95,25 @@ namespace Ryujinx.Graphics.Gpu.Engine
int firstInstance = state.Get(MethodOffset.FirstInstance);
- if (_drawIndexed)
+ if (_inlineIndexCount != 0)
{
- _drawIndexed = false;
+ int firstVertex = state.Get(MethodOffset.FirstVertex);
+ BufferRange br = new BufferRange(_inlineIndexBuffer, 0, _inlineIndexCount * 4);
+
+ _context.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt);
+
+ _context.Renderer.Pipeline.DrawIndexed(
+ _inlineIndexCount,
+ 1,
+ _firstIndex,
+ firstVertex,
+ firstInstance);
+
+ _inlineIndexCount = 0;
+ }
+ else if (_drawIndexed)
+ {
int firstVertex = state.Get(MethodOffset.FirstVertex);
_context.Renderer.Pipeline.DrawIndexed(
@@ -111,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
firstInstance);
}
+ _drawIndexed = false;
+
if (renderEnable == ConditionalRenderEnabled.Host)
{
_context.Renderer.Pipeline.EndHostConditionalRendering();
@@ -154,6 +179,103 @@ namespace Ryujinx.Graphics.Gpu.Engine
_drawIndexed = true;
}
+ ///
+ /// Pushes four 8-bit index buffer elements.
+ ///
+ /// Current GPU state
+ /// Method call argument
+ private void VbElementU8(GpuState state, int argument)
+ {
+ byte i0 = (byte)argument;
+ byte i1 = (byte)(argument >> 8);
+ byte i2 = (byte)(argument >> 16);
+ byte i3 = (byte)(argument >> 24);
+
+ Span data = stackalloc uint[4];
+
+ data[0] = i0;
+ data[1] = i1;
+ data[2] = i2;
+ data[3] = i3;
+
+ int offset = _inlineIndexCount * 4;
+
+ _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast(data));
+
+ _inlineIndexCount += 4;
+ }
+
+ ///
+ /// Pushes two 16-bit index buffer elements.
+ ///
+ /// Current GPU state
+ /// Method call argument
+ private void VbElementU16(GpuState state, int argument)
+ {
+ ushort i0 = (ushort)argument;
+ ushort i1 = (ushort)(argument >> 16);
+
+ Span data = stackalloc uint[2];
+
+ data[0] = i0;
+ data[1] = i1;
+
+ int offset = _inlineIndexCount * 4;
+
+ _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast(data));
+
+ _inlineIndexCount += 2;
+ }
+
+ ///
+ /// Pushes one 32-bit index buffer element.
+ ///
+ /// Current GPU state
+ /// Method call argument
+ private void VbElementU32(GpuState state, int argument)
+ {
+ uint i0 = (uint)argument;
+
+ Span data = stackalloc uint[1];
+
+ data[0] = i0;
+
+ int offset = _inlineIndexCount++ * 4;
+
+ _context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast(data));
+ }
+
+ ///
+ /// Gets the handle of a buffer large enough to hold the data that will be written to .
+ ///
+ /// Offset where the data will be written
+ /// Buffer handle
+ private BufferHandle GetInlineIndexBuffer(int offset)
+ {
+ // 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);
+ }
+
+ return _inlineIndexBuffer;
+ }
+
///
/// Perform any deferred draws.
/// This is used for instanced draws.
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index fc933131f..af32c6bc1 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -78,6 +78,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
state.RegisterCallback(MethodOffset.InvalidateTextures, InvalidateTextures);
state.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
+ state.RegisterCallback(MethodOffset.VbElementU8, VbElementU8);
+ state.RegisterCallback(MethodOffset.VbElementU16, VbElementU16);
+ state.RegisterCallback(MethodOffset.VbElementU32, VbElementU32);
+
state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
@@ -726,7 +730,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
ulong size;
- if (_drawIndexed || stride == 0 || instanced)
+ if (_inlineIndexCount != 0 || _drawIndexed || stride == 0 || instanced)
{
// This size may be (much) larger than the real vertex buffer size.
// Avoid calculating it this way, unless we don't have any other option.
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index 39d1cd6f1..533b05768 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -103,6 +103,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
_indexBufferDirty = true;
}
+ ///
+ /// Sets a new index buffer that overrides the one set on the call to .
+ ///
+ /// Buffer to be used as index buffer
+ /// Type of each index buffer element
+ public void SetIndexBuffer(BufferRange buffer, IndexType type)
+ {
+ _context.Renderer.Pipeline.SetIndexBuffer(buffer, type);
+
+ _indexBufferDirty = true;
+ }
+
///
/// Sets the memory range with vertex buffer data, to be used for subsequent draw calls.
///
diff --git a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
index da54a4698..2e0a197e2 100644
--- a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
+++ b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
@@ -58,6 +58,7 @@ namespace Ryujinx.Graphics.Gpu.State
DepthTestEnable = 0x4b3,
BlendIndependent = 0x4b9,
DepthWriteEnable = 0x4ba,
+ VbElementU8 = 0x4c1,
DepthTestFunc = 0x4c3,
BlendConstant = 0x4c7,
BlendStateCommon = 0x4cf,
@@ -78,6 +79,8 @@ namespace Ryujinx.Graphics.Gpu.State
StencilBackTestState = 0x565,
DepthBiasUnits = 0x56f,
RtMsaaMode = 0x574,
+ VbElementU32 = 0x57a,
+ VbElementU16 = 0x57c,
ShaderBaseAddress = 0x582,
DrawEnd = 0x585,
DrawBegin = 0x586,