/ src / Ryujinx.Graphics.Shader / Translation / ResourceReservations.cs
ResourceReservations.cs
  1  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2  using Ryujinx.Graphics.Shader.StructuredIr;
  3  using System.Collections.Generic;
  4  using System.Numerics;
  5  
  6  namespace Ryujinx.Graphics.Shader.Translation
  7  {
  8      public class ResourceReservations
  9      {
 10          public const int TfeBuffersCount = 4;
 11  
 12          public const int MaxVertexBufferTextures = 32;
 13  
 14          private const int TextureSetIndex = 2; // TODO: Get from GPU accessor.
 15  
 16          public int VertexInfoConstantBufferBinding { get; }
 17          public int VertexOutputStorageBufferBinding { get; }
 18          public int GeometryVertexOutputStorageBufferBinding { get; }
 19          public int GeometryIndexOutputStorageBufferBinding { get; }
 20          public int IndexBufferTextureBinding { get; }
 21          public int TopologyRemapBufferTextureBinding { get; }
 22  
 23          public int ReservedConstantBuffers { get; }
 24          public int ReservedStorageBuffers { get; }
 25          public int ReservedTextures { get; }
 26          public int ReservedImages { get; }
 27          public int InputSizePerInvocation { get; }
 28          public int OutputSizePerInvocation { get; }
 29          public int OutputSizeInBytesPerInvocation => OutputSizePerInvocation * sizeof(uint);
 30  
 31          private readonly int _tfeBufferSbBaseBinding;
 32          private readonly int _vertexBufferTextureBaseBinding;
 33  
 34          private readonly Dictionary<IoDefinition, int> _offsets;
 35          internal IReadOnlyDictionary<IoDefinition, int> Offsets => _offsets;
 36  
 37          internal ResourceReservations(bool isTransformFeedbackEmulated, bool vertexAsCompute)
 38          {
 39              // All stages reserves the first constant buffer binding for the support buffer.
 40              ReservedConstantBuffers = 1;
 41              ReservedStorageBuffers = 0;
 42              ReservedTextures = 0;
 43              ReservedImages = 0;
 44  
 45              if (isTransformFeedbackEmulated)
 46              {
 47                  // Transform feedback emulation currently always uses 4 storage buffers.
 48                  _tfeBufferSbBaseBinding = ReservedStorageBuffers;
 49                  ReservedStorageBuffers = TfeBuffersCount;
 50              }
 51  
 52              if (vertexAsCompute)
 53              {
 54                  // One constant buffer reserved for vertex related state.
 55                  VertexInfoConstantBufferBinding = ReservedConstantBuffers++;
 56  
 57                  // One storage buffer for the output vertex data.
 58                  VertexOutputStorageBufferBinding = ReservedStorageBuffers++;
 59  
 60                  // One storage buffer for the output geometry vertex data.
 61                  GeometryVertexOutputStorageBufferBinding = ReservedStorageBuffers++;
 62  
 63                  // One storage buffer for the output geometry index data.
 64                  GeometryIndexOutputStorageBufferBinding = ReservedStorageBuffers++;
 65  
 66                  // Enough textures reserved for all vertex attributes, plus the index buffer.
 67                  IndexBufferTextureBinding = ReservedTextures;
 68                  TopologyRemapBufferTextureBinding = ReservedTextures + 1;
 69                  _vertexBufferTextureBaseBinding = ReservedTextures + 2;
 70                  ReservedTextures += 2 + MaxVertexBufferTextures;
 71              }
 72          }
 73  
 74          internal ResourceReservations(
 75              IGpuAccessor gpuAccessor,
 76              bool isTransformFeedbackEmulated,
 77              bool vertexAsCompute,
 78              IoUsage? vacInput,
 79              IoUsage vacOutput) : this(isTransformFeedbackEmulated, vertexAsCompute)
 80          {
 81              if (vertexAsCompute)
 82              {
 83                  _offsets = new();
 84  
 85                  if (vacInput.HasValue)
 86                  {
 87                      InputSizePerInvocation = FillIoOffsetMap(gpuAccessor, StorageKind.Input, vacInput.Value);
 88                  }
 89  
 90                  OutputSizePerInvocation = FillIoOffsetMap(gpuAccessor, StorageKind.Output, vacOutput);
 91              }
 92          }
 93  
 94          private int FillIoOffsetMap(IGpuAccessor gpuAccessor, StorageKind storageKind, IoUsage vacUsage)
 95          {
 96              int offset = 0;
 97  
 98              for (int c = 0; c < 4; c++)
 99              {
100                  _offsets.Add(new IoDefinition(storageKind, IoVariable.Position, 0, c), offset++);
101              }
102  
103              _offsets.Add(new IoDefinition(storageKind, IoVariable.PointSize), offset++);
104  
105              int clipDistancesWrittenMap = vacUsage.ClipDistancesWritten;
106  
107              while (clipDistancesWrittenMap != 0)
108              {
109                  int index = BitOperations.TrailingZeroCount(clipDistancesWrittenMap);
110  
111                  _offsets.Add(new IoDefinition(storageKind, IoVariable.ClipDistance, 0, index), offset++);
112  
113                  clipDistancesWrittenMap &= ~(1 << index);
114              }
115  
116              if (vacUsage.UsesRtLayer)
117              {
118                  _offsets.Add(new IoDefinition(storageKind, IoVariable.Layer), offset++);
119              }
120  
121              if (vacUsage.UsesViewportIndex && gpuAccessor.QueryHostSupportsViewportIndexVertexTessellation())
122              {
123                  _offsets.Add(new IoDefinition(storageKind, IoVariable.VertexIndex), offset++);
124              }
125  
126              if (vacUsage.UsesViewportMask && gpuAccessor.QueryHostSupportsViewportMask())
127              {
128                  _offsets.Add(new IoDefinition(storageKind, IoVariable.ViewportMask), offset++);
129              }
130  
131              int usedDefinedMap = vacUsage.UserDefinedMap;
132  
133              while (usedDefinedMap != 0)
134              {
135                  int location = BitOperations.TrailingZeroCount(usedDefinedMap);
136  
137                  for (int c = 0; c < 4; c++)
138                  {
139                      _offsets.Add(new IoDefinition(storageKind, IoVariable.UserDefined, location, c), offset++);
140                  }
141  
142                  usedDefinedMap &= ~(1 << location);
143              }
144  
145              return offset;
146          }
147  
148          internal static bool IsVectorOrArrayVariable(IoVariable variable)
149          {
150              return variable switch
151              {
152                  IoVariable.ClipDistance or
153                  IoVariable.Position => true,
154                  _ => false,
155              };
156          }
157  
158          public int GetTfeBufferStorageBufferBinding(int bufferIndex)
159          {
160              return _tfeBufferSbBaseBinding + bufferIndex;
161          }
162  
163          public int GetVertexBufferTextureBinding(int vaLocation)
164          {
165              return _vertexBufferTextureBaseBinding + vaLocation;
166          }
167  
168          public SetBindingPair GetVertexBufferTextureSetAndBinding(int vaLocation)
169          {
170              return new SetBindingPair(TextureSetIndex, GetVertexBufferTextureBinding(vaLocation));
171          }
172  
173          public SetBindingPair GetIndexBufferTextureSetAndBinding()
174          {
175              return new SetBindingPair(TextureSetIndex, IndexBufferTextureBinding);
176          }
177  
178          public SetBindingPair GetTopologyRemapBufferTextureSetAndBinding()
179          {
180              return new SetBindingPair(TextureSetIndex, TopologyRemapBufferTextureBinding);
181          }
182  
183          internal bool TryGetOffset(StorageKind storageKind, int location, int component, out int offset)
184          {
185              return _offsets.TryGetValue(new IoDefinition(storageKind, IoVariable.UserDefined, location, component), out offset);
186          }
187  
188          internal bool TryGetOffset(StorageKind storageKind, IoVariable ioVariable, int location, int component, out int offset)
189          {
190              return _offsets.TryGetValue(new IoDefinition(storageKind, ioVariable, location, component), out offset);
191          }
192  
193          internal bool TryGetOffset(StorageKind storageKind, IoVariable ioVariable, int component, out int offset)
194          {
195              return _offsets.TryGetValue(new IoDefinition(storageKind, ioVariable, 0, component), out offset);
196          }
197  
198          internal bool TryGetOffset(StorageKind storageKind, IoVariable ioVariable, out int offset)
199          {
200              return _offsets.TryGetValue(new IoDefinition(storageKind, ioVariable, 0, 0), out offset);
201          }
202      }
203  }