R/Ryujinx.Graphics.Vulkan/IndexBufferPattern.cs

140 lines
4.3 KiB
C#
Raw Normal View History

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)
{
return Math.Max(0, (vertexCount - BaseIndex) / IndexStride);
}
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;
}
}
}
}