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 }