aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/EmitterContext.cs')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs111
1 files changed, 107 insertions, 4 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 332b3e02..51823240 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Numerics;
using System.Runtime.CompilerServices;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -30,6 +31,19 @@ namespace Ryujinx.Graphics.Shader.Translation
IsNonMain = isNonMain;
_operations = new List<Operation>();
_labels = new Dictionary<ulong, Operand>();
+
+ EmitStart();
+ }
+
+ private void EmitStart()
+ {
+ if (Config.Stage == ShaderStage.Vertex &&
+ Config.Options.TargetApi == TargetApi.Vulkan &&
+ (Config.Options.Flags & TranslationFlags.VertexA) == 0)
+ {
+ // Vulkan requires the point size to be always written on the shader if the primitive topology is points.
+ this.Copy(Attribute(AttributeConsts.PointSize), ConstF(Config.GpuAccessor.QueryPointSize()));
+ }
}
public T GetOp<T>() where T : unmanaged
@@ -43,7 +57,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
Operation operation = new Operation(inst, dest, sources);
- Add(operation);
+ _operations.Add(operation);
return dest;
}
@@ -167,6 +181,15 @@ namespace Ryujinx.Graphics.Shader.Translation
this.Copy(Attribute(AttributeConsts.PositionX), this.FPFusedMultiplyAdd(x, xScale, negativeOne));
this.Copy(Attribute(AttributeConsts.PositionY), this.FPFusedMultiplyAdd(y, yScale, negativeOne));
}
+
+ if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne())
+ {
+ Operand z = Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask);
+ Operand w = Attribute(AttributeConsts.PositionW | AttributeConsts.LoadOutputMask);
+ Operand halfW = this.FPMultiply(w, ConstF(0.5f));
+
+ this.Copy(Attribute(AttributeConsts.PositionZ), this.FPFusedMultiplyAdd(z, ConstF(0.5f), halfW));
+ }
}
public void PrepareForVertexReturn(out Operand oldXLocal, out Operand oldYLocal, out Operand oldZLocal)
@@ -184,8 +207,15 @@ namespace Ryujinx.Graphics.Shader.Translation
oldYLocal = null;
}
- // Will be used by Vulkan backend for depth mode emulation.
- oldZLocal = null;
+ if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne())
+ {
+ oldZLocal = Local();
+ this.Copy(oldZLocal, Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask));
+ }
+ else
+ {
+ oldZLocal = null;
+ }
PrepareForVertexReturn();
}
@@ -203,10 +233,50 @@ namespace Ryujinx.Graphics.Shader.Translation
{
PrepareForVertexReturn();
}
+ else if (Config.Stage == ShaderStage.Geometry)
+ {
+ void WriteOutput(int index, int primIndex)
+ {
+ Operand x = this.LoadAttribute(Const(index), Const(0), Const(primIndex));
+ Operand y = this.LoadAttribute(Const(index + 4), Const(0), Const(primIndex));
+ Operand z = this.LoadAttribute(Const(index + 8), Const(0), Const(primIndex));
+ Operand w = this.LoadAttribute(Const(index + 12), Const(0), Const(primIndex));
+
+ this.Copy(Attribute(index), x);
+ this.Copy(Attribute(index + 4), y);
+ this.Copy(Attribute(index + 8), z);
+ this.Copy(Attribute(index + 12), w);
+ }
+
+ if (Config.GpPassthrough)
+ {
+ int inputVertices = Config.GpuAccessor.QueryPrimitiveTopology().ToInputVertices();
+
+ for (int primIndex = 0; primIndex < inputVertices; primIndex++)
+ {
+ WriteOutput(AttributeConsts.PositionX, primIndex);
+
+ int passthroughAttributes = Config.PassthroughAttributes;
+ while (passthroughAttributes != 0)
+ {
+ int index = BitOperations.TrailingZeroCount(passthroughAttributes);
+ WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex);
+ Config.SetOutputUserAttribute(index, perPatch: false);
+ passthroughAttributes &= ~(1 << index);
+ }
+
+ this.EmitVertex();
+ }
+
+ this.EndPrimitive();
+ }
+ }
else if (Config.Stage == ShaderStage.Fragment)
{
GenerateAlphaToCoverageDitherDiscard();
+ bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
+
if (Config.OmapDepth)
{
Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
@@ -216,7 +286,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++)