/ src / Ryujinx.Graphics.Vulkan / IndexBufferPattern.cs
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  }