mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-17 22:28:43 +02:00
Luigi's Mansion 3 performs a non-index quads draw with 6 vertices. It's meant to ignore the last two, but the index pattern's primitive count calculation was rounding up. No idea why the game does this but this should fix random triangles in the map.
140 lines
4.3 KiB
C#
140 lines
4.3 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|