IndexBufferPattern.cs
1 using Ryujinx.Graphics.GAL; 2 using System; 3 using System.Collections.Generic; 4 using System.Runtime.InteropServices; 5 6 namespace Ryujinx.Graphics.Vulkan 7 { 8 internal class IndexBufferPattern : IDisposable 9 { 10 public int PrimitiveVertices { get; } 11 public int PrimitiveVerticesOut { get; } 12 public int BaseIndex { get; } 13 public int[] OffsetIndex { get; } 14 public int IndexStride { get; } 15 public bool RepeatStart { get; } 16 17 private readonly VulkanRenderer _gd; 18 private int _currentSize; 19 private BufferHandle _repeatingBuffer; 20 21 public IndexBufferPattern(VulkanRenderer gd, 22 int primitiveVertices, 23 int primitiveVerticesOut, 24 int baseIndex, 25 int[] offsetIndex, 26 int indexStride, 27 bool repeatStart) 28 { 29 PrimitiveVertices = primitiveVertices; 30 PrimitiveVerticesOut = primitiveVerticesOut; 31 BaseIndex = baseIndex; 32 OffsetIndex = offsetIndex; 33 IndexStride = indexStride; 34 RepeatStart = repeatStart; 35 36 _gd = gd; 37 } 38 39 public int GetPrimitiveCount(int vertexCount) 40 { 41 return Math.Max(0, (vertexCount - BaseIndex) / IndexStride); 42 } 43 44 public int GetConvertedCount(int indexCount) 45 { 46 int primitiveCount = GetPrimitiveCount(indexCount); 47 return primitiveCount * OffsetIndex.Length; 48 } 49 50 public IEnumerable<int> GetIndexMapping(int indexCount) 51 { 52 int primitiveCount = GetPrimitiveCount(indexCount); 53 int index = BaseIndex; 54 55 for (int i = 0; i < primitiveCount; i++) 56 { 57 if (RepeatStart) 58 { 59 // Used for triangle fan 60 yield return 0; 61 } 62 63 for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++) 64 { 65 yield return index + OffsetIndex[j]; 66 } 67 68 index += IndexStride; 69 } 70 } 71 72 public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount) 73 { 74 int primitiveCount = GetPrimitiveCount(vertexCount); 75 indexCount = primitiveCount * PrimitiveVerticesOut; 76 77 int expectedSize = primitiveCount * OffsetIndex.Length; 78 79 if (expectedSize <= _currentSize && _repeatingBuffer != BufferHandle.Null) 80 { 81 return _repeatingBuffer; 82 } 83 84 // Expand the repeating pattern to the number of requested primitives. 85 BufferHandle newBuffer = _gd.BufferManager.CreateWithHandle(_gd, expectedSize * sizeof(int)); 86 87 // Copy the old data to the new one. 88 if (_repeatingBuffer != BufferHandle.Null) 89 { 90 _gd.Pipeline.CopyBuffer(_repeatingBuffer, newBuffer, 0, 0, _currentSize * sizeof(int)); 91 _gd.DeleteBuffer(_repeatingBuffer); 92 } 93 94 _repeatingBuffer = newBuffer; 95 96 // Add the additional repeats on top. 97 int newPrimitives = primitiveCount; 98 int oldPrimitives = (_currentSize) / OffsetIndex.Length; 99 100 int[] newData; 101 102 newPrimitives -= oldPrimitives; 103 newData = new int[expectedSize - _currentSize]; 104 105 int outOffset = 0; 106 int index = oldPrimitives * IndexStride + BaseIndex; 107 108 for (int i = 0; i < newPrimitives; i++) 109 { 110 if (RepeatStart) 111 { 112 // Used for triangle fan 113 newData[outOffset++] = 0; 114 } 115 116 for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++) 117 { 118 newData[outOffset++] = index + OffsetIndex[j]; 119 } 120 121 index += IndexStride; 122 } 123 124 _gd.SetBufferData(newBuffer, _currentSize * sizeof(int), MemoryMarshal.Cast<int, byte>(newData)); 125 _currentSize = expectedSize; 126 127 return newBuffer; 128 } 129 130 public void Dispose() 131 { 132 if (_repeatingBuffer != BufferHandle.Null) 133 { 134 _gd.DeleteBuffer(_repeatingBuffer); 135 _repeatingBuffer = BufferHandle.Null; 136 } 137 } 138 } 139 }