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
This commit is contained in:
parent
0510fde25a
commit
a7109c767b
168 changed files with 12022 additions and 6388 deletions
|
@ -2,6 +2,7 @@ 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;
|
||||
|
||||
|
@ -29,184 +30,101 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Register(3, RegisterType.Flag);
|
||||
}
|
||||
|
||||
public static Operand GetDest(EmitterContext context)
|
||||
public static Operand GetDest(int rd)
|
||||
{
|
||||
return Register(((IOpCodeRd)context.CurrOp).Rd);
|
||||
return Register(rd, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
public static Operand GetDest2(EmitterContext context)
|
||||
public static Operand GetDest2(int rd)
|
||||
{
|
||||
Register rd = ((IOpCodeRd)context.CurrOp).Rd;
|
||||
|
||||
return Register(rd.Index | 1, rd.Type);
|
||||
return Register(rd | 1, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
public static Operand GetSrcA(EmitterContext context, bool isFP64 = false)
|
||||
{
|
||||
IOpCodeRa op = (IOpCodeRa)context.CurrOp;
|
||||
|
||||
if (isFP64)
|
||||
{
|
||||
return context.PackDouble2x32(Register(op.Ra.Index, op.Ra.Type), Register(op.Ra.Index | 1, op.Ra.Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Register(op.Ra);
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand GetSrcB(EmitterContext context, FPType floatType)
|
||||
{
|
||||
if (floatType == FPType.FP32)
|
||||
{
|
||||
return GetSrcB(context);
|
||||
}
|
||||
else if (floatType == FPType.FP16)
|
||||
{
|
||||
int h = context.CurrOp.RawOpCode.Extract(41, 1);
|
||||
|
||||
return GetHalfUnpacked(context, GetSrcB(context), FPHalfSwizzle.FP16)[h];
|
||||
}
|
||||
else if (floatType == FPType.FP64)
|
||||
{
|
||||
return GetSrcB(context, true);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid floating point type \"{floatType}\".");
|
||||
}
|
||||
|
||||
public static Operand GetSrcB(EmitterContext context, bool isFP64 = false)
|
||||
public static Operand GetSrcCbuf(EmitterContext context, int cbufSlot, int cbufOffset, bool isFP64 = false)
|
||||
{
|
||||
if (isFP64)
|
||||
{
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case IOpCodeCbuf op:
|
||||
return context.PackDouble2x32(
|
||||
context.Config.CreateCbuf(op.Slot, op.Offset),
|
||||
context.Config.CreateCbuf(op.Slot, op.Offset + 1));
|
||||
|
||||
case IOpCodeImmF op:
|
||||
return context.FP32ConvertToFP64(ConstF(op.Immediate));
|
||||
|
||||
case IOpCodeReg op:
|
||||
return context.PackDouble2x32(Register(op.Rb.Index, op.Rb.Type), Register(op.Rb.Index | 1, op.Rb.Type));
|
||||
|
||||
case IOpCodeRegCbuf op:
|
||||
return context.PackDouble2x32(Register(op.Rc.Index, op.Rc.Type), Register(op.Rc.Index | 1, op.Rc.Type));
|
||||
}
|
||||
return context.PackDouble2x32(
|
||||
context.Config.CreateCbuf(cbufSlot, cbufOffset),
|
||||
context.Config.CreateCbuf(cbufSlot, cbufOffset + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case IOpCodeCbuf op:
|
||||
return context.Config.CreateCbuf(op.Slot, op.Offset);
|
||||
|
||||
case IOpCodeImm op:
|
||||
return Const(op.Immediate);
|
||||
|
||||
case IOpCodeImmF op:
|
||||
return ConstF(op.Immediate);
|
||||
|
||||
case IOpCodeReg op:
|
||||
return Register(op.Rb);
|
||||
|
||||
case IOpCodeRegCbuf op:
|
||||
return Register(op.Rc);
|
||||
}
|
||||
return context.Config.CreateCbuf(cbufSlot, cbufOffset);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\".");
|
||||
}
|
||||
|
||||
public static Operand GetSrcC(EmitterContext context, bool isFP64 = false)
|
||||
public static Operand GetSrcImm(EmitterContext context, int imm, bool isFP64 = false)
|
||||
{
|
||||
if (isFP64)
|
||||
{
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case IOpCodeRegCbuf op:
|
||||
return context.PackDouble2x32(
|
||||
context.Config.CreateCbuf(op.Slot, op.Offset),
|
||||
context.Config.CreateCbuf(op.Slot, op.Offset + 1));
|
||||
|
||||
case IOpCodeRc op:
|
||||
return context.PackDouble2x32(Register(op.Rc.Index, op.Rc.Type), Register(op.Rc.Index | 1, op.Rc.Type));
|
||||
}
|
||||
return context.FP32ConvertToFP64(Const(imm));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case IOpCodeRegCbuf op:
|
||||
return context.Config.CreateCbuf(op.Slot, op.Offset);
|
||||
|
||||
case IOpCodeRc op:
|
||||
return Register(op.Rc);
|
||||
}
|
||||
return Const(imm);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\".");
|
||||
}
|
||||
|
||||
public static Operand[] GetHalfSrcA(EmitterContext context, bool isAdd = false)
|
||||
public static Operand GetSrcReg(EmitterContext context, int reg, bool isFP64 = false)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
bool absoluteA = false, negateA = false;
|
||||
|
||||
if (op is OpCodeAluImm32 && isAdd)
|
||||
if (isFP64)
|
||||
{
|
||||
negateA = op.RawOpCode.Extract(56);
|
||||
return context.PackDouble2x32(Register(reg, RegisterType.Gpr), Register(reg | 1, RegisterType.Gpr));
|
||||
}
|
||||
else if (isAdd || op is IOpCodeCbuf || op is IOpCodeImm)
|
||||
else
|
||||
{
|
||||
negateA = op.RawOpCode.Extract(43);
|
||||
absoluteA = op.RawOpCode.Extract(44);
|
||||
return Register(reg, RegisterType.Gpr);
|
||||
}
|
||||
else if (op is IOpCodeReg)
|
||||
{
|
||||
absoluteA = op.RawOpCode.Extract(44);
|
||||
}
|
||||
|
||||
FPHalfSwizzle swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(47, 2);
|
||||
|
||||
Operand[] operands = GetHalfUnpacked(context, GetSrcA(context), swizzle);
|
||||
|
||||
return FPAbsNeg(context, operands, absoluteA, negateA);
|
||||
}
|
||||
|
||||
public static Operand[] GetHalfSrcB(EmitterContext context, bool isMul = false)
|
||||
public static Operand[] GetHalfSrc(
|
||||
EmitterContext context,
|
||||
HalfSwizzle swizzle,
|
||||
int ra,
|
||||
bool negate,
|
||||
bool absolute)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
Operand[] operands = GetHalfUnpacked(context, GetSrcReg(context, ra), swizzle);
|
||||
|
||||
FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
|
||||
return FPAbsNeg(context, operands, absolute, negate);
|
||||
}
|
||||
|
||||
bool absoluteB = false, negateB = false;
|
||||
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);
|
||||
|
||||
if (op is IOpCodeReg)
|
||||
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[]
|
||||
{
|
||||
swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2);
|
||||
ConstF((float)Unsafe.As<ushort, Half>(ref low)),
|
||||
ConstF((float)Unsafe.As<ushort, Half>(ref high))
|
||||
};
|
||||
}
|
||||
|
||||
absoluteB = op.RawOpCode.Extract(30);
|
||||
negateB = op.RawOpCode.Extract(31);
|
||||
}
|
||||
else if (op is IOpCodeCbuf)
|
||||
public static Operand[] GetHalfSrc(EmitterContext context, int imm32)
|
||||
{
|
||||
ushort low = (ushort)imm32;
|
||||
ushort high = (ushort)(imm32 >> 16);
|
||||
|
||||
return new Operand[]
|
||||
{
|
||||
swizzle = FPHalfSwizzle.FP32;
|
||||
|
||||
absoluteB = op.RawOpCode.Extract(54);
|
||||
|
||||
if (!isMul)
|
||||
{
|
||||
negateB = op.RawOpCode.Extract(56);
|
||||
}
|
||||
}
|
||||
|
||||
Operand[] operands = GetHalfUnpacked(context, GetSrcB(context), swizzle);
|
||||
|
||||
return FPAbsNeg(context, operands, absoluteB, negateB);
|
||||
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)
|
||||
|
@ -219,27 +137,27 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return operands;
|
||||
}
|
||||
|
||||
public static Operand[] GetHalfUnpacked(EmitterContext context, Operand src, FPHalfSwizzle swizzle)
|
||||
public static Operand[] GetHalfUnpacked(EmitterContext context, Operand src, HalfSwizzle swizzle)
|
||||
{
|
||||
switch (swizzle)
|
||||
{
|
||||
case FPHalfSwizzle.FP16:
|
||||
case HalfSwizzle.F16:
|
||||
return new Operand[]
|
||||
{
|
||||
context.UnpackHalf2x16Low (src),
|
||||
context.UnpackHalf2x16High(src)
|
||||
};
|
||||
|
||||
case FPHalfSwizzle.FP32: return new Operand[] { src, src };
|
||||
case HalfSwizzle.F32: return new Operand[] { src, src };
|
||||
|
||||
case FPHalfSwizzle.DupH0:
|
||||
case HalfSwizzle.H0H0:
|
||||
return new Operand[]
|
||||
{
|
||||
context.UnpackHalf2x16Low(src),
|
||||
context.UnpackHalf2x16Low(src)
|
||||
};
|
||||
|
||||
case FPHalfSwizzle.DupH1:
|
||||
case HalfSwizzle.H1H1:
|
||||
return new Operand[]
|
||||
{
|
||||
context.UnpackHalf2x16High(src),
|
||||
|
@ -250,33 +168,24 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
|
||||
}
|
||||
|
||||
public static Operand GetHalfPacked(EmitterContext context, Operand[] results)
|
||||
public static Operand GetHalfPacked(EmitterContext context, OFmt swizzle, Operand[] results, int rd)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
|
||||
|
||||
if (!(op is OpCodeAluImm32))
|
||||
{
|
||||
swizzle = (FPHalfSwizzle)context.CurrOp.RawOpCode.Extract(49, 2);
|
||||
}
|
||||
|
||||
switch (swizzle)
|
||||
{
|
||||
case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]);
|
||||
case OFmt.F16: return context.PackHalf2x16(results[0], results[1]);
|
||||
|
||||
case FPHalfSwizzle.FP32: return results[0];
|
||||
case OFmt.F32: return results[0];
|
||||
|
||||
case FPHalfSwizzle.DupH0:
|
||||
case OFmt.MrgH0:
|
||||
{
|
||||
Operand h1 = GetHalfDest(context, isHigh: true);
|
||||
Operand h1 = GetHalfDest(context, rd, isHigh: true);
|
||||
|
||||
return context.PackHalf2x16(results[0], h1);
|
||||
}
|
||||
|
||||
case FPHalfSwizzle.DupH1:
|
||||
case OFmt.MrgH1:
|
||||
{
|
||||
Operand h0 = GetHalfDest(context, isHigh: false);
|
||||
Operand h0 = GetHalfDest(context, rd, isHigh: false);
|
||||
|
||||
return context.PackHalf2x16(h0, results[1]);
|
||||
}
|
||||
|
@ -285,25 +194,23 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
|
||||
}
|
||||
|
||||
public static Operand GetHalfDest(EmitterContext context, bool isHigh)
|
||||
public static Operand GetHalfDest(EmitterContext context, int rd, bool isHigh)
|
||||
{
|
||||
if (isHigh)
|
||||
{
|
||||
return context.UnpackHalf2x16High(GetDest(context));
|
||||
return context.UnpackHalf2x16High(GetDest(rd));
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.UnpackHalf2x16Low(GetDest(context));
|
||||
return context.UnpackHalf2x16Low(GetDest(rd));
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand GetPredicate39(EmitterContext context)
|
||||
public static Operand GetPredicate(EmitterContext context, int pred, bool not)
|
||||
{
|
||||
IOpCodePredicate39 op = (IOpCodePredicate39)context.CurrOp;
|
||||
Operand local = Register(pred, RegisterType.Predicate);
|
||||
|
||||
Operand local = Register(op.Predicate39);
|
||||
|
||||
if (op.InvertP)
|
||||
if (not)
|
||||
{
|
||||
local = context.BitwiseNot(local);
|
||||
}
|
||||
|
@ -311,6 +218,26 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
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));
|
||||
|
@ -318,7 +245,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
|
||||
public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits)
|
||||
{
|
||||
int mask = (int)(0xffffffffu >> (32 - srcBits));
|
||||
int mask = (int)(uint.MaxValue >> (32 - srcBits));
|
||||
|
||||
return context.BitwiseAnd(src, Const(mask));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue