/ src / Ryujinx.Graphics.Vulkan / IndexBufferState.cs
IndexBufferState.cs
  1  using Ryujinx.Graphics.GAL;
  2  using IndexType = Silk.NET.Vulkan.IndexType;
  3  
  4  namespace Ryujinx.Graphics.Vulkan
  5  {
  6      internal struct IndexBufferState
  7      {
  8          private const int IndexBufferMaxMirrorable = 0x20000;
  9  
 10          public static IndexBufferState Null => new(BufferHandle.Null, 0, 0);
 11  
 12          private readonly int _offset;
 13          private readonly int _size;
 14          private readonly IndexType _type;
 15  
 16          private readonly BufferHandle _handle;
 17          private Auto<DisposableBuffer> _buffer;
 18  
 19          public IndexBufferState(BufferHandle handle, int offset, int size, IndexType type)
 20          {
 21              _handle = handle;
 22              _offset = offset;
 23              _size = size;
 24              _type = type;
 25              _buffer = null;
 26          }
 27  
 28          public IndexBufferState(BufferHandle handle, int offset, int size)
 29          {
 30              _handle = handle;
 31              _offset = offset;
 32              _size = size;
 33              _type = IndexType.Uint16;
 34              _buffer = null;
 35          }
 36  
 37          public void BindIndexBuffer(VulkanRenderer gd, CommandBufferScoped cbs)
 38          {
 39              Auto<DisposableBuffer> autoBuffer;
 40              int offset, size;
 41              IndexType type = _type;
 42              bool mirrorable = false;
 43  
 44              if (_type == IndexType.Uint8Ext && !gd.Capabilities.SupportsIndexTypeUint8)
 45              {
 46                  // Index type is not supported. Convert to I16.
 47                  autoBuffer = gd.BufferManager.GetBufferI8ToI16(cbs, _handle, _offset, _size);
 48  
 49                  type = IndexType.Uint16;
 50                  offset = 0;
 51                  size = _size * 2;
 52              }
 53              else
 54              {
 55                  autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int bufferSize);
 56  
 57                  if (_offset >= bufferSize)
 58                  {
 59                      autoBuffer = null;
 60                  }
 61  
 62                  mirrorable = _size < IndexBufferMaxMirrorable;
 63  
 64                  offset = _offset;
 65                  size = _size;
 66              }
 67  
 68              _buffer = autoBuffer;
 69  
 70              if (autoBuffer != null)
 71              {
 72                  DisposableBuffer buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, size, out _) : autoBuffer.Get(cbs, offset, size);
 73  
 74                  gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, buffer.Value, (ulong)offset, type);
 75              }
 76          }
 77  
 78          public void BindConvertedIndexBuffer(
 79              VulkanRenderer gd,
 80              CommandBufferScoped cbs,
 81              int firstIndex,
 82              int indexCount,
 83              int convertedCount,
 84              IndexBufferPattern pattern)
 85          {
 86              Auto<DisposableBuffer> autoBuffer;
 87  
 88              // Convert the index buffer using the given pattern.
 89              int indexSize = GetIndexSize();
 90  
 91              int firstIndexOffset = firstIndex * indexSize;
 92  
 93              autoBuffer = gd.BufferManager.GetBufferTopologyConversion(cbs, _handle, _offset + firstIndexOffset, indexCount * indexSize, pattern, indexSize);
 94  
 95              int size = convertedCount * 4;
 96  
 97              _buffer = autoBuffer;
 98  
 99              if (autoBuffer != null)
100              {
101                  gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, autoBuffer.Get(cbs, 0, size).Value, 0, IndexType.Uint32);
102              }
103          }
104  
105          public Auto<DisposableBuffer> BindConvertedIndexBufferIndirect(
106              VulkanRenderer gd,
107              CommandBufferScoped cbs,
108              BufferRange indirectBuffer,
109              BufferRange drawCountBuffer,
110              IndexBufferPattern pattern,
111              bool hasDrawCount,
112              int maxDrawCount,
113              int indirectDataStride)
114          {
115              // Convert the index buffer using the given pattern.
116              int indexSize = GetIndexSize();
117  
118              (var indexBufferAuto, var indirectBufferAuto) = gd.BufferManager.GetBufferTopologyConversionIndirect(
119                  gd,
120                  cbs,
121                  new BufferRange(_handle, _offset, _size),
122                  indirectBuffer,
123                  drawCountBuffer,
124                  pattern,
125                  indexSize,
126                  hasDrawCount,
127                  maxDrawCount,
128                  indirectDataStride);
129  
130              int convertedCount = pattern.GetConvertedCount(_size / indexSize);
131              int size = convertedCount * 4;
132  
133              _buffer = indexBufferAuto;
134  
135              if (indexBufferAuto != null)
136              {
137                  gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, indexBufferAuto.Get(cbs, 0, size).Value, 0, IndexType.Uint32);
138              }
139  
140              return indirectBufferAuto;
141          }
142  
143          private readonly int GetIndexSize()
144          {
145              return _type switch
146              {
147                  IndexType.Uint32 => 4,
148                  IndexType.Uint16 => 2,
149                  _ => 1,
150              };
151          }
152  
153          public readonly bool BoundEquals(Auto<DisposableBuffer> buffer)
154          {
155              return _buffer == buffer;
156          }
157  
158          public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
159          {
160              if (_buffer == from)
161              {
162                  _buffer = to;
163              }
164          }
165  
166          public readonly bool Overlaps(Auto<DisposableBuffer> buffer, int offset, int size)
167          {
168              return buffer == _buffer && offset < _offset + _size && offset + size > _offset;
169          }
170      }
171  }