aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
new file mode 100644
index 00000000..17639ca1
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
@@ -0,0 +1,266 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Shader;
+using Ryujinx.Graphics.Shader.Translation;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
+{
+ /// <summary>
+ /// Represents a GPU state and memory accessor.
+ /// </summary>
+ class DiskCacheGpuAccessor : GpuAccessorBase, IGpuAccessor
+ {
+ private readonly ReadOnlyMemory<byte> _data;
+ private readonly ReadOnlyMemory<byte> _cb1Data;
+ private readonly ShaderSpecializationState _oldSpecState;
+ private readonly ShaderSpecializationState _newSpecState;
+ private readonly int _stageIndex;
+ private readonly bool _isVulkan;
+ private readonly ResourceCounts _resourceCounts;
+
+ /// <summary>
+ /// Creates a new instance of the cached GPU state accessor for shader translation.
+ /// </summary>
+ /// <param name="context">GPU context</param>
+ /// <param name="data">The data of the shader</param>
+ /// <param name="cb1Data">The constant buffer 1 data of the shader</param>
+ /// <param name="oldSpecState">Shader specialization state of the cached shader</param>
+ /// <param name="newSpecState">Shader specialization state of the recompiled shader</param>
+ /// <param name="stageIndex">Shader stage index</param>
+ public DiskCacheGpuAccessor(
+ GpuContext context,
+ ReadOnlyMemory<byte> data,
+ ReadOnlyMemory<byte> cb1Data,
+ ShaderSpecializationState oldSpecState,
+ ShaderSpecializationState newSpecState,
+ ResourceCounts counts,
+ int stageIndex) : base(context, counts, stageIndex)
+ {
+ _data = data;
+ _cb1Data = cb1Data;
+ _oldSpecState = oldSpecState;
+ _newSpecState = newSpecState;
+ _stageIndex = stageIndex;
+ _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
+ _resourceCounts = counts;
+ }
+
+ /// <inheritdoc/>
+ public uint ConstantBuffer1Read(int offset)
+ {
+ if (offset + sizeof(uint) > _cb1Data.Length)
+ {
+ throw new DiskCacheLoadException(DiskCacheLoadResult.InvalidCb1DataLength);
+ }
+
+ return MemoryMarshal.Cast<byte, uint>(_cb1Data.Span.Slice(offset))[0];
+ }
+
+ /// <inheritdoc/>
+ public void Log(string message)
+ {
+ Logger.Warning?.Print(LogClass.Gpu, $"Shader translator: {message}");
+ }
+
+ /// <inheritdoc/>
+ public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize)
+ {
+ return MemoryMarshal.Cast<byte, ulong>(_data.Span.Slice((int)address));
+ }
+
+ /// <inheritdoc/>
+ public bool QueryAlphaToCoverageDitherEnable()
+ {
+ return _oldSpecState.GraphicsState.AlphaToCoverageEnable && _oldSpecState.GraphicsState.AlphaToCoverageDitherEnable;
+ }
+
+ /// <inheritdoc/>
+ public AlphaTestOp QueryAlphaTestCompare()
+ {
+ if (!_isVulkan || !_oldSpecState.GraphicsState.AlphaTestEnable)
+ {
+ return AlphaTestOp.Always;
+ }
+
+ return _oldSpecState.GraphicsState.AlphaTestCompare switch
+ {
+ CompareOp.Never or CompareOp.NeverGl => AlphaTestOp.Never,
+ CompareOp.Less or CompareOp.LessGl => AlphaTestOp.Less,
+ CompareOp.Equal or CompareOp.EqualGl => AlphaTestOp.Equal,
+ CompareOp.LessOrEqual or CompareOp.LessOrEqualGl => AlphaTestOp.LessOrEqual,
+ CompareOp.Greater or CompareOp.GreaterGl => AlphaTestOp.Greater,
+ CompareOp.NotEqual or CompareOp.NotEqualGl => AlphaTestOp.NotEqual,
+ CompareOp.GreaterOrEqual or CompareOp.GreaterOrEqualGl => AlphaTestOp.GreaterOrEqual,
+ _ => AlphaTestOp.Always
+ };
+ }
+
+ /// <inheritdoc/>
+ public float QueryAlphaTestReference() => _oldSpecState.GraphicsState.AlphaTestReference;
+
+ /// <inheritdoc/>
+ public AttributeType QueryAttributeType(int location)
+ {
+ return _oldSpecState.GraphicsState.AttributeTypes[location];
+ }
+
+ /// <inheritdoc/>
+ public AttributeType QueryFragmentOutputType(int location)
+ {
+ return _oldSpecState.GraphicsState.FragmentOutputTypes[location];
+ }
+
+ /// <inheritdoc/>
+ public int QueryComputeLocalSizeX() => _oldSpecState.ComputeState.LocalSizeX;
+
+ /// <inheritdoc/>
+ public int QueryComputeLocalSizeY() => _oldSpecState.ComputeState.LocalSizeY;
+
+ /// <inheritdoc/>
+ public int QueryComputeLocalSizeZ() => _oldSpecState.ComputeState.LocalSizeZ;
+
+ /// <inheritdoc/>
+ public int QueryComputeLocalMemorySize() => _oldSpecState.ComputeState.LocalMemorySize;
+
+ /// <inheritdoc/>
+ public int QueryComputeSharedMemorySize() => _oldSpecState.ComputeState.SharedMemorySize;
+
+ /// <inheritdoc/>
+ public uint QueryConstantBufferUse()
+ {
+ _newSpecState.RecordConstantBufferUse(_stageIndex, _oldSpecState.ConstantBufferUse[_stageIndex]);
+ return _oldSpecState.ConstantBufferUse[_stageIndex];
+ }
+
+ /// <inheritdoc/>
+ public bool QueryHasConstantBufferDrawParameters()
+ {
+ return _oldSpecState.GraphicsState.HasConstantBufferDrawParameters;
+ }
+
+ /// <inheritdoc/>
+ public bool QueryDualSourceBlendEnable()
+ {
+ return _oldSpecState.GraphicsState.DualSourceBlendEnable;
+ }
+
+ /// <inheritdoc/>
+ public InputTopology QueryPrimitiveTopology()
+ {
+ _newSpecState.RecordPrimitiveTopology();
+ return ConvertToInputTopology(_oldSpecState.GraphicsState.Topology, _oldSpecState.GraphicsState.TessellationMode);
+ }
+
+ /// <inheritdoc/>
+ public bool QueryProgramPointSize()
+ {
+ return _oldSpecState.GraphicsState.ProgramPointSizeEnable;
+ }
+
+ /// <inheritdoc/>
+ public float QueryPointSize()
+ {
+ return _oldSpecState.GraphicsState.PointSize;
+ }
+
+ /// <inheritdoc/>
+ public bool QueryTessCw()
+ {
+ return _oldSpecState.GraphicsState.TessellationMode.UnpackCw();
+ }
+
+ /// <inheritdoc/>
+ public TessPatchType QueryTessPatchType()
+ {
+ return _oldSpecState.GraphicsState.TessellationMode.UnpackPatchType();
+ }
+
+ /// <inheritdoc/>
+ public TessSpacing QueryTessSpacing()
+ {
+ return _oldSpecState.GraphicsState.TessellationMode.UnpackSpacing();
+ }
+
+ /// <inheritdoc/>
+ public TextureFormat QueryTextureFormat(int handle, int cbufSlot)
+ {
+ _newSpecState.RecordTextureFormat(_stageIndex, handle, cbufSlot);
+ (uint format, bool formatSrgb) = _oldSpecState.GetFormat(_stageIndex, handle, cbufSlot);
+ return ConvertToTextureFormat(format, formatSrgb);
+ }
+
+ /// <inheritdoc/>
+ public SamplerType QuerySamplerType(int handle, int cbufSlot)
+ {
+ _newSpecState.RecordTextureSamplerType(_stageIndex, handle, cbufSlot);
+ return _oldSpecState.GetTextureTarget(_stageIndex, handle, cbufSlot).ConvertSamplerType();
+ }
+
+ /// <inheritdoc/>
+ public bool QueryTextureCoordNormalized(int handle, int cbufSlot)
+ {
+ _newSpecState.RecordTextureCoordNormalized(_stageIndex, handle, cbufSlot);
+ return _oldSpecState.GetCoordNormalized(_stageIndex, handle, cbufSlot);
+ }
+
+ /// <inheritdoc/>
+ public bool QueryTransformDepthMinusOneToOne()
+ {
+ return _oldSpecState.GraphicsState.DepthMode;
+ }
+
+ /// <inheritdoc/>
+ public bool QueryTransformFeedbackEnabled()
+ {
+ return _oldSpecState.TransformFeedbackDescriptors != null;
+ }
+
+ /// <inheritdoc/>
+ public ReadOnlySpan<byte> QueryTransformFeedbackVaryingLocations(int bufferIndex)
+ {
+ return _oldSpecState.TransformFeedbackDescriptors[bufferIndex].AsSpan();
+ }
+
+ /// <inheritdoc/>
+ public int QueryTransformFeedbackStride(int bufferIndex)
+ {
+ return _oldSpecState.TransformFeedbackDescriptors[bufferIndex].Stride;
+ }
+
+ /// <inheritdoc/>
+ public bool QueryEarlyZForce()
+ {
+ _newSpecState.RecordEarlyZForce();
+ return _oldSpecState.GraphicsState.EarlyZForce;
+ }
+
+ /// <inheritdoc/>
+ public bool QueryHasUnalignedStorageBuffer()
+ {
+ return _oldSpecState.GraphicsState.HasUnalignedStorageBuffer || _oldSpecState.ComputeState.HasUnalignedStorageBuffer;
+ }
+
+ /// <inheritdoc/>
+ public bool QueryViewportTransformDisable()
+ {
+ return _oldSpecState.GraphicsState.ViewportTransformDisable;
+ }
+
+ /// <inheritdoc/>
+ public void RegisterTexture(int handle, int cbufSlot)
+ {
+ if (!_oldSpecState.TextureRegistered(_stageIndex, handle, cbufSlot))
+ {
+ throw new DiskCacheLoadException(DiskCacheLoadResult.MissingTextureDescriptor);
+ }
+
+ (uint format, bool formatSrgb) = _oldSpecState.GetFormat(_stageIndex, handle, cbufSlot);
+ TextureTarget target = _oldSpecState.GetTextureTarget(_stageIndex, handle, cbufSlot);
+ bool coordNormalized = _oldSpecState.GetCoordNormalized(_stageIndex, handle, cbufSlot);
+ _newSpecState.RegisterTexture(_stageIndex, handle, cbufSlot, format, formatSrgb, target, coordNormalized);
+ }
+ }
+}