2022-09-20 23:38:48 +02:00
|
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Vulkan
|
|
|
|
|
{
|
|
|
|
|
internal class IndexBufferPattern : IDisposable
|
|
|
|
|
{
|
|
|
|
|
public int PrimitiveVertices { get; }
|
|
|
|
|
public int PrimitiveVerticesOut { get; }
|
|
|
|
|
public int BaseIndex { get; }
|
|
|
|
|
public int[] OffsetIndex { get; }
|
|
|
|
|
public int IndexStride { get; }
|
|
|
|
|
public bool RepeatStart { get; }
|
|
|
|
|
|
|
|
|
|
private VulkanRenderer _gd;
|
|
|
|
|
private int _currentSize;
|
|
|
|
|
private BufferHandle _repeatingBuffer;
|
|
|
|
|
|
|
|
|
|
public IndexBufferPattern(VulkanRenderer gd,
|
|
|
|
|
int primitiveVertices,
|
|
|
|
|
int primitiveVerticesOut,
|
|
|
|
|
int baseIndex,
|
|
|
|
|
int[] offsetIndex,
|
|
|
|
|
int indexStride,
|
|
|
|
|
bool repeatStart)
|
|
|
|
|
{
|
|
|
|
|
PrimitiveVertices = primitiveVertices;
|
|
|
|
|
PrimitiveVerticesOut = primitiveVerticesOut;
|
|
|
|
|
BaseIndex = baseIndex;
|
|
|
|
|
OffsetIndex = offsetIndex;
|
|
|
|
|
IndexStride = indexStride;
|
|
|
|
|
RepeatStart = repeatStart;
|
|
|
|
|
|
|
|
|
|
_gd = gd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetPrimitiveCount(int vertexCount)
|
|
|
|
|
{
|
2022-10-17 00:25:40 +02:00
|
|
|
|
return Math.Max(0, (vertexCount - BaseIndex) / IndexStride);
|
2022-09-20 23:38:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetConvertedCount(int indexCount)
|
|
|
|
|
{
|
|
|
|
|
int primitiveCount = GetPrimitiveCount(indexCount);
|
|
|
|
|
return primitiveCount * OffsetIndex.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<int> GetIndexMapping(int indexCount)
|
|
|
|
|
{
|
|
|
|
|
int primitiveCount = GetPrimitiveCount(indexCount);
|
|
|
|
|
int index = BaseIndex;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < primitiveCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if (RepeatStart)
|
|
|
|
|
{
|
|
|
|
|
// Used for triangle fan
|
|
|
|
|
yield return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++)
|
|
|
|
|
{
|
|
|
|
|
yield return index + OffsetIndex[j];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index += IndexStride;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount)
|
|
|
|
|
{
|
|
|
|
|
int primitiveCount = GetPrimitiveCount(vertexCount);
|
|
|
|
|
indexCount = primitiveCount * PrimitiveVerticesOut;
|
|
|
|
|
|
|
|
|
|
int expectedSize = primitiveCount * OffsetIndex.Length;
|
|
|
|
|
|
|
|
|
|
if (expectedSize <= _currentSize && _repeatingBuffer != BufferHandle.Null)
|
|
|
|
|
{
|
|
|
|
|
return _repeatingBuffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Expand the repeating pattern to the number of requested primitives.
|
|
|
|
|
BufferHandle newBuffer = _gd.CreateBuffer(expectedSize * sizeof(int));
|
|
|
|
|
|
|
|
|
|
// Copy the old data to the new one.
|
|
|
|
|
if (_repeatingBuffer != BufferHandle.Null)
|
|
|
|
|
{
|
|
|
|
|
_gd.Pipeline.CopyBuffer(_repeatingBuffer, newBuffer, 0, 0, _currentSize * sizeof(int));
|
|
|
|
|
_gd.DeleteBuffer(_repeatingBuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_repeatingBuffer = newBuffer;
|
|
|
|
|
|
|
|
|
|
// Add the additional repeats on top.
|
|
|
|
|
int newPrimitives = primitiveCount;
|
|
|
|
|
int oldPrimitives = (_currentSize) / OffsetIndex.Length;
|
|
|
|
|
|
|
|
|
|
int[] newData;
|
|
|
|
|
|
|
|
|
|
newPrimitives -= oldPrimitives;
|
|
|
|
|
newData = new int[expectedSize - _currentSize];
|
|
|
|
|
|
|
|
|
|
int outOffset = 0;
|
|
|
|
|
int index = oldPrimitives * IndexStride + BaseIndex;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < newPrimitives; i++)
|
|
|
|
|
{
|
|
|
|
|
if (RepeatStart)
|
|
|
|
|
{
|
|
|
|
|
// Used for triangle fan
|
|
|
|
|
newData[outOffset++] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++)
|
|
|
|
|
{
|
|
|
|
|
newData[outOffset++] = index + OffsetIndex[j];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index += IndexStride;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_gd.SetBufferData(newBuffer, _currentSize * sizeof(int), MemoryMarshal.Cast<int, byte>(newData));
|
|
|
|
|
_currentSize = expectedSize;
|
|
|
|
|
|
|
|
|
|
return newBuffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
if (_repeatingBuffer != BufferHandle.Null)
|
|
|
|
|
{
|
|
|
|
|
_gd.DeleteBuffer(_repeatingBuffer);
|
|
|
|
|
_repeatingBuffer = BufferHandle.Null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|