diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-01-31 09:43:24 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-01-31 09:43:24 -0300 |
| commit | e10ff17e2d87b818d340947367d2d1a4276a0d06 (patch) | |
| tree | 3b07aa92c5d8acff81d43ddb1ded48c4c7917b72 /Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs | |
| parent | c81abdde4c48c607669580ef769776623b86dcc7 (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.cs | 59 |
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); |
