aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Instructions
diff options
context:
space:
mode:
authorgdk <gab.dark.100@gmail.com>2019-10-31 00:29:22 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit278a4c317c0b87add67cc9ebc904afe1db23a031 (patch)
tree452b59bf4aebf45b9086cf1f59e006c089a2cba7 /Ryujinx.Graphics.Shader/Instructions
parentd786d8d2b924da7cd116a2eb97d738a9f07b4e43 (diff)
Implement BFI, BRK, FLO, FSWZADD, PBK, SHFL and TXD shader instructions, misc. fixes
Diffstat (limited to 'Ryujinx.Graphics.Shader/Instructions')
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs39
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitFArith.cs16
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitFlow.cs22
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs35
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs127
5 files changed, 230 insertions, 9 deletions
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
index 5cbb3b73..8d14b0cf 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
@@ -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;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFArith.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFArith.cs
index 1a7d4251..4f7072eb 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFArith.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFArith.cs
@@ -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);
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFlow.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFlow.cs
index fb76e06a..e17c9d6c 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFlow.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFlow.cs
@@ -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,8 +37,23 @@ 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;
foreach (KeyValuePair<OpCodeSync, Operand> kv in op.Syncs)
@@ -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;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
index b9bb18d9..f0792245 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
@@ -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);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 39672789..2654a05b 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -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;