aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs138
1 files changed, 67 insertions, 71 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index fe7e0d09..b611f4e7 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader;
@@ -16,9 +17,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
class StateUpdater
{
- public const int ShaderStateIndex = 16;
+ public const int ShaderStateIndex = 26;
public const int RasterizerStateIndex = 15;
- public const int ScissorStateIndex = 18;
+ public const int ScissorStateIndex = 16;
public const int VertexBufferStateIndex = 0;
public const int PrimitiveRestartStateIndex = 12;
@@ -31,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private readonly ShaderProgramInfo[] _currentProgramInfo;
private ShaderSpecializationState _shaderSpecState;
+ private SpecializationStateUpdater _currentSpecState;
private ProgramPipelineState _pipeline;
@@ -54,15 +56,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="channel">GPU channel</param>
/// <param name="state">3D engine state</param>
/// <param name="drawState">Draw state</param>
- public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
+ /// <param name="spec">Specialization state updater</param>
+ public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
{
_context = context;
_channel = channel;
_state = state;
_drawState = drawState;
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
+ _currentSpecState = spec;
- // ShaderState must be updated after other state updates, as pipeline state is sent to the backend when compiling new shaders.
+ // ShaderState must be updated after other state updates, as specialization/pipeline state is used when fetching shaders.
// Render target state must appear after shader state as it depends on information from the currently bound shader.
// Rasterizer and scissor states are checked by render target clear, their indexes
// must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
@@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.DepthTestFunc)),
new StateUpdateCallbackEntry(UpdateTessellationState,
+ nameof(ThreedClassState.TessMode),
nameof(ThreedClassState.TessOuterLevel),
nameof(ThreedClassState.TessInnerLevel),
nameof(ThreedClassState.PatchVertices)),
@@ -138,17 +143,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
- new StateUpdateCallbackEntry(UpdateShaderState,
- nameof(ThreedClassState.ShaderBaseAddress),
- nameof(ThreedClassState.ShaderState)),
-
- new StateUpdateCallbackEntry(UpdateRenderTargetState,
- nameof(ThreedClassState.RtColorState),
- nameof(ThreedClassState.RtDepthStencilState),
- nameof(ThreedClassState.RtControl),
- nameof(ThreedClassState.RtDepthStencilSize),
- nameof(ThreedClassState.RtDepthStencilEnable)),
-
new StateUpdateCallbackEntry(UpdateScissorState,
nameof(ThreedClassState.ScissorState),
nameof(ThreedClassState.ScreenScissorState)),
@@ -179,7 +173,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
new StateUpdateCallbackEntry(UpdateMultisampleState,
nameof(ThreedClassState.AlphaToCoverageDitherEnable),
- nameof(ThreedClassState.MultisampleControl))
+ nameof(ThreedClassState.MultisampleControl)),
+
+ new StateUpdateCallbackEntry(UpdateEarlyZState,
+ nameof(ThreedClassState.EarlyZForce)),
+
+ new StateUpdateCallbackEntry(UpdateShaderState,
+ nameof(ThreedClassState.ShaderBaseAddress),
+ nameof(ThreedClassState.ShaderState)),
+
+ new StateUpdateCallbackEntry(UpdateRenderTargetState,
+ nameof(ThreedClassState.RtColorState),
+ nameof(ThreedClassState.RtDepthStencilState),
+ nameof(ThreedClassState.RtControl),
+ nameof(ThreedClassState.RtDepthStencilSize),
+ nameof(ThreedClassState.RtDepthStencilEnable)),
});
}
@@ -209,17 +217,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update()
{
- // If any state that the shader depends on changed,
- // then we may need to compile/bind a different version
- // of the shader for the new state.
- if (_shaderSpecState != null)
- {
- if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
- {
- ForceShaderUpdate();
- }
- }
-
// The vertex buffer size is calculated using a different
// method when doing indexed draws, so we need to make sure
// to update the vertex buffers if we are doing a regular
@@ -271,6 +268,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_updateTracker.Update(ulong.MaxValue);
+ // If any state that the shader depends on changed,
+ // then we may need to compile/bind a different version
+ // of the shader for the new state.
+ if (_shaderSpecState != null && _currentSpecState.HasChanged())
+ {
+ if (!_shaderSpecState.MatchesGraphics(_channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), _vsUsesDrawParameters, false))
+ {
+ // Shader must be reloaded. _vtgWritesRtLayer should not change.
+ UpdateShaderState();
+ }
+ }
+
CommitBindings();
if (tfEnable && !_prevTfEnable)
@@ -302,7 +311,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
{
- // Shader must be reloaded.
+ _currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers);
+ // Shader must be reloaded. _vtgWritesRtLayer should not change.
UpdateShaderState();
}
@@ -351,6 +361,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.PatchVertices,
_state.State.TessOuterLevel.AsSpan(),
_state.State.TessInnerLevel.AsSpan());
+
+ _currentSpecState.SetTessellationMode(_state.State.TessMode);
}
/// <summary>
@@ -611,6 +623,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.AlphaTestEnable,
_state.State.AlphaTestRef,
_state.State.AlphaTestFunc);
+
+ _currentSpecState.SetAlphaTest(
+ _state.State.AlphaTestEnable,
+ _state.State.AlphaTestRef,
+ _state.State.AlphaTestFunc);
}
/// <summary>
@@ -710,6 +727,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
_context.Renderer.Pipeline.SetViewports(viewports, disableTransform);
+
+ _currentSpecState.SetViewportTransformDisable(_state.State.ViewportTransformEnable == 0);
+ _currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
}
/// <summary>
@@ -847,6 +867,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
_channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex);
+
+ _currentSpecState.SetPoolState(GetPoolState());
}
/// <summary>
@@ -887,6 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_pipeline.SetVertexAttribs(vertexAttribs);
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
+ _currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
}
/// <summary>
@@ -914,6 +937,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
_context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
+
+ _currentSpecState.SetProgramPointSizeEnable(isProgramPointSize);
+ _currentSpecState.SetPointSize(size);
}
/// <summary>
@@ -1212,6 +1238,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
alphaToCoverageEnable,
_state.State.AlphaToCoverageDitherEnable,
alphaToOneEnable));
+
+ _currentSpecState.SetAlphaToCoverageEnable(alphaToCoverageEnable, _state.State.AlphaToCoverageDitherEnable);
+ }
+
+ /// <summary>
+ /// Updates the early z flag, based on guest state.
+ /// </summary>
+ private void UpdateEarlyZState()
+ {
+ _currentSpecState.SetEarlyZForce(_state.State.EarlyZForce);
}
/// <summary>
@@ -1239,10 +1275,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
addressesSpan[index] = baseAddress + shader.Offset;
}
- GpuChannelPoolState poolState = GetPoolState();
- GpuChannelGraphicsState graphicsState = GetGraphicsState();
+ CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses);
- CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, poolState, graphicsState, addresses);
+ // Consume the modified flag for spec state so that it isn't checked again.
+ _currentSpecState.SetShader(gs);
_shaderSpecState = gs.SpecializationState;
@@ -1290,46 +1326,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
/// <summary>
- /// Gets the current GPU channel state for shader creation or compatibility verification.
- /// </summary>
- /// <returns>Current GPU channel state</returns>
- private GpuChannelGraphicsState GetGraphicsState()
- {
- ref var vertexAttribState = ref _state.State.VertexAttribState;
-
- Array32<AttributeType> attributeTypes = new Array32<AttributeType>();
-
- for (int location = 0; location < attributeTypes.Length; location++)
- {
- VertexAttribType type = vertexAttribState[location].UnpackType();
-
- attributeTypes[location] = type switch
- {
- VertexAttribType.Sint => AttributeType.Sint,
- VertexAttribType.Uint => AttributeType.Uint,
- _ => AttributeType.Float
- };
- }
-
- return new GpuChannelGraphicsState(
- _state.State.EarlyZForce,
- _drawState.Topology,
- _state.State.TessMode,
- (_state.State.MultisampleControl & 1) != 0,
- _state.State.AlphaToCoverageDitherEnable,
- _state.State.ViewportTransformEnable == 0,
- GetDepthMode() == DepthMode.MinusOneToOne,
- _state.State.VertexProgramPointSize,
- _state.State.PointSize,
- _state.State.AlphaTestEnable,
- _state.State.AlphaTestFunc,
- _state.State.AlphaTestRef,
- ref attributeTypes,
- _drawState.HasConstantBufferDrawParameters,
- _channel.BufferManager.HasUnalignedStorageBuffers);
- }
-
- /// <summary>
/// Gets the depth mode that is currently being used (zero to one or minus one to one).
/// </summary>
/// <returns>Current depth mode</returns>