Add alpha test emulation on shader (but no shader specialisation yet...)

This commit is contained in:
gdk 2021-12-11 23:36:47 -03:00 committed by riperiperi
parent 9a95c3c3bc
commit 4c7e6df7d1
7 changed files with 124 additions and 4 deletions

View file

@ -1248,7 +1248,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.ViewportTransformEnable == 0,
GetDepthMode() == DepthMode.MinusOneToOne,
_state.State.VertexProgramPointSize,
_state.State.PointSize);
_state.State.PointSize,
_state.State.AlphaTestEnable,
_state.State.AlphaTestFunc,
_state.State.AlphaTestRef);
}
private DepthMode GetDepthMode()

View file

@ -170,7 +170,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
false,
false,
false,
1f);
1f,
false,
CompareOp.Always,
0f);
TransformFeedbackDescriptor[] tfdNew = null;

View file

@ -1,6 +1,8 @@
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;
@ -16,6 +18,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly AttributeType[] _attributeTypes;
private readonly int _stageIndex;
private readonly bool _compute;
private readonly bool _isVulkan;
/// <summary>
/// Creates a new instance of the GPU state accessor for graphics shader translation.
@ -32,6 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
AttributeType[] attributeTypes,
int stageIndex) : base(context, state.ResourceCounts, stageIndex)
{
_isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
_channel = channel;
_state = state;
_attributeTypes = attributeTypes;
@ -74,6 +78,33 @@ namespace Ryujinx.Graphics.Gpu.Shader
return MemoryMarshal.Cast<byte, ulong>(_channel.MemoryManager.GetSpan(address, size));
}
/// <inheritdoc/>
public AlphaTestOp QueryAlphaTestCompare()
{
if (!_isVulkan || !_state.GraphicsState.AlphaTestEnable)
{
return AlphaTestOp.Always;
}
return _state.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()
{
return _state.GraphicsState.AlphaTestReference;
}
/// <inheritdoc/>
public AttributeType QueryAttributeType(int location)
{

View file

@ -45,6 +45,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
public readonly float PointSize;
/// <summary>
/// Indicates whenever alpha test is enabled.
/// </summary>
public readonly bool AlphaTestEnable;
/// <summary>
/// When alpha test is enabled, indicates the comparison that decides if the fragment is discarded.
/// </summary>
public readonly CompareOp AlphaTestCompare;
/// <summary>
/// When alpha test is enabled, indicates the value to compare with the fragment output alpha.
/// </summary>
public readonly float AlphaTestReference;
/// <summary>
/// Creates a new GPU graphics state.
/// </summary>
@ -55,6 +70,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="depthMode">Depth mode zero to one or minus one to one</param>
/// <param name="programPointSizeEnable">Indicates if the point size is set on the shader or is fixed</param>
/// <param name="pointSize">Point size if not set from shader</param>
/// <param name="alphaTestEnable">Indicates whenever alpha test is enabled</param>
/// <param name="alphaTestCompare">When alpha test is enabled, indicates the comparison that decides if the fragment is discarded</param>
/// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param>
public GpuChannelGraphicsState(
bool earlyZForce,
PrimitiveTopology topology,
@ -62,7 +80,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
bool viewportTransformDisable,
bool depthMode,
bool programPointSizeEnable,
float pointSize)
float pointSize,
bool alphaTestEnable,
CompareOp alphaTestCompare,
float alphaTestReference)
{
EarlyZForce = earlyZForce;
Topology = topology;
@ -71,6 +92,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
DepthMode = depthMode;
ProgramPointSizeEnable = programPointSizeEnable;
PointSize = pointSize;
AlphaTestEnable = alphaTestEnable;
AlphaTestCompare = alphaTestCompare;
AlphaTestReference = alphaTestReference;
}
}
}

View file

@ -0,0 +1,14 @@
namespace Ryujinx.Graphics.Shader
{
public enum AlphaTestOp
{
Never = 1,
Less,
Equal,
LessOrEqual,
Greater,
NotEqual,
GreaterOrEqual,
Always
}
}

View file

@ -34,6 +34,16 @@ namespace Ryujinx.Graphics.Shader
/// <returns>Span of the memory location</returns>
ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
AlphaTestOp QueryAlphaTestCompare()
{
return AlphaTestOp.Always;
}
float QueryAlphaTestReference()
{
return 0f;
}
AttributeType QueryAttributeType(int location)
{
return AttributeType.Float;

View file

@ -234,6 +234,8 @@ namespace Ryujinx.Graphics.Shader.Translation
}
else if (Config.Stage == ShaderStage.Fragment)
{
bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
if (Config.OmapDepth)
{
Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
@ -243,7 +245,40 @@ namespace Ryujinx.Graphics.Shader.Translation
this.Copy(dest, src);
}
bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
AlphaTestOp alphaTestOp = Config.GpuAccessor.QueryAlphaTestCompare();
if (alphaTestOp != AlphaTestOp.Always && (Config.OmapTargets & 8) != 0)
{
if (alphaTestOp == AlphaTestOp.Never)
{
this.Discard();
}
else
{
Instruction comparator = alphaTestOp switch
{
AlphaTestOp.Equal => Instruction.CompareEqual,
AlphaTestOp.Greater => Instruction.CompareGreater,
AlphaTestOp.GreaterOrEqual => Instruction.CompareGreaterOrEqual,
AlphaTestOp.Less => Instruction.CompareLess,
AlphaTestOp.LessOrEqual => Instruction.CompareLessOrEqual,
AlphaTestOp.NotEqual => Instruction.CompareNotEqual,
_ => 0
};
Debug.Assert(comparator != 0, $"Invalid alpha test operation \"{alphaTestOp}\".");
Operand alpha = Register(3, RegisterType.Gpr);
Operand alphaRef = ConstF(Config.GpuAccessor.QueryAlphaTestReference());
Operand alphaPass = Add(Instruction.FP32 | comparator, Local(), alpha, alphaRef);
Operand alphaPassLabel = Label();
this.BranchIfTrue(alphaPassLabel, alphaPass);
this.Discard();
this.MarkLabel(alphaPassLabel);
}
}
int regIndexBase = 0;
for (int rtIndex = 0; rtIndex < 8; rtIndex++)