Implement small indexed draws and other fixes to make guest Vulkan work (#1558)
This commit is contained in:
parent
e00ca92063
commit
bd28ce90e6
10 changed files with 357 additions and 133 deletions
9
Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs
Normal file
9
Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
{
|
||||||
|
enum ConditionalRenderEnabled
|
||||||
|
{
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
Host
|
||||||
|
}
|
||||||
|
}
|
139
Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs
Normal file
139
Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds inline index buffer state.
|
||||||
|
/// The inline index buffer data is sent to the GPU through the command buffer.
|
||||||
|
/// </summary>
|
||||||
|
struct IbStreamer
|
||||||
|
{
|
||||||
|
private BufferHandle _inlineIndexBuffer;
|
||||||
|
private int _inlineIndexBufferSize;
|
||||||
|
private int _inlineIndexCount;
|
||||||
|
|
||||||
|
public bool HasInlineIndexData => _inlineIndexCount != 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the handle for the host buffer currently holding the inline index buffer data.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Host buffer handle</returns>
|
||||||
|
public BufferHandle GetInlineIndexBuffer()
|
||||||
|
{
|
||||||
|
return _inlineIndexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of elements on the current inline index buffer,
|
||||||
|
/// while also reseting it to zero for the next draw.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Inline index bufffer count</returns>
|
||||||
|
public int GetAndResetInlineIndexCount()
|
||||||
|
{
|
||||||
|
int temp = _inlineIndexCount;
|
||||||
|
_inlineIndexCount = 0;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pushes four 8-bit index buffer elements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
|
/// <param name="argument">Method call argument</param>
|
||||||
|
public void VbElementU8(IRenderer renderer, 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;
|
||||||
|
|
||||||
|
int offset = _inlineIndexCount * 4;
|
||||||
|
|
||||||
|
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
||||||
|
|
||||||
|
_inlineIndexCount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pushes two 16-bit index buffer elements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
|
/// <param name="argument">Method call argument</param>
|
||||||
|
public void VbElementU16(IRenderer renderer, int argument)
|
||||||
|
{
|
||||||
|
ushort i0 = (ushort)argument;
|
||||||
|
ushort i1 = (ushort)(argument >> 16);
|
||||||
|
|
||||||
|
Span<uint> data = stackalloc uint[2];
|
||||||
|
|
||||||
|
data[0] = i0;
|
||||||
|
data[1] = i1;
|
||||||
|
|
||||||
|
int offset = _inlineIndexCount * 4;
|
||||||
|
|
||||||
|
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
||||||
|
|
||||||
|
_inlineIndexCount += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pushes one 32-bit index buffer element.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
|
/// <param name="argument">Method call argument</param>
|
||||||
|
public void VbElementU32(IRenderer renderer, int argument)
|
||||||
|
{
|
||||||
|
uint i0 = (uint)argument;
|
||||||
|
|
||||||
|
Span<uint> data = stackalloc uint[1];
|
||||||
|
|
||||||
|
data[0] = i0;
|
||||||
|
|
||||||
|
int offset = _inlineIndexCount++ * 4;
|
||||||
|
|
||||||
|
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
|
/// <param name="offset">Offset where the data will be written</param>
|
||||||
|
/// <returns>Buffer handle</returns>
|
||||||
|
private BufferHandle GetInlineIndexBuffer(IRenderer renderer, 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 = renderer.CreateBuffer(size);
|
||||||
|
_inlineIndexBufferSize = size;
|
||||||
|
}
|
||||||
|
else if (_inlineIndexBufferSize < size)
|
||||||
|
{
|
||||||
|
BufferHandle oldBuffer = _inlineIndexBuffer;
|
||||||
|
int oldSize = _inlineIndexBufferSize;
|
||||||
|
|
||||||
|
_inlineIndexBuffer = renderer.CreateBuffer(size);
|
||||||
|
_inlineIndexBufferSize = size;
|
||||||
|
|
||||||
|
renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize);
|
||||||
|
renderer.DeleteBuffer(oldBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _inlineIndexBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
UpdateRenderTargetState(state, useControl: false, singleUse: index);
|
UpdateRenderTargetState(state, useControl: false, singleUse: index);
|
||||||
|
|
||||||
TextureManager.CommitGraphicsBindings();
|
TextureManager.UpdateRenderTargets();
|
||||||
|
|
||||||
bool clearDepth = (argument & 1) != 0;
|
bool clearDepth = (argument & 1) != 0;
|
||||||
bool clearStencil = (argument & 2) != 0;
|
bool clearStencil = (argument & 2) != 0;
|
||||||
|
|
|
@ -6,13 +6,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
{
|
{
|
||||||
partial class Methods
|
partial class Methods
|
||||||
{
|
{
|
||||||
enum ConditionalRenderEnabled
|
|
||||||
{
|
|
||||||
False,
|
|
||||||
True,
|
|
||||||
Host
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if draws and clears should be performed, according
|
/// Checks if draws and clears should be performed, according
|
||||||
/// to currently set conditional rendering conditions.
|
/// to currently set conditional rendering conditions.
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Image;
|
using Ryujinx.Graphics.Gpu.Image;
|
||||||
using Ryujinx.Graphics.Gpu.State;
|
using Ryujinx.Graphics.Gpu.State;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine
|
namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
{
|
{
|
||||||
|
@ -11,9 +8,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
{
|
{
|
||||||
private bool _drawIndexed;
|
private bool _drawIndexed;
|
||||||
|
|
||||||
private int _firstIndex;
|
|
||||||
private int _indexCount;
|
|
||||||
|
|
||||||
private bool _instancedDrawPending;
|
private bool _instancedDrawPending;
|
||||||
private bool _instancedIndexed;
|
private bool _instancedIndexed;
|
||||||
|
|
||||||
|
@ -26,22 +20,34 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
private int _instanceIndex;
|
private int _instanceIndex;
|
||||||
|
|
||||||
private BufferHandle _inlineIndexBuffer = BufferHandle.Null;
|
private IbStreamer _ibStreamer;
|
||||||
private int _inlineIndexBufferSize;
|
|
||||||
private int _inlineIndexCount;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Primitive type of the current draw.
|
/// Primitive topology of the current draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PrimitiveType PrimitiveType { get; private set; }
|
public PrimitiveTopology Topology { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finishes draw call.
|
/// Finishes the draw call.
|
||||||
/// This draws geometry on the bound buffers based on the current GPU state.
|
/// This draws geometry on the bound buffers based on the current GPU state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument</param>
|
||||||
private void DrawEnd(GpuState state, int argument)
|
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);
|
ConditionalRenderEnabled renderEnable = GetRenderEnable(state);
|
||||||
|
|
||||||
|
@ -62,7 +68,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateState(state);
|
UpdateState(state, firstIndex, indexCount);
|
||||||
|
|
||||||
bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
|
bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
|
||||||
|
|
||||||
|
@ -72,11 +78,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
_instancedIndexed = _drawIndexed;
|
_instancedIndexed = _drawIndexed;
|
||||||
|
|
||||||
_instancedFirstIndex = _firstIndex;
|
_instancedFirstIndex = firstIndex;
|
||||||
_instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
_instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
||||||
_instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
|
_instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
|
||||||
|
|
||||||
_instancedIndexCount = _indexCount;
|
_instancedIndexCount = indexCount;
|
||||||
|
|
||||||
var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
|
var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
|
||||||
|
|
||||||
|
@ -95,31 +101,31 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
|
int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
|
||||||
|
|
||||||
if (_inlineIndexCount != 0)
|
int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount();
|
||||||
|
|
||||||
|
if (inlineIndexCount != 0)
|
||||||
{
|
{
|
||||||
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
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.Methods.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.DrawIndexed(
|
_context.Renderer.Pipeline.DrawIndexed(
|
||||||
_inlineIndexCount,
|
inlineIndexCount,
|
||||||
1,
|
1,
|
||||||
_firstIndex,
|
firstIndex,
|
||||||
firstVertex,
|
firstVertex,
|
||||||
firstInstance);
|
firstInstance);
|
||||||
|
|
||||||
_inlineIndexCount = 0;
|
|
||||||
}
|
}
|
||||||
else if (_drawIndexed)
|
else if (_drawIndexed)
|
||||||
{
|
{
|
||||||
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.DrawIndexed(
|
_context.Renderer.Pipeline.DrawIndexed(
|
||||||
_indexCount,
|
indexCount,
|
||||||
1,
|
1,
|
||||||
_firstIndex,
|
firstIndex,
|
||||||
firstVertex,
|
firstVertex,
|
||||||
firstInstance);
|
firstInstance);
|
||||||
}
|
}
|
||||||
|
@ -150,22 +156,46 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument</param>
|
||||||
private void DrawBegin(GpuState state, int argument)
|
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++;
|
_instanceIndex++;
|
||||||
}
|
}
|
||||||
else if ((argument & (1 << 27)) == 0)
|
else if (resetInstance)
|
||||||
{
|
{
|
||||||
PerformDeferredDraws();
|
PerformDeferredDraws();
|
||||||
|
|
||||||
_instanceIndex = 0;
|
_instanceIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
|
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert());
|
Topology = topology;
|
||||||
|
|
||||||
PrimitiveType = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -179,6 +209,73 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
_drawIndexed = true;
|
_drawIndexed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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 DrawIndexedSmall(GpuState state, int argument)
|
||||||
|
{
|
||||||
|
DrawIndexedSmall(state, argument, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// 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>
|
||||||
|
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
|
||||||
|
private void DrawIndexedSmall(GpuState state, int argument, bool instanced)
|
||||||
|
{
|
||||||
|
PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
|
||||||
|
|
||||||
|
DrawBegin(instanced, !instanced, typeOverride.Convert());
|
||||||
|
|
||||||
|
int firstIndex = argument & 0xffff;
|
||||||
|
int indexCount = (argument >> 16) & 0xfff;
|
||||||
|
|
||||||
|
bool oldDrawIndexed = _drawIndexed;
|
||||||
|
|
||||||
|
_drawIndexed = true;
|
||||||
|
|
||||||
|
DrawEnd(state, firstIndex, indexCount);
|
||||||
|
|
||||||
|
_drawIndexed = oldDrawIndexed;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pushes four 8-bit index buffer elements.
|
/// Pushes four 8-bit index buffer elements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -186,23 +283,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument</param>
|
||||||
private void VbElementU8(GpuState state, int argument)
|
private void VbElementU8(GpuState state, int argument)
|
||||||
{
|
{
|
||||||
byte i0 = (byte)argument;
|
_ibStreamer.VbElementU8(_context.Renderer, 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;
|
|
||||||
|
|
||||||
int offset = _inlineIndexCount * 4;
|
|
||||||
|
|
||||||
_context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
|
||||||
|
|
||||||
_inlineIndexCount += 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -212,19 +293,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument</param>
|
||||||
private void VbElementU16(GpuState state, int argument)
|
private void VbElementU16(GpuState state, int argument)
|
||||||
{
|
{
|
||||||
ushort i0 = (ushort)argument;
|
_ibStreamer.VbElementU16(_context.Renderer, argument);
|
||||||
ushort i1 = (ushort)(argument >> 16);
|
|
||||||
|
|
||||||
Span<uint> data = stackalloc uint[2];
|
|
||||||
|
|
||||||
data[0] = i0;
|
|
||||||
data[1] = i1;
|
|
||||||
|
|
||||||
int offset = _inlineIndexCount * 4;
|
|
||||||
|
|
||||||
_context.Renderer.SetBufferData(GetInlineIndexBuffer(offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
|
||||||
|
|
||||||
_inlineIndexCount += 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -234,46 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// <param name="argument">Method call argument</param>
|
/// <param name="argument">Method call argument</param>
|
||||||
private void VbElementU32(GpuState state, int argument)
|
private void VbElementU32(GpuState state, int argument)
|
||||||
{
|
{
|
||||||
uint i0 = (uint)argument;
|
_ibStreamer.VbElementU32(_context.Renderer, 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="offset">Offset where the data will be written</param>
|
|
||||||
/// <returns>Buffer handle</returns>
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -87,8 +87,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
|
state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
|
||||||
|
|
||||||
state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
|
state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
|
||||||
state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
|
state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
|
||||||
|
state.RegisterCallback(MethodOffset.DrawIndexedSmall, DrawIndexedSmall);
|
||||||
|
state.RegisterCallback(MethodOffset.DrawIndexedSmall2, DrawIndexedSmall2);
|
||||||
|
state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance, DrawIndexedSmallIncInstance);
|
||||||
|
state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance2, DrawIndexedSmallIncInstance2);
|
||||||
|
|
||||||
state.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
|
state.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
|
||||||
|
|
||||||
|
@ -111,7 +115,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// Updates host state based on the current guest GPU state.
|
/// Updates host state based on the current guest GPU state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Guest GPU state</param>
|
/// <param name="state">Guest GPU state</param>
|
||||||
private void UpdateState(GpuState state)
|
/// <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 UpdateState(GpuState state, int firstIndex, int indexCount)
|
||||||
{
|
{
|
||||||
bool tfEnable = state.Get<Boolean32>(MethodOffset.TfEnable);
|
bool tfEnable = state.Get<Boolean32>(MethodOffset.TfEnable);
|
||||||
|
|
||||||
|
@ -233,7 +239,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
if (state.QueryModified(MethodOffset.IndexBufferState))
|
if (state.QueryModified(MethodOffset.IndexBufferState))
|
||||||
{
|
{
|
||||||
UpdateIndexBufferState(state);
|
UpdateIndexBufferState(state, firstIndex, indexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.QueryModified(MethodOffset.VertexBufferDrawState,
|
if (state.QueryModified(MethodOffset.VertexBufferDrawState,
|
||||||
|
@ -273,7 +279,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
if (tfEnable && !_prevTfEnable)
|
if (tfEnable && !_prevTfEnable)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.BeginTransformFeedback(PrimitiveType.Convert());
|
_context.Renderer.Pipeline.BeginTransformFeedback(Topology);
|
||||||
_prevTfEnable = true;
|
_prevTfEnable = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -742,14 +748,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// Updates host index buffer binding based on guest GPU state.
|
/// Updates host index buffer binding based on guest GPU state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
private void UpdateIndexBufferState(GpuState state)
|
/// <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 UpdateIndexBufferState(GpuState state, int firstIndex, int indexCount)
|
||||||
{
|
{
|
||||||
var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
|
var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
|
||||||
|
|
||||||
_firstIndex = indexBuffer.First;
|
if (indexCount == 0)
|
||||||
_indexCount = indexBuffer.Count;
|
|
||||||
|
|
||||||
if (_indexCount == 0)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -758,7 +763,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
// Do not use the end address to calculate the size, because
|
// Do not use the end address to calculate the size, because
|
||||||
// the result may be much larger than the real size of the index buffer.
|
// the result may be much larger than the real size of the index buffer.
|
||||||
ulong size = (ulong)(_firstIndex + _indexCount);
|
ulong size = (ulong)(firstIndex + indexCount);
|
||||||
|
|
||||||
switch (indexBuffer.Type)
|
switch (indexBuffer.Type)
|
||||||
{
|
{
|
||||||
|
@ -806,7 +811,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
ulong size;
|
ulong size;
|
||||||
|
|
||||||
if (_inlineIndexCount != 0 || _drawIndexed || stride == 0 || instanced)
|
if (_ibStreamer.HasInlineIndexData || _drawIndexed || stride == 0 || instanced)
|
||||||
{
|
{
|
||||||
// This size may be (much) larger than the real vertex buffer size.
|
// 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.
|
// Avoid calculating it this way, unless we don't have any other option.
|
||||||
|
|
|
@ -348,7 +348,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update host framebuffer attachments based on currently bound render target buffers.
|
/// Update host framebuffer attachments based on currently bound render target buffers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateRenderTargets()
|
public void UpdateRenderTargets()
|
||||||
{
|
{
|
||||||
bool anyChanged = false;
|
bool anyChanged = false;
|
||||||
|
|
||||||
|
|
|
@ -147,23 +147,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <returns>Current primitive topology</returns>
|
/// <returns>Current primitive topology</returns>
|
||||||
public InputTopology QueryPrimitiveTopology()
|
public InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
switch (_context.Methods.PrimitiveType)
|
switch (_context.Methods.Topology)
|
||||||
{
|
{
|
||||||
case PrimitiveType.Points:
|
case PrimitiveTopology.Points:
|
||||||
return InputTopology.Points;
|
return InputTopology.Points;
|
||||||
case PrimitiveType.Lines:
|
case PrimitiveTopology.Lines:
|
||||||
case PrimitiveType.LineLoop:
|
case PrimitiveTopology.LineLoop:
|
||||||
case PrimitiveType.LineStrip:
|
case PrimitiveTopology.LineStrip:
|
||||||
return InputTopology.Lines;
|
return InputTopology.Lines;
|
||||||
case PrimitiveType.LinesAdjacency:
|
case PrimitiveTopology.LinesAdjacency:
|
||||||
case PrimitiveType.LineStripAdjacency:
|
case PrimitiveTopology.LineStripAdjacency:
|
||||||
return InputTopology.LinesAdjacency;
|
return InputTopology.LinesAdjacency;
|
||||||
case PrimitiveType.Triangles:
|
case PrimitiveTopology.Triangles:
|
||||||
case PrimitiveType.TriangleStrip:
|
case PrimitiveTopology.TriangleStrip:
|
||||||
case PrimitiveType.TriangleFan:
|
case PrimitiveTopology.TriangleFan:
|
||||||
return InputTopology.Triangles;
|
return InputTopology.Triangles;
|
||||||
case PrimitiveType.TrianglesAdjacency:
|
case PrimitiveTopology.TrianglesAdjacency:
|
||||||
case PrimitiveType.TriangleStripAdjacency:
|
case PrimitiveTopology.TriangleStripAdjacency:
|
||||||
return InputTopology.TrianglesAdjacency;
|
return InputTopology.TrianglesAdjacency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,17 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
PrimitiveRestartState = 0x591,
|
PrimitiveRestartState = 0x591,
|
||||||
IndexBufferState = 0x5f2,
|
IndexBufferState = 0x5f2,
|
||||||
IndexBufferCount = 0x5f8,
|
IndexBufferCount = 0x5f8,
|
||||||
|
DrawIndexedSmall = 0x5f9,
|
||||||
|
DrawIndexedSmall2 = 0x5fa,
|
||||||
|
DrawIndexedSmallIncInstance = 0x5fc,
|
||||||
|
DrawIndexedSmallIncInstance2 = 0x5fd,
|
||||||
DepthBiasClamp = 0x61f,
|
DepthBiasClamp = 0x61f,
|
||||||
VertexBufferInstanced = 0x620,
|
VertexBufferInstanced = 0x620,
|
||||||
VertexProgramPointSize = 0x644,
|
VertexProgramPointSize = 0x644,
|
||||||
FaceState = 0x646,
|
FaceState = 0x646,
|
||||||
ViewportTransformEnable = 0x64b,
|
ViewportTransformEnable = 0x64b,
|
||||||
ViewVolumeClipControl = 0x64f,
|
ViewVolumeClipControl = 0x64f,
|
||||||
|
PrimitiveTypeOverride = 0x65c,
|
||||||
LogicOpState = 0x671,
|
LogicOpState = 0x671,
|
||||||
Clear = 0x674,
|
Clear = 0x674,
|
||||||
RtColorMask = 0x680,
|
RtColorMask = 0x680,
|
||||||
|
|
|
@ -24,6 +24,25 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
Patches
|
Patches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Alternative primitive type that might override <see cref="PrimitiveType"/>.
|
||||||
|
/// </summary>
|
||||||
|
enum PrimitiveTypeOverride
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
Points = 1,
|
||||||
|
Lines = 2,
|
||||||
|
LineStrip = 3,
|
||||||
|
Triangles = 4,
|
||||||
|
TriangleStrip = 5,
|
||||||
|
TriangleFan = 0x1015,
|
||||||
|
LinesAdjacency = 10,
|
||||||
|
LineStripAdjacency = 11,
|
||||||
|
TrianglesAdjacency = 12,
|
||||||
|
TriangleStripAdjacency = 13,
|
||||||
|
Patches = 14
|
||||||
|
}
|
||||||
|
|
||||||
static class PrimitiveTypeConverter
|
static class PrimitiveTypeConverter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -53,5 +72,29 @@ namespace Ryujinx.Graphics.Gpu.State
|
||||||
_ => PrimitiveTopology.Triangles
|
_ => PrimitiveTopology.Triangles
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the primitive type into something that can be used with the host API.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The primitive type to convert</param>
|
||||||
|
/// <returns>A host compatible enum value</returns>
|
||||||
|
public static PrimitiveTopology Convert(this PrimitiveTypeOverride type)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
PrimitiveTypeOverride.Points => PrimitiveTopology.Points,
|
||||||
|
PrimitiveTypeOverride.Lines => PrimitiveTopology.Lines,
|
||||||
|
PrimitiveTypeOverride.LineStrip => PrimitiveTopology.LineStrip,
|
||||||
|
PrimitiveTypeOverride.Triangles => PrimitiveTopology.Triangles,
|
||||||
|
PrimitiveTypeOverride.TriangleStrip => PrimitiveTopology.TriangleStrip,
|
||||||
|
PrimitiveTypeOverride.TriangleFan => PrimitiveTopology.TriangleFan,
|
||||||
|
PrimitiveTypeOverride.LinesAdjacency => PrimitiveTopology.LinesAdjacency,
|
||||||
|
PrimitiveTypeOverride.LineStripAdjacency => PrimitiveTopology.LineStripAdjacency,
|
||||||
|
PrimitiveTypeOverride.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency,
|
||||||
|
PrimitiveTypeOverride.TriangleStripAdjacency => PrimitiveTopology.TriangleStripAdjacency,
|
||||||
|
PrimitiveTypeOverride.Patches => PrimitiveTopology.Patches,
|
||||||
|
_ => PrimitiveTopology.Triangles
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue