Ryujinx/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
gdkchan a7109c767b
Rewrite shader decoding stage (#2698)
* Rewrite shader decoding stage

* Fix P2R constant buffer encoding

* Fix PSET/PSETP

* PR feedback

* Log unimplemented shader instructions

* Implement NOP

* Remove using

* PR feedback
2021-10-12 22:35:31 +02:00

253 lines
No EOL
7.3 KiB
C#

using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.Translation;
using System;
using System.Runtime.CompilerServices;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
namespace Ryujinx.Graphics.Shader.Instructions
{
static class InstEmitHelper
{
public static Operand GetZF()
{
return Register(0, RegisterType.Flag);
}
public static Operand GetNF()
{
return Register(1, RegisterType.Flag);
}
public static Operand GetCF()
{
return Register(2, RegisterType.Flag);
}
public static Operand GetVF()
{
return Register(3, RegisterType.Flag);
}
public static Operand GetDest(int rd)
{
return Register(rd, RegisterType.Gpr);
}
public static Operand GetDest2(int rd)
{
return Register(rd | 1, RegisterType.Gpr);
}
public static Operand GetSrcCbuf(EmitterContext context, int cbufSlot, int cbufOffset, bool isFP64 = false)
{
if (isFP64)
{
return context.PackDouble2x32(
context.Config.CreateCbuf(cbufSlot, cbufOffset),
context.Config.CreateCbuf(cbufSlot, cbufOffset + 1));
}
else
{
return context.Config.CreateCbuf(cbufSlot, cbufOffset);
}
}
public static Operand GetSrcImm(EmitterContext context, int imm, bool isFP64 = false)
{
if (isFP64)
{
return context.FP32ConvertToFP64(Const(imm));
}
else
{
return Const(imm);
}
}
public static Operand GetSrcReg(EmitterContext context, int reg, bool isFP64 = false)
{
if (isFP64)
{
return context.PackDouble2x32(Register(reg, RegisterType.Gpr), Register(reg | 1, RegisterType.Gpr));
}
else
{
return Register(reg, RegisterType.Gpr);
}
}
public static Operand[] GetHalfSrc(
EmitterContext context,
HalfSwizzle swizzle,
int ra,
bool negate,
bool absolute)
{
Operand[] operands = GetHalfUnpacked(context, GetSrcReg(context, ra), swizzle);
return FPAbsNeg(context, operands, absolute, negate);
}
public static Operand[] GetHalfSrc(
EmitterContext context,
HalfSwizzle swizzle,
int cbufSlot,
int cbufOffset,
bool negate,
bool absolute)
{
Operand[] operands = GetHalfUnpacked(context, GetSrcCbuf(context, cbufSlot, cbufOffset), swizzle);
return FPAbsNeg(context, operands, absolute, negate);
}
public static Operand[] GetHalfSrc(EmitterContext context, int immH0, int immH1)
{
ushort low = (ushort)(immH0 << 6);
ushort high = (ushort)(immH1 << 6);
return new Operand[]
{
ConstF((float)Unsafe.As<ushort, Half>(ref low)),
ConstF((float)Unsafe.As<ushort, Half>(ref high))
};
}
public static Operand[] GetHalfSrc(EmitterContext context, int imm32)
{
ushort low = (ushort)imm32;
ushort high = (ushort)(imm32 >> 16);
return new Operand[]
{
ConstF((float)Unsafe.As<ushort, Half>(ref low)),
ConstF((float)Unsafe.As<ushort, Half>(ref high))
};
}
public static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
{
for (int index = 0; index < operands.Length; index++)
{
operands[index] = context.FPAbsNeg(operands[index], abs, neg);
}
return operands;
}
public static Operand[] GetHalfUnpacked(EmitterContext context, Operand src, HalfSwizzle swizzle)
{
switch (swizzle)
{
case HalfSwizzle.F16:
return new Operand[]
{
context.UnpackHalf2x16Low (src),
context.UnpackHalf2x16High(src)
};
case HalfSwizzle.F32: return new Operand[] { src, src };
case HalfSwizzle.H0H0:
return new Operand[]
{
context.UnpackHalf2x16Low(src),
context.UnpackHalf2x16Low(src)
};
case HalfSwizzle.H1H1:
return new Operand[]
{
context.UnpackHalf2x16High(src),
context.UnpackHalf2x16High(src)
};
}
throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
}
public static Operand GetHalfPacked(EmitterContext context, OFmt swizzle, Operand[] results, int rd)
{
switch (swizzle)
{
case OFmt.F16: return context.PackHalf2x16(results[0], results[1]);
case OFmt.F32: return results[0];
case OFmt.MrgH0:
{
Operand h1 = GetHalfDest(context, rd, isHigh: true);
return context.PackHalf2x16(results[0], h1);
}
case OFmt.MrgH1:
{
Operand h0 = GetHalfDest(context, rd, isHigh: false);
return context.PackHalf2x16(h0, results[1]);
}
}
throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
}
public static Operand GetHalfDest(EmitterContext context, int rd, bool isHigh)
{
if (isHigh)
{
return context.UnpackHalf2x16High(GetDest(rd));
}
else
{
return context.UnpackHalf2x16Low(GetDest(rd));
}
}
public static Operand GetPredicate(EmitterContext context, int pred, bool not)
{
Operand local = Register(pred, RegisterType.Predicate);
if (not)
{
local = context.BitwiseNot(local);
}
return local;
}
public static int Imm16ToSInt(int imm16)
{
return (short)imm16;
}
public static int Imm20ToFloat(int imm20)
{
return imm20 << 12;
}
public static int Imm20ToSInt(int imm20)
{
return (imm20 << 12) >> 12;
}
public static int Imm24ToSInt(int imm24)
{
return (imm24 << 8) >> 8;
}
public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits)
{
return context.BitfieldExtractS32(src, Const(0), Const(srcBits));
}
public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits)
{
int mask = (int)(uint.MaxValue >> (32 - srcBits));
return context.BitwiseAnd(src, Const(mask));
}
}
}