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 }