Add support for alpha to coverage dithering (#3069)

* Add support for alpha to coverage dithering

* Shader cache version bump

* Fix wrong alpha register

* Ensure support buffer is cleared

* New shader specialization based approach
This commit is contained in:
gdkchan
2022-07-05 19:58:36 -03:00
committed by GitHub
parent 594246ea47
commit b46b63e06a
20 changed files with 217 additions and 34 deletions

View File

@ -166,7 +166,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.BlendEnable),
nameof(ThreedClassState.BlendState)),
new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState))
new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState)),
new StateUpdateCallbackEntry(UpdateMultisampleState,
nameof(ThreedClassState.AlphaToCoverageDitherEnable),
nameof(ThreedClassState.MultisampleControl))
});
}
@ -1092,6 +1096,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
}
/// <summary>
/// Updates multisample state, based on guest state.
/// </summary>
private void UpdateMultisampleState()
{
bool alphaToCoverageEnable = (_state.State.MultisampleControl & 1) != 0;
bool alphaToOneEnable = (_state.State.MultisampleControl & 0x10) != 0;
_context.Renderer.Pipeline.SetMultisampleState(new MultisampleDescriptor(
alphaToCoverageEnable,
_state.State.AlphaToCoverageDitherEnable,
alphaToOneEnable));
}
/// <summary>
/// Updates host shaders based on the guest GPU state.
/// </summary>
@ -1231,7 +1249,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.EarlyZForce,
_drawState.Topology,
_state.State.TessMode,
_state.State.ViewportTransformEnable == 0);
_state.State.ViewportTransformEnable == 0,
(_state.State.MultisampleControl & 1) != 0,
_state.State.AlphaToCoverageDitherEnable);
}
/// <summary>

View File

@ -767,7 +767,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public SamplerIndex SamplerIndex;
public fixed uint Reserved1238[37];
public Boolean32 DepthTestEnable;
public fixed uint Reserved12D0[5];
public fixed uint Reserved12D0[4];
public Boolean32 AlphaToCoverageDitherEnable;
public Boolean32 BlendIndependent;
public Boolean32 DepthWriteEnable;
public Boolean32 AlphaTestEnable;
@ -802,9 +803,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public Boolean32 PointSpriteEnable;
public fixed uint Reserved1524[3];
public uint ResetCounter;
public uint Reserved1534;
public Boolean32 MultisampleEnable;
public Boolean32 RtDepthStencilEnable;
public fixed uint Reserved153C[5];
public uint MultisampleControl;
public fixed uint Reserved1540[4];
public GpuVa RenderEnableAddress;
public Condition RenderEnableCondition;
public PoolState SamplerPoolState;

View File

@ -167,6 +167,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce),
topology,
tessMode,
false,
false,
false);
TransformFeedbackDescriptor[] tfdNew = null;

View File

@ -67,6 +67,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
return MemoryMarshal.Cast<byte, ulong>(_data.Span.Slice((int)address));
}
/// <inheritdoc/>
public bool QueryAlphaToCoverageDitherEnable()
{
return _oldSpecState.GraphicsState.AlphaToCoverageEnable && _oldSpecState.GraphicsState.AlphaToCoverageDitherEnable;
}
/// <inheritdoc/>
public int QueryBindingConstantBuffer(int index)
{

View File

@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 1;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 3424;
private const uint CodeGenVersion = 3069;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@ -66,6 +66,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
return MemoryMarshal.Cast<byte, ulong>(_channel.MemoryManager.GetSpan(address, size));
}
/// <inheritdoc/>
public bool QueryAlphaToCoverageDitherEnable()
{
return _state.GraphicsState.AlphaToCoverageEnable && _state.GraphicsState.AlphaToCoverageDitherEnable;
}
/// <inheritdoc/>
public int QueryBindingConstantBuffer(int index)
{

View File

@ -30,6 +30,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
public readonly bool ViewportTransformDisable;
/// <summary>
/// Indicates whenever alpha-to-coverage is enabled.
/// </summary>
public readonly bool AlphaToCoverageEnable;
/// <summary>
/// Indicates whenever alpha-to-coverage dithering is enabled.
/// </summary>
public readonly bool AlphaToCoverageDitherEnable;
/// <summary>
/// Creates a new GPU graphics state.
/// </summary>
@ -37,12 +47,22 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="topology">Primitive topology</param>
/// <param name="tessellationMode">Tessellation mode</param>
/// <param name="viewportTransformDisable">Indicates whenever the viewport transform is disabled</param>
public GpuChannelGraphicsState(bool earlyZForce, PrimitiveTopology topology, TessMode tessellationMode, bool viewportTransformDisable)
/// <param name="alphaToCoverageEnable">Indicates whenever alpha-to-coverage is enabled</param>
/// <param name="alphaToCoverageDitherEnable">Indicates whenever alpha-to-coverage dithering is enabled</param>
public GpuChannelGraphicsState(
bool earlyZForce,
PrimitiveTopology topology,
TessMode tessellationMode,
bool viewportTransformDisable,
bool alphaToCoverageEnable,
bool alphaToCoverageDitherEnable)
{
EarlyZForce = earlyZForce;
Topology = topology;
TessellationMode = tessellationMode;
ViewportTransformDisable = viewportTransformDisable;
AlphaToCoverageEnable = alphaToCoverageEnable;
AlphaToCoverageDitherEnable = alphaToCoverageDitherEnable;
}
}
}

View File

@ -455,6 +455,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
return false;
}
bool thisA2cDitherEnable = GraphicsState.AlphaToCoverageEnable && GraphicsState.AlphaToCoverageDitherEnable;
bool otherA2cDitherEnable = graphicsState.AlphaToCoverageEnable && graphicsState.AlphaToCoverageDitherEnable;
if (otherA2cDitherEnable != thisA2cDitherEnable)
{
return false;
}
return Matches(channel, poolState, checkTextures, isCompute: false);
}