Implement BFI, BRK, FLO, FSWZADD, PBK, SHFL and TXD shader instructions, misc. fixes

This commit is contained in:
gdk 2019-10-31 00:29:22 -03:00 committed by Thog
parent d786d8d2b9
commit 278a4c317c
38 changed files with 972 additions and 166 deletions

View file

@ -39,6 +39,23 @@ namespace Ryujinx.Graphics.Shader.Instructions
// TODO: CC, X, corner cases
}
public static void Bfi(EmitterContext context)
{
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
Operand srcA = GetSrcA(context);
Operand srcB = GetSrcB(context);
Operand srcC = GetSrcC(context);
Operand position = context.BitwiseAnd(srcB, Const(0xff));
Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8));
Operand res = context.BitfieldInsert(srcC, srcA, position, size);
context.Copy(GetDest(context), res);
}
public static void Csetp(EmitterContext context)
{
OpCodePsetp op = (OpCodePsetp)context.CurrOp;
@ -58,6 +75,28 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Copy(Register(op.Predicate0), p1Res);
}
public static void Flo(EmitterContext context)
{
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
bool invert = op.RawOpCode.Extract(40);
bool countZeros = op.RawOpCode.Extract(41);
bool isSigned = op.RawOpCode.Extract(48);
Operand srcB = context.BitwiseNot(GetSrcB(context), invert);
Operand res = isSigned
? context.FindFirstSetS32(srcB)
: context.FindFirstSetU32(srcB);
if (countZeros)
{
res = context.BitwiseExclusiveOr(res, Const(31));
}
context.Copy(GetDest(context), res);
}
public static void Iadd(EmitterContext context)
{
OpCodeAlu op = (OpCodeAlu)context.CurrOp;

View file

@ -180,6 +180,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Copy(Register(op.Predicate0), p1Res);
}
public static void Fswzadd(EmitterContext context)
{
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
int mask = op.RawOpCode.Extract(28, 8);
Operand srcA = GetSrcA(context);
Operand srcB = GetSrcB(context);
Operand dest = GetDest(context);
context.Copy(dest, context.FPSwizzleAdd(srcA, srcB, mask));
SetFPZnFlags(context, dest, op.SetCondCode);
}
public static void Hadd2(EmitterContext context)
{
Hadd2Hmul2Impl(context, isAdd: true);

View file

@ -15,6 +15,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
EmitBranch(context, context.CurrBlock.Branch.Address);
}
public static void Brk(EmitterContext context)
{
EmitBrkOrSync(context);
}
public static void Exit(EmitterContext context)
{
OpCodeExit op = (OpCodeExit)context.CurrOp;
@ -32,7 +37,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Discard();
}
public static void Pbk(EmitterContext context)
{
EmitPbkOrSsy(context);
}
public static void Ssy(EmitterContext context)
{
EmitPbkOrSsy(context);
}
public static void Sync(EmitterContext context)
{
EmitBrkOrSync(context);
}
private static void EmitPbkOrSsy(EmitterContext context)
{
OpCodeSsy op = (OpCodeSsy)context.CurrOp;
@ -48,7 +68,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
public static void Sync(EmitterContext context)
private static void EmitBrkOrSync(EmitterContext context)
{
OpCodeSync op = (OpCodeSync)context.CurrOp;

View file

@ -27,6 +27,9 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (sysReg)
{
// TODO: Use value from Y direction GPU register.
case SystemRegister.YDirection: src = ConstF(1); break;
case SystemRegister.ThreadId:
{
Operand tidX = Attribute(AttributeConsts.ThreadIdX);
@ -67,5 +70,37 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Copy(GetDest(context), res);
}
public static void Shfl(EmitterContext context)
{
OpCodeShuffle op = (OpCodeShuffle)context.CurrOp;
Operand pred = Register(op.Predicate48);
Operand srcA = GetSrcA(context);
Operand srcB = op.IsBImmediate ? Const(op.ImmediateB) : Register(op.Rb);
Operand srcC = op.IsCImmediate ? Const(op.ImmediateC) : Register(op.Rc);
Operand res = null;
switch (op.ShuffleType)
{
case ShuffleType.Indexed:
res = context.Shuffle(srcA, srcB, srcC);
break;
case ShuffleType.Up:
res = context.ShuffleUp(srcA, srcB, srcC);
break;
case ShuffleType.Down:
res = context.ShuffleDown(srcA, srcB, srcC);
break;
case ShuffleType.Butterfly:
res = context.ShuffleXor(srcA, srcB, srcC);
break;
}
context.Copy(GetDest(context), res);
}
}
}

View file

@ -102,22 +102,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Tex(EmitterContext context)
{
Tex(context, TextureFlags.None);
EmitTextureSample(context, TextureFlags.None);
}
public static void TexB(EmitterContext context)
{
Tex(context, TextureFlags.Bindless);
EmitTextureSample(context, TextureFlags.Bindless);
}
public static void Tld(EmitterContext context)
{
Tex(context, TextureFlags.IntCoords);
EmitTextureSample(context, TextureFlags.IntCoords);
}
public static void TldB(EmitterContext context)
{
Tex(context, TextureFlags.IntCoords | TextureFlags.Bindless);
EmitTextureSample(context, TextureFlags.IntCoords | TextureFlags.Bindless);
}
public static void Texs(EmitterContext context)
@ -512,17 +512,128 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
public static void Txd(EmitterContext context)
{
OpCodeTxd op = (OpCodeTxd)context.CurrOp;
if (op.Rd.IsRZ)
{
return;
}
int raIndex = op.Ra.Index;
int rbIndex = op.Rb.Index;
Operand Ra()
{
if (raIndex > RegisterConsts.RegisterZeroIndex)
{
return Const(0);
}
return context.Copy(Register(raIndex++, RegisterType.Gpr));
}
Operand Rb()
{
if (rbIndex > RegisterConsts.RegisterZeroIndex)
{
return Const(0);
}
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
}
TextureFlags flags = TextureFlags.Derivatives;
List<Operand> sourcesList = new List<Operand>();
if (op.IsBindless)
{
sourcesList.Add(Ra());
}
SamplerType type = GetSamplerType(op.Dimensions);
int coordsCount = type.GetDimensions();
for (int index = 0; index < coordsCount; index++)
{
sourcesList.Add(Ra());
}
Operand packedParams = Ra();
if (op.IsArray)
{
sourcesList.Add(context.BitwiseAnd(packedParams, Const(0xffff)));
type |= SamplerType.Array;
}
// Derivatives (X and Y).
for (int dIndex = 0; dIndex < 2 * coordsCount; dIndex++)
{
sourcesList.Add(Rb());
}
if (op.HasOffset)
{
for (int index = 0; index < coordsCount; index++)
{
sourcesList.Add(context.BitfieldExtractS32(packedParams, Const(16 + index * 4), Const(4)));
}
flags |= TextureFlags.Offset;
}
Operand[] sources = sourcesList.ToArray();
int rdIndex = op.Rd.Index;
Operand GetDest()
{
if (rdIndex > RegisterConsts.RegisterZeroIndex)
{
return Const(0);
}
return Register(rdIndex++, RegisterType.Gpr);
}
int handle = !op.IsBindless ? op.Immediate : 0;
for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{
if ((compMask & 1) != 0)
{
Operand dest = GetDest();
TextureOperation operation = new TextureOperation(
Instruction.TextureSample,
type,
flags,
handle,
compIndex,
dest,
sources);
context.Add(operation);
}
}
}
public static void Txq(EmitterContext context)
{
Txq(context, bindless: false);
EmitTextureQuery(context, bindless: false);
}
public static void TxqB(EmitterContext context)
{
Txq(context, bindless: true);
EmitTextureQuery(context, bindless: true);
}
private static void Txq(EmitterContext context, bool bindless)
private static void EmitTextureQuery(EmitterContext context, bool bindless)
{
OpCodeTex op = (OpCodeTex)context.CurrOp;
@ -597,7 +708,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
private static void Tex(EmitterContext context, TextureFlags flags)
private static void EmitTextureSample(EmitterContext context, TextureFlags flags)
{
OpCodeTexture op = (OpCodeTexture)context.CurrOp;