/ src / Ryujinx.Graphics.Gpu / Shader / GpuAccessor.cs
GpuAccessor.cs
  1  using Ryujinx.Common.Logging;
  2  using Ryujinx.Graphics.Gpu.Image;
  3  using Ryujinx.Graphics.Shader;
  4  using Ryujinx.Graphics.Shader.Translation;
  5  using System;
  6  using System.Runtime.InteropServices;
  7  
  8  namespace Ryujinx.Graphics.Gpu.Shader
  9  {
 10      /// <summary>
 11      /// Represents a GPU state and memory accessor.
 12      /// </summary>
 13      class GpuAccessor : GpuAccessorBase, IGpuAccessor
 14      {
 15          private readonly GpuChannel _channel;
 16          private readonly GpuAccessorState _state;
 17          private readonly int _stageIndex;
 18          private readonly bool _compute;
 19          private readonly bool _isVulkan;
 20          private readonly bool _hasGeometryShader;
 21          private readonly bool _supportsQuads;
 22  
 23          /// <summary>
 24          /// Creates a new instance of the GPU state accessor for graphics shader translation.
 25          /// </summary>
 26          /// <param name="context">GPU context</param>
 27          /// <param name="channel">GPU channel</param>
 28          /// <param name="state">Current GPU state</param>
 29          /// <param name="stageIndex">Graphics shader stage index (0 = Vertex, 4 = Fragment)</param>
 30          /// <param name="hasGeometryShader">Indicates if a geometry shader is present</param>
 31          public GpuAccessor(
 32              GpuContext context,
 33              GpuChannel channel,
 34              GpuAccessorState state,
 35              int stageIndex,
 36              bool hasGeometryShader) : base(context, state.ResourceCounts, stageIndex)
 37          {
 38              _channel = channel;
 39              _state = state;
 40              _stageIndex = stageIndex;
 41              _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
 42              _hasGeometryShader = hasGeometryShader;
 43              _supportsQuads = context.Capabilities.SupportsQuads;
 44  
 45              if (stageIndex == (int)ShaderStage.Geometry - 1)
 46              {
 47                  // Only geometry shaders require the primitive topology.
 48                  _state.SpecializationState.RecordPrimitiveTopology();
 49              }
 50          }
 51  
 52          /// <summary>
 53          /// Creates a new instance of the GPU state accessor for compute shader translation.
 54          /// </summary>
 55          /// <param name="context">GPU context</param>
 56          /// <param name="channel">GPU channel</param>
 57          /// <param name="state">Current GPU state</param>
 58          public GpuAccessor(GpuContext context, GpuChannel channel, GpuAccessorState state) : base(context, state.ResourceCounts, 0)
 59          {
 60              _channel = channel;
 61              _state = state;
 62              _compute = true;
 63          }
 64  
 65          /// <inheritdoc/>
 66          public uint ConstantBuffer1Read(int offset)
 67          {
 68              ulong baseAddress = _compute
 69                  ? _channel.BufferManager.GetComputeUniformBufferAddress(1)
 70                  : _channel.BufferManager.GetGraphicsUniformBufferAddress(_stageIndex, 1);
 71  
 72              return _channel.MemoryManager.Physical.Read<uint>(baseAddress + (ulong)offset);
 73          }
 74  
 75          /// <inheritdoc/>
 76          public void Log(string message)
 77          {
 78              Logger.Warning?.Print(LogClass.Gpu, $"Shader translator: {message}");
 79          }
 80  
 81          /// <inheritdoc/>
 82          public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize)
 83          {
 84              int size = Math.Max(minimumSize, 0x1000 - (int)(address & 0xfff));
 85  
 86              return MemoryMarshal.Cast<byte, ulong>(_channel.MemoryManager.GetSpan(address, size));
 87          }
 88  
 89          /// <inheritdoc/>
 90          public int QueryComputeLocalSizeX() => _state.ComputeState.LocalSizeX;
 91  
 92          /// <inheritdoc/>
 93          public int QueryComputeLocalSizeY() => _state.ComputeState.LocalSizeY;
 94  
 95          /// <inheritdoc/>
 96          public int QueryComputeLocalSizeZ() => _state.ComputeState.LocalSizeZ;
 97  
 98          /// <inheritdoc/>
 99          public int QueryComputeLocalMemorySize() => _state.ComputeState.LocalMemorySize;
100  
101          /// <inheritdoc/>
102          public int QueryComputeSharedMemorySize() => _state.ComputeState.SharedMemorySize;
103  
104          /// <inheritdoc/>
105          public uint QueryConstantBufferUse()
106          {
107              uint useMask = _compute
108                  ? _channel.BufferManager.GetComputeUniformBufferUseMask()
109                  : _channel.BufferManager.GetGraphicsUniformBufferUseMask(_stageIndex);
110  
111              _state.SpecializationState?.RecordConstantBufferUse(_stageIndex, useMask);
112              return useMask;
113          }
114  
115          /// <inheritdoc/>
116          public GpuGraphicsState QueryGraphicsState()
117          {
118              return _state.GraphicsState.CreateShaderGraphicsState(
119                  !_isVulkan,
120                  _supportsQuads,
121                  _hasGeometryShader,
122                  _isVulkan || _state.GraphicsState.YNegateEnabled);
123          }
124  
125          /// <inheritdoc/>
126          public bool QueryHasConstantBufferDrawParameters()
127          {
128              return _state.GraphicsState.HasConstantBufferDrawParameters;
129          }
130  
131          /// <inheritdoc/>
132          public bool QueryHasUnalignedStorageBuffer()
133          {
134              return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer;
135          }
136  
137          /// <inheritdoc/>
138          public int QuerySamplerArrayLengthFromPool()
139          {
140              int length = _state.SamplerPoolMaximumId + 1;
141              _state.SpecializationState?.RegisterTextureArrayLengthFromPool(isSampler: true, length);
142  
143              return length;
144          }
145  
146          /// <inheritdoc/>
147          public SamplerType QuerySamplerType(int handle, int cbufSlot)
148          {
149              _state.SpecializationState?.RecordTextureSamplerType(_stageIndex, handle, cbufSlot);
150              return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget().ConvertSamplerType();
151          }
152  
153          /// <inheritdoc/>
154          public int QueryTextureArrayLengthFromBuffer(int slot)
155          {
156              int size = _compute
157                  ? _channel.BufferManager.GetComputeUniformBufferSize(slot)
158                  : _channel.BufferManager.GetGraphicsUniformBufferSize(_stageIndex, slot);
159  
160              int arrayLength = size / Constants.TextureHandleSizeInBytes;
161  
162              _state.SpecializationState?.RegisterTextureArrayLengthFromBuffer(_stageIndex, 0, slot, arrayLength);
163  
164              return arrayLength;
165          }
166  
167          /// <inheritdoc/>
168          public int QueryTextureArrayLengthFromPool()
169          {
170              int length = _state.PoolState.TexturePoolMaximumId + 1;
171              _state.SpecializationState?.RegisterTextureArrayLengthFromPool(isSampler: false, length);
172  
173              return length;
174          }
175  
176          //// <inheritdoc/>
177          public TextureFormat QueryTextureFormat(int handle, int cbufSlot)
178          {
179              _state.SpecializationState?.RecordTextureFormat(_stageIndex, handle, cbufSlot);
180              var descriptor = GetTextureDescriptor(handle, cbufSlot);
181              return ConvertToTextureFormat(descriptor.UnpackFormat(), descriptor.UnpackSrgb());
182          }
183  
184          /// <inheritdoc/>
185          public bool QueryTextureCoordNormalized(int handle, int cbufSlot)
186          {
187              _state.SpecializationState?.RecordTextureCoordNormalized(_stageIndex, handle, cbufSlot);
188              return GetTextureDescriptor(handle, cbufSlot).UnpackTextureCoordNormalized();
189          }
190  
191          /// <summary>
192          /// Gets the texture descriptor for a given texture on the pool.
193          /// </summary>
194          /// <param name="handle">Index of the texture (this is the word offset of the handle in the constant buffer)</param>
195          /// <param name="cbufSlot">Constant buffer slot for the texture handle</param>
196          /// <returns>Texture descriptor</returns>
197          private Image.TextureDescriptor GetTextureDescriptor(int handle, int cbufSlot)
198          {
199              if (_compute)
200              {
201                  return _channel.TextureManager.GetComputeTextureDescriptor(
202                      _state.PoolState.TexturePoolGpuVa,
203                      _state.PoolState.TextureBufferIndex,
204                      _state.PoolState.TexturePoolMaximumId,
205                      handle,
206                      cbufSlot);
207              }
208              else
209              {
210                  return _channel.TextureManager.GetGraphicsTextureDescriptor(
211                      _state.PoolState.TexturePoolGpuVa,
212                      _state.PoolState.TextureBufferIndex,
213                      _state.PoolState.TexturePoolMaximumId,
214                      _stageIndex,
215                      handle,
216                      cbufSlot);
217              }
218          }
219  
220          /// <inheritdoc/>
221          public bool QueryTransformFeedbackEnabled()
222          {
223              return _state.TransformFeedbackDescriptors != null;
224          }
225  
226          /// <inheritdoc/>
227          public ReadOnlySpan<byte> QueryTransformFeedbackVaryingLocations(int bufferIndex)
228          {
229              return _state.TransformFeedbackDescriptors[bufferIndex].AsSpan();
230          }
231  
232          /// <inheritdoc/>
233          public int QueryTransformFeedbackStride(int bufferIndex)
234          {
235              return _state.TransformFeedbackDescriptors[bufferIndex].Stride;
236          }
237  
238          /// <inheritdoc/>
239          public void RegisterTexture(int handle, int cbufSlot)
240          {
241              _state.SpecializationState?.RegisterTexture(_stageIndex, handle, cbufSlot, GetTextureDescriptor(handle, cbufSlot));
242          }
243      }
244  }