2023-12-04 13:17:13 +00:00
|
|
|
using Ryujinx.Graphics.GAL;
|
2023-07-01 10:31:42 +00:00
|
|
|
using IndexType = Silk.NET.Vulkan.IndexType;
|
2022-09-20 21:38:48 +00:00
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Vulkan
|
|
|
|
{
|
|
|
|
internal struct IndexBufferState
|
|
|
|
{
|
2023-08-14 17:18:47 +00:00
|
|
|
private const int IndexBufferMaxMirrorable = 0x20000;
|
|
|
|
|
2023-07-01 10:31:42 +00:00
|
|
|
public static IndexBufferState Null => new(BufferHandle.Null, 0, 0);
|
2022-09-20 21:38:48 +00:00
|
|
|
|
|
|
|
private readonly int _offset;
|
|
|
|
private readonly int _size;
|
|
|
|
private readonly IndexType _type;
|
|
|
|
|
2023-07-01 10:31:42 +00:00
|
|
|
private readonly BufferHandle _handle;
|
2022-09-20 21:38:48 +00:00
|
|
|
private Auto<DisposableBuffer> _buffer;
|
|
|
|
|
2023-07-01 10:31:42 +00:00
|
|
|
public IndexBufferState(BufferHandle handle, int offset, int size, IndexType type)
|
2022-09-20 21:38:48 +00:00
|
|
|
{
|
|
|
|
_handle = handle;
|
|
|
|
_offset = offset;
|
|
|
|
_size = size;
|
|
|
|
_type = type;
|
|
|
|
_buffer = null;
|
|
|
|
}
|
|
|
|
|
2023-07-01 10:31:42 +00:00
|
|
|
public IndexBufferState(BufferHandle handle, int offset, int size)
|
2022-09-20 21:38:48 +00:00
|
|
|
{
|
|
|
|
_handle = handle;
|
|
|
|
_offset = offset;
|
|
|
|
_size = size;
|
|
|
|
_type = IndexType.Uint16;
|
|
|
|
_buffer = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void BindIndexBuffer(VulkanRenderer gd, CommandBufferScoped cbs)
|
|
|
|
{
|
|
|
|
Auto<DisposableBuffer> autoBuffer;
|
|
|
|
int offset, size;
|
|
|
|
IndexType type = _type;
|
2023-08-14 17:18:47 +00:00
|
|
|
bool mirrorable = false;
|
2022-09-20 21:38:48 +00:00
|
|
|
|
|
|
|
if (_type == IndexType.Uint8Ext && !gd.Capabilities.SupportsIndexTypeUint8)
|
|
|
|
{
|
|
|
|
// Index type is not supported. Convert to I16.
|
|
|
|
autoBuffer = gd.BufferManager.GetBufferI8ToI16(cbs, _handle, _offset, _size);
|
|
|
|
|
|
|
|
type = IndexType.Uint16;
|
|
|
|
offset = 0;
|
|
|
|
size = _size * 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-10-16 22:38:58 +00:00
|
|
|
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int bufferSize);
|
|
|
|
|
|
|
|
if (_offset >= bufferSize)
|
|
|
|
{
|
|
|
|
autoBuffer = null;
|
|
|
|
}
|
2022-09-20 21:38:48 +00:00
|
|
|
|
2023-08-14 17:18:47 +00:00
|
|
|
mirrorable = _size < IndexBufferMaxMirrorable;
|
|
|
|
|
2022-09-20 21:38:48 +00:00
|
|
|
offset = _offset;
|
|
|
|
size = _size;
|
|
|
|
}
|
|
|
|
|
|
|
|
_buffer = autoBuffer;
|
|
|
|
|
|
|
|
if (autoBuffer != null)
|
|
|
|
{
|
2023-08-14 17:18:47 +00:00
|
|
|
DisposableBuffer buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, size, out _) : autoBuffer.Get(cbs, offset, size);
|
|
|
|
|
|
|
|
gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, buffer.Value, (ulong)offset, type);
|
2022-09-20 21:38:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-16 17:53:04 +00:00
|
|
|
public void BindConvertedIndexBuffer(
|
|
|
|
VulkanRenderer gd,
|
|
|
|
CommandBufferScoped cbs,
|
|
|
|
int firstIndex,
|
|
|
|
int indexCount,
|
|
|
|
int convertedCount,
|
|
|
|
IndexBufferPattern pattern)
|
2022-09-20 21:38:48 +00:00
|
|
|
{
|
|
|
|
Auto<DisposableBuffer> autoBuffer;
|
|
|
|
|
|
|
|
// Convert the index buffer using the given pattern.
|
2022-11-16 17:53:04 +00:00
|
|
|
int indexSize = GetIndexSize();
|
2022-09-20 21:38:48 +00:00
|
|
|
|
|
|
|
int firstIndexOffset = firstIndex * indexSize;
|
|
|
|
|
|
|
|
autoBuffer = gd.BufferManager.GetBufferTopologyConversion(cbs, _handle, _offset + firstIndexOffset, indexCount * indexSize, pattern, indexSize);
|
|
|
|
|
|
|
|
int size = convertedCount * 4;
|
|
|
|
|
|
|
|
_buffer = autoBuffer;
|
|
|
|
|
|
|
|
if (autoBuffer != null)
|
|
|
|
{
|
|
|
|
gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, autoBuffer.Get(cbs, 0, size).Value, 0, IndexType.Uint32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-16 17:53:04 +00:00
|
|
|
public Auto<DisposableBuffer> BindConvertedIndexBufferIndirect(
|
|
|
|
VulkanRenderer gd,
|
|
|
|
CommandBufferScoped cbs,
|
2023-07-01 10:31:42 +00:00
|
|
|
BufferRange indirectBuffer,
|
|
|
|
BufferRange drawCountBuffer,
|
2022-11-16 17:53:04 +00:00
|
|
|
IndexBufferPattern pattern,
|
|
|
|
bool hasDrawCount,
|
|
|
|
int maxDrawCount,
|
|
|
|
int indirectDataStride)
|
|
|
|
{
|
|
|
|
// Convert the index buffer using the given pattern.
|
|
|
|
int indexSize = GetIndexSize();
|
|
|
|
|
|
|
|
(var indexBufferAuto, var indirectBufferAuto) = gd.BufferManager.GetBufferTopologyConversionIndirect(
|
|
|
|
gd,
|
|
|
|
cbs,
|
2023-07-01 10:31:42 +00:00
|
|
|
new BufferRange(_handle, _offset, _size),
|
2022-11-16 17:53:04 +00:00
|
|
|
indirectBuffer,
|
|
|
|
drawCountBuffer,
|
|
|
|
pattern,
|
|
|
|
indexSize,
|
|
|
|
hasDrawCount,
|
|
|
|
maxDrawCount,
|
|
|
|
indirectDataStride);
|
|
|
|
|
|
|
|
int convertedCount = pattern.GetConvertedCount(_size / indexSize);
|
|
|
|
int size = convertedCount * 4;
|
|
|
|
|
|
|
|
_buffer = indexBufferAuto;
|
|
|
|
|
|
|
|
if (indexBufferAuto != null)
|
|
|
|
{
|
|
|
|
gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, indexBufferAuto.Get(cbs, 0, size).Value, 0, IndexType.Uint32);
|
|
|
|
}
|
|
|
|
|
|
|
|
return indirectBufferAuto;
|
|
|
|
}
|
|
|
|
|
2023-07-01 10:31:42 +00:00
|
|
|
private readonly int GetIndexSize()
|
2022-11-16 17:53:04 +00:00
|
|
|
{
|
|
|
|
return _type switch
|
|
|
|
{
|
|
|
|
IndexType.Uint32 => 4,
|
|
|
|
IndexType.Uint16 => 2,
|
|
|
|
_ => 1,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-07-01 10:31:42 +00:00
|
|
|
public readonly bool BoundEquals(Auto<DisposableBuffer> buffer)
|
2022-09-20 21:38:48 +00:00
|
|
|
{
|
|
|
|
return _buffer == buffer;
|
|
|
|
}
|
2023-03-19 20:56:48 +00:00
|
|
|
|
|
|
|
public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
|
|
|
|
{
|
|
|
|
if (_buffer == from)
|
|
|
|
{
|
|
|
|
_buffer = to;
|
|
|
|
}
|
|
|
|
}
|
2023-08-14 17:18:47 +00:00
|
|
|
|
|
|
|
public readonly bool Overlaps(Auto<DisposableBuffer> buffer, int offset, int size)
|
|
|
|
{
|
|
|
|
return buffer == _buffer && offset < _offset + _size && offset + size > _offset;
|
|
|
|
}
|
2022-09-20 21:38:48 +00:00
|
|
|
}
|
|
|
|
}
|