aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-01-31 09:43:24 -0300
committerGitHub <noreply@github.com>2019-01-31 09:43:24 -0300
commite10ff17e2d87b818d340947367d2d1a4276a0d06 (patch)
tree3b07aa92c5d8acff81d43ddb1ded48c4c7917b72 /Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
parentc81abdde4c48c607669580ef769776623b86dcc7 (diff)
Initial support for shader half float instructions (#507)
Diffstat (limited to 'Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs')
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs59
1 files changed, 59 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index 6957e30b..24c85c8f 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -6,6 +6,14 @@ namespace Ryujinx.Graphics.Gal.Shader
{
static partial class ShaderDecode
{
+ private enum HalfOutputType
+ {
+ PackedFp16,
+ Fp32,
+ MergeH0,
+ MergeH1
+ }
+
public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position)
{
EmitBfe(Block, OpCode, ShaderOper.CR);
@@ -144,6 +152,16 @@ namespace Ryujinx.Graphics.Gal.Shader
EmitFsetp(Block, OpCode, ShaderOper.RR);
}
+ public static void Hadd2_R(ShaderIrBlock Block, long OpCode, int Position)
+ {
+ EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fadd);
+ }
+
+ public static void Hmul2_R(ShaderIrBlock Block, long OpCode, int Position)
+ {
+ EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fmul);
+ }
+
public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position)
{
EmitIadd(Block, OpCode, ShaderOper.CR);
@@ -1041,6 +1059,47 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
}
+ private static void EmitBinaryHalfOp(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
+ {
+ bool AbsB = OpCode.Read(30);
+ bool NegB = OpCode.Read(31);
+ bool Sat = OpCode.Read(32);
+ bool AbsA = OpCode.Read(44);
+
+ ShaderIrOperGpr[] VecA = OpCode.GprHalfVec8();
+ ShaderIrOperGpr[] VecB = OpCode.GprHalfVec20();
+
+ HalfOutputType OutputType = (HalfOutputType)OpCode.Read(49, 3);
+
+ int Elems = OutputType == HalfOutputType.PackedFp16 ? 2 : 1;
+ int First = OutputType == HalfOutputType.MergeH1 ? 1 : 0;
+
+ for (int Index = First; Index < Elems; Index++)
+ {
+ ShaderIrNode OperA = GetAluFabs (VecA[Index], AbsA);
+ ShaderIrNode OperB = GetAluFabsFneg(VecB[Index], AbsB, NegB);
+
+ ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
+
+ ShaderIrOperGpr Dst = GetHalfDst(OpCode, OutputType, Index);
+
+ Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, GetAluFsat(Op, Sat))));
+ }
+ }
+
+ private static ShaderIrOperGpr GetHalfDst(long OpCode, HalfOutputType OutputType, int Index)
+ {
+ switch (OutputType)
+ {
+ case HalfOutputType.PackedFp16: return OpCode.GprHalf0(Index);
+ case HalfOutputType.Fp32: return OpCode.Gpr0();
+ case HalfOutputType.MergeH0: return OpCode.GprHalf0(0);
+ case HalfOutputType.MergeH1: return OpCode.GprHalf0(1);
+ }
+
+ throw new ArgumentException(nameof(OutputType));
+ }
+
private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
int SubOp = OpCode.Read(41, 3);