using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
///
/// Holds inline index buffer state.
/// The inline index buffer data is sent to the GPU through the command buffer.
///
struct IbStreamer
{
private BufferHandle _inlineIndexBuffer;
private int _inlineIndexBufferSize;
private int _inlineIndexCount;
///
/// Indicates if any index buffer data has been pushed.
///
public bool HasInlineIndexData => _inlineIndexCount != 0;
///
/// Total numbers of indices that have been pushed.
///
public int InlineIndexCount => _inlineIndexCount;
///
/// Gets the handle for the host buffer currently holding the inline index buffer data.
///
/// Host buffer handle
public BufferHandle GetInlineIndexBuffer()
{
return _inlineIndexBuffer;
}
///
/// Gets the number of elements on the current inline index buffer,
/// while also reseting it to zero for the next draw.
///
/// Inline index bufffer count
public int GetAndResetInlineIndexCount()
{
int temp = _inlineIndexCount;
_inlineIndexCount = 0;
return temp;
}
///
/// Pushes four 8-bit index buffer elements.
///
/// Host renderer
/// Method call argument
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 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(data));
_inlineIndexCount += 4;
}
///
/// Pushes two 16-bit index buffer elements.
///
/// Host renderer
/// Method call argument
public void VbElementU16(IRenderer renderer, 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;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data));
_inlineIndexCount += 2;
}
///
/// Pushes one 32-bit index buffer element.
///
/// Host renderer
/// Method call argument
public void VbElementU32(IRenderer renderer, int argument)
{
uint i0 = (uint)argument;
Span data = stackalloc uint[1];
data[0] = i0;
int offset = _inlineIndexCount++ * 4;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data));
}
///
/// Gets the handle of a buffer large enough to hold the data that will be written to .
///
/// Host renderer
/// Offset where the data will be written
/// Buffer handle
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;
}
}
}