Implement BFI, BRK, FLO, FSWZADD, PBK, SHFL and TXD shader instructions, misc. fixes
This commit is contained in:
parent
d786d8d2b9
commit
278a4c317c
38 changed files with 972 additions and 166 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue