/ src / Ryujinx.Graphics.Vulkan / VertexBufferState.cs
VertexBufferState.cs
  1  using Ryujinx.Graphics.GAL;
  2  
  3  namespace Ryujinx.Graphics.Vulkan
  4  {
  5      internal struct VertexBufferState
  6      {
  7          private const int VertexBufferMaxMirrorable = 0x20000;
  8  
  9          public static VertexBufferState Null => new(null, 0, 0, 0);
 10  
 11          private readonly int _offset;
 12          private readonly int _size;
 13          private readonly int _stride;
 14  
 15          private readonly BufferHandle _handle;
 16          private Auto<DisposableBuffer> _buffer;
 17  
 18          internal readonly int DescriptorIndex;
 19          internal int AttributeScalarAlignment;
 20  
 21          public VertexBufferState(Auto<DisposableBuffer> buffer, int descriptorIndex, int offset, int size, int stride = 0)
 22          {
 23              _buffer = buffer;
 24              _handle = BufferHandle.Null;
 25  
 26              _offset = offset;
 27              _size = size;
 28              _stride = stride;
 29  
 30              DescriptorIndex = descriptorIndex;
 31              AttributeScalarAlignment = 1;
 32  
 33              buffer?.IncrementReferenceCount();
 34          }
 35  
 36          public VertexBufferState(BufferHandle handle, int descriptorIndex, int offset, int size, int stride = 0)
 37          {
 38              // This buffer state may be rewritten at bind time, so it must be retrieved on bind.
 39  
 40              _buffer = null;
 41              _handle = handle;
 42  
 43              _offset = offset;
 44              _size = size;
 45              _stride = stride;
 46  
 47              DescriptorIndex = descriptorIndex;
 48              AttributeScalarAlignment = 1;
 49          }
 50  
 51          public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding, ref PipelineState state, VertexBufferUpdater updater)
 52          {
 53              var autoBuffer = _buffer;
 54  
 55              if (_handle != BufferHandle.Null)
 56              {
 57                  // May need to restride the vertex buffer.
 58  
 59                  if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0)
 60                  {
 61                      autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment);
 62  
 63                      if (autoBuffer != null)
 64                      {
 65                          int stride = (_stride + (alignment - 1)) & -alignment;
 66                          int newSize = (_size / _stride) * stride;
 67  
 68                          var buffer = autoBuffer.Get(cbs, 0, newSize).Value;
 69  
 70                          updater.BindVertexBuffer(cbs, binding, buffer, 0, (ulong)newSize, (ulong)stride);
 71  
 72                          _buffer = autoBuffer;
 73  
 74                          state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
 75                      }
 76  
 77                      return;
 78                  }
 79  
 80                  autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
 81  
 82                  // The original stride must be reapplied in case it was rewritten.
 83                  state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
 84  
 85                  if (_offset >= size)
 86                  {
 87                      autoBuffer = null;
 88                  }
 89              }
 90  
 91              if (autoBuffer != null)
 92              {
 93                  int offset = _offset;
 94                  bool mirrorable = _size <= VertexBufferMaxMirrorable;
 95                  var buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, _size, out _).Value : autoBuffer.Get(cbs, offset, _size).Value;
 96  
 97                  updater.BindVertexBuffer(cbs, binding, buffer, (ulong)offset, (ulong)_size, (ulong)_stride);
 98              }
 99          }
100  
101          public readonly bool BoundEquals(Auto<DisposableBuffer> buffer)
102          {
103              return _buffer == buffer;
104          }
105  
106          public readonly bool Overlaps(Auto<DisposableBuffer> buffer, int offset, int size)
107          {
108              return buffer == _buffer && offset < _offset + _size && offset + size > _offset;
109          }
110  
111          public readonly bool Matches(Auto<DisposableBuffer> buffer, int descriptorIndex, int offset, int size, int stride = 0)
112          {
113              return _buffer == buffer && DescriptorIndex == descriptorIndex && _offset == offset && _size == size && _stride == stride;
114          }
115  
116          public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
117          {
118              if (_buffer == from)
119              {
120                  _buffer.DecrementReferenceCount();
121                  to.IncrementReferenceCount();
122  
123                  _buffer = to;
124              }
125          }
126  
127          public readonly void Dispose()
128          {
129              // Only dispose if this buffer is not refetched on each bind.
130  
131              if (_handle == BufferHandle.Null)
132              {
133                  _buffer?.DecrementReferenceCount();
134              }
135          }
136      }
137  }