aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs346
1 files changed, 346 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
new file mode 100644
index 00000000..a8af5497
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
@@ -0,0 +1,346 @@
+using Ryujinx.Common.Memory;
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.Types;
+using Ryujinx.Graphics.Gpu.Shader;
+using Ryujinx.Graphics.Shader;
+
+namespace Ryujinx.Graphics.Gpu.Engine.Threed
+{
+ /// <summary>
+ /// Maintains a "current" specialiation state, and provides a flag to check if it has changed meaningfully.
+ /// </summary>
+ internal class SpecializationStateUpdater
+ {
+ private readonly GpuContext _context;
+ private GpuChannelGraphicsState _graphics;
+ private GpuChannelPoolState _pool;
+
+ private bool _usesDrawParameters;
+ private bool _usesTopology;
+
+ private bool _changed;
+
+ /// <summary>
+ /// Creates a new instance of the specialization state updater class.
+ /// </summary>
+ /// <param name="context">GPU context</param>
+ public SpecializationStateUpdater(GpuContext context)
+ {
+ _context = context;
+ }
+
+ /// <summary>
+ /// Signal that the specialization state has changed.
+ /// </summary>
+ private void Signal()
+ {
+ _changed = true;
+ }
+
+ /// <summary>
+ /// Checks if the specialization state has changed since the last check.
+ /// </summary>
+ /// <returns>True if it has changed, false otherwise</returns>
+ public bool HasChanged()
+ {
+ if (_changed)
+ {
+ _changed = false;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Sets the active shader, clearing the dirty state and recording if certain specializations are noteworthy.
+ /// </summary>
+ /// <param name="gs">The active shader</param>
+ public void SetShader(CachedShaderProgram gs)
+ {
+ _usesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
+ _usesTopology = gs.SpecializationState.IsPrimitiveTopologyQueried();
+
+ _changed = false;
+ }
+
+ /// <summary>
+ /// Get the current graphics state.
+ /// </summary>
+ /// <returns>GPU graphics state</returns>
+ public ref GpuChannelGraphicsState GetGraphicsState()
+ {
+ return ref _graphics;
+ }
+
+ /// <summary>
+ /// Get the current pool state.
+ /// </summary>
+ /// <returns>GPU pool state</returns>
+ public ref GpuChannelPoolState GetPoolState()
+ {
+ return ref _pool;
+ }
+
+ /// <summary>
+ /// Early Z force enable.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetEarlyZForce(bool value)
+ {
+ _graphics.EarlyZForce = value;
+
+ Signal();
+ }
+
+ /// <summary>
+ /// Primitive topology of current draw.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetTopology(PrimitiveTopology value)
+ {
+ if (value != _graphics.Topology)
+ {
+ _graphics.Topology = value;
+
+ if (_usesTopology)
+ {
+ Signal();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Tessellation mode.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetTessellationMode(TessMode value)
+ {
+ if (value.Packed != _graphics.TessellationMode.Packed)
+ {
+ _graphics.TessellationMode = value;
+
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Updates alpha-to-coverage state, and sets it as changed.
+ /// </summary>
+ /// <param name="enable">Whether alpha-to-coverage is enabled</param>
+ /// <param name="ditherEnable">Whether alpha-to-coverage dithering is enabled</param>
+ public void SetAlphaToCoverageEnable(bool enable, bool ditherEnable)
+ {
+ _graphics.AlphaToCoverageEnable = enable;
+ _graphics.AlphaToCoverageDitherEnable = ditherEnable;
+
+ Signal();
+ }
+
+ /// <summary>
+ /// Indicates whether the viewport transform is disabled.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetViewportTransformDisable(bool value)
+ {
+ if (value != _graphics.ViewportTransformDisable)
+ {
+ _graphics.ViewportTransformDisable = value;
+
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Depth mode zero to one or minus one to one.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetDepthMode(bool value)
+ {
+ if (value != _graphics.DepthMode)
+ {
+ _graphics.DepthMode = value;
+
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Indicates if the point size is set on the shader or is fixed.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetProgramPointSizeEnable(bool value)
+ {
+ if (value != _graphics.ProgramPointSizeEnable)
+ {
+ _graphics.ProgramPointSizeEnable = value;
+
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Point size used if <see cref="SetProgramPointSizeEnable" /> is provided false.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetPointSize(float value)
+ {
+ if (value != _graphics.PointSize)
+ {
+ _graphics.PointSize = value;
+
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Updates alpha test specialization state, and sets it as changed.
+ /// </summary>
+ /// <param name="enable">Whether alpha test is enabled</param>
+ /// <param name="reference">The value to compare with the fragment output alpha</param>
+ /// <param name="op">The comparison that decides if the fragment should be discarded</param>
+ public void SetAlphaTest(bool enable, float reference, CompareOp op)
+ {
+ _graphics.AlphaTestEnable = enable;
+ _graphics.AlphaTestReference = reference;
+ _graphics.AlphaTestCompare = op;
+
+ Signal();
+ }
+
+ /// <summary>
+ /// Updates the type of the vertex attributes consumed by the shader.
+ /// </summary>
+ /// <param name="state">The new state</param>
+ public void SetAttributeTypes(ref Array32<VertexAttribState> state)
+ {
+ bool changed = false;
+ ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
+
+ for (int location = 0; location < state.Length; location++)
+ {
+ VertexAttribType type = state[location].UnpackType();
+
+ AttributeType value = type switch
+ {
+ VertexAttribType.Sint => AttributeType.Sint,
+ VertexAttribType.Uint => AttributeType.Uint,
+ _ => AttributeType.Float
+ };
+
+ if (attributeTypes[location] != value)
+ {
+ attributeTypes[location] = value;
+ changed = true;
+ }
+ }
+
+ if (changed)
+ {
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Updates the type of the outputs produced by the fragment shader based on the current render target state.
+ /// </summary>
+ /// <param name="rtControl">The render target control register</param>
+ /// <param name="state">The color attachment state</param>
+ public void SetFragmentOutputTypes(RtControl rtControl, ref Array8<RtColorState> state)
+ {
+ bool changed = false;
+ int count = rtControl.UnpackCount();
+
+ for (int index = 0; index < Constants.TotalRenderTargets; index++)
+ {
+ int rtIndex = rtControl.UnpackPermutationIndex(index);
+
+ var colorState = state[rtIndex];
+
+ if (index < count && StateUpdater.IsRtEnabled(colorState))
+ {
+ Format format = colorState.Format.Convert().Format;
+
+ AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
+
+ if (type != _graphics.FragmentOutputTypes[index])
+ {
+ _graphics.FragmentOutputTypes[index] = type;
+ changed = true;
+ }
+ }
+ }
+
+ if (changed && _context.Capabilities.NeedsFragmentOutputSpecialization)
+ {
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ public void SetHasConstantBufferDrawParameters(bool value)
+ {
+ if (value != _graphics.HasConstantBufferDrawParameters)
+ {
+ _graphics.HasConstantBufferDrawParameters = value;
+
+ if (_usesDrawParameters)
+ {
+ Signal();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Indicates that any storage buffer use is unaligned.
+ /// </summary>
+ /// <param name="value">The new value</param>
+ /// <returns>True if the unaligned state changed, false otherwise</returns>
+ public bool SetHasUnalignedStorageBuffer(bool value)
+ {
+ if (value != _graphics.HasUnalignedStorageBuffer)
+ {
+ _graphics.HasUnalignedStorageBuffer = value;
+
+ Signal();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Sets the GPU pool state.
+ /// </summary>
+ /// <param name="state">The new state</param>
+ public void SetPoolState(GpuChannelPoolState state)
+ {
+ if (!state.Equals(_pool))
+ {
+ _pool = state;
+
+ Signal();
+ }
+ }
+
+ /// <summary>
+ /// Sets the dual-source blend enabled state.
+ /// </summary>
+ /// <param name="enabled">True if blending is enabled and using dual-source blend</param>
+ public void SetDualSourceBlendEnabled(bool enabled)
+ {
+ if (enabled != _graphics.DualSourceBlendEnable)
+ {
+ _graphics.DualSourceBlendEnable = enabled;
+
+ Signal();
+ }
+ }
+ }
+}