/ src / Ryujinx.Graphics.Vic / Image / BufferPool.cs
BufferPool.cs
  1  using System;
  2  
  3  namespace Ryujinx.Graphics.Vic.Image
  4  {
  5      class BufferPool<T>
  6      {
  7          /// <summary>
  8          /// Maximum number of buffers on the pool.
  9          /// </summary>
 10          private const int MaxBuffers = 4;
 11  
 12          /// <summary>
 13          /// Maximum size of a buffer that can be added on the pool.
 14          /// If the required buffer is larger than this, it won't be
 15          /// added to the pool to avoid long term high memory usage.
 16          /// </summary>
 17          private const int MaxBufferSize = 2048 * 2048;
 18  
 19          private struct PoolItem
 20          {
 21              public bool InUse;
 22              public T[] Buffer;
 23          }
 24  
 25          private readonly PoolItem[] _pool = new PoolItem[MaxBuffers];
 26  
 27          /// <summary>
 28          /// Rents a buffer with the exact size requested.
 29          /// </summary>
 30          /// <param name="length">Size of the buffer</param>
 31          /// <param name="buffer">Span of the requested size</param>
 32          /// <returns>The index of the buffer on the pool</returns>
 33          public int Rent(int length, out Span<T> buffer)
 34          {
 35              int index = RentMinimum(length, out T[] bufferArray);
 36  
 37              buffer = new Span<T>(bufferArray)[..length];
 38  
 39              return index;
 40          }
 41  
 42          /// <summary>
 43          /// Rents a buffer with a size greater than or equal to the requested size.
 44          /// </summary>
 45          /// <param name="length">Size of the buffer</param>
 46          /// <param name="buffer">Array with a length greater than or equal to the requested length</param>
 47          /// <returns>The index of the buffer on the pool</returns>
 48          public int RentMinimum(int length, out T[] buffer)
 49          {
 50              if ((uint)length > MaxBufferSize)
 51              {
 52                  buffer = new T[length];
 53                  return -1;
 54              }
 55  
 56              // Try to find a buffer that is larger or the same size of the requested one.
 57              // This will avoid an allocation.
 58              for (int i = 0; i < MaxBuffers; i++)
 59              {
 60                  ref PoolItem item = ref _pool[i];
 61  
 62                  if (!item.InUse && item.Buffer != null && item.Buffer.Length >= length)
 63                  {
 64                      buffer = item.Buffer;
 65                      item.InUse = true;
 66                      return i;
 67                  }
 68              }
 69  
 70              buffer = new T[length];
 71  
 72              // Try to add the new buffer to the pool.
 73              // We try to find a slot that is not in use, and replace the buffer in it.
 74              for (int i = 0; i < MaxBuffers; i++)
 75              {
 76                  ref PoolItem item = ref _pool[i];
 77  
 78                  if (!item.InUse)
 79                  {
 80                      item.Buffer = buffer;
 81                      item.InUse = true;
 82                      return i;
 83                  }
 84              }
 85  
 86              return -1;
 87          }
 88  
 89          /// <summary>
 90          /// Returns a buffer returned from <see cref="Rent(int)"/> to the pool.
 91          /// </summary>
 92          /// <param name="index">Index of the buffer on the pool</param>
 93          public void Return(int index)
 94          {
 95              if (index < 0)
 96              {
 97                  return;
 98              }
 99  
100              _pool[index].InUse = false;
101          }
102      }
103  }