aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Instructions
diff options
context:
space:
mode:
authorgdk <gab.dark.100@gmail.com>2019-11-08 17:29:41 -0300
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commit769c02235f489f02b1791e6e76dc8b3ab18028ee (patch)
treeef0a2ffc5030360d5cef78e7c67e131e44348d50 /Ryujinx.Graphics.Shader/Instructions
parent1e8bc29f32cde08616175f8f87405dfa7b8c4025 (diff)
Add ATOMS, LDS, POPC, RED, STS and VOTE shader instructions, start changing the way how global memory is handled
Diffstat (limited to 'Ryujinx.Graphics.Shader/Instructions')
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs13
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs2
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs178
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs7
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs48
5 files changed, 226 insertions, 22 deletions
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
index 8d14b0cf..31375e43 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
@@ -368,6 +368,19 @@ namespace Ryujinx.Graphics.Shader.Instructions
SetZnFlags(context, dest, op.SetCondCode, op.Extended);
}
+ public static void Popc(EmitterContext context)
+ {
+ OpCodeAlu op = (OpCodeAlu)context.CurrOp;
+
+ bool invert = op.RawOpCode.Extract(40);
+
+ Operand srcB = context.BitwiseNot(GetSrcB(context), invert);
+
+ Operand res = context.BitCount(srcB);
+
+ context.Copy(GetDest(context), res);
+ }
+
public static void Psetp(EmitterContext context)
{
OpCodePsetp op = (OpCodePsetp)context.CurrOp;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
index c0a3012a..ddacc151 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitHelper.cs
@@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static Operand GetPredicate39(EmitterContext context)
{
- IOpCodeAlu op = (IOpCodeAlu)context.CurrOp;
+ IOpCodePredicate39 op = (IOpCodePredicate39)context.CurrOp;
Operand local = Register(op.Predicate39);
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
index ee210f22..d76f44cb 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
@@ -9,6 +9,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
static partial class InstEmit
{
+ private enum MemoryRegion
+ {
+ Global,
+ Local,
+ Shared
+ }
+
public static void Ald(EmitterContext context)
{
OpCodeAttribute op = (OpCodeAttribute)context.CurrOp;
@@ -49,6 +56,21 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
+ public static void Atoms(EmitterContext context)
+ {
+ OpCodeAtom op = (OpCodeAtom)context.CurrOp;
+
+ Operand mem = context.ShiftRightU32(GetSrcA(context), Const(2));
+
+ mem = context.IAdd(mem, Const(op.Offset));
+
+ Operand value = GetSrcB(context);
+
+ Operand res = EmitAtomicOp(context, Instruction.MrShared, op.AtomicOp, op.Type, mem, value);
+
+ context.Copy(GetDest(context), res);
+ }
+
public static void Ipa(EmitterContext context)
{
OpCodeIpa op = (OpCodeIpa)context.CurrOp;
@@ -80,7 +102,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Ld(EmitterContext context)
{
- LoadLocalOrGlobal(context, isGlobal: false);
+ EmitLoad(context, MemoryRegion.Local);
}
public static void Ldc(EmitterContext context)
@@ -126,7 +148,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Ldg(EmitterContext context)
{
- LoadLocalOrGlobal(context, isGlobal: true);
+ EmitLoad(context, MemoryRegion.Global);
+ }
+
+ public static void Lds(EmitterContext context)
+ {
+ EmitLoad(context, MemoryRegion.Shared);
}
public static void Out(EmitterContext context)
@@ -152,17 +179,118 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
+ public static void Red(EmitterContext context)
+ {
+ OpCodeRed op = (OpCodeRed)context.CurrOp;
+
+ Operand offset = context.IAdd(GetSrcA(context), Const(op.Offset));
+
+ Operand mem = context.ShiftRightU32(offset, Const(2));
+
+ EmitAtomicOp(context, Instruction.MrGlobal, op.AtomicOp, op.Type, mem, GetDest(context));
+ }
+
public static void St(EmitterContext context)
{
- StoreLocalOrGlobal(context, isGlobal: false);
+ EmitStore(context, MemoryRegion.Local);
}
public static void Stg(EmitterContext context)
{
- StoreLocalOrGlobal(context, isGlobal: true);
+ EmitStore(context, MemoryRegion.Global);
+ }
+
+ public static void Sts(EmitterContext context)
+ {
+ EmitStore(context, MemoryRegion.Shared);
}
- private static void LoadLocalOrGlobal(EmitterContext context, bool isGlobal)
+ private static Operand EmitAtomicOp(
+ EmitterContext context,
+ Instruction mr,
+ AtomicOp op,
+ ReductionType type,
+ Operand mem,
+ Operand value)
+ {
+ Operand res = null;
+
+ switch (op)
+ {
+ case AtomicOp.Add:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicAdd(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.BitwiseAnd:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicAnd(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.BitwiseExclusiveOr:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicXor(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.BitwiseOr:
+ if (type == ReductionType.S32 || type == ReductionType.U32)
+ {
+ res = context.AtomicOr(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.Maximum:
+ if (type == ReductionType.S32)
+ {
+ res = context.AtomicMaxS32(mr, mem, value);
+ }
+ else if (type == ReductionType.U32)
+ {
+ res = context.AtomicMaxU32(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ case AtomicOp.Minimum:
+ if (type == ReductionType.S32)
+ {
+ res = context.AtomicMinS32(mr, mem, value);
+ }
+ else if (type == ReductionType.U32)
+ {
+ res = context.AtomicMinU32(mr, mem, value);
+ }
+ else
+ {
+ // Not supported or invalid.
+ }
+ break;
+ }
+
+ return res;
+ }
+
+ private static void EmitLoad(EmitterContext context, MemoryRegion region)
{
OpCodeMemory op = (OpCodeMemory)context.CurrOp;
@@ -199,9 +327,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
Operand offset = context.IAdd(wordOffset, Const(index));
- Operand value = isGlobal
- ? context.LoadGlobal(offset)
- : context.LoadLocal (offset);
+ Operand value = null;
+
+ switch (region)
+ {
+ case MemoryRegion.Global: value = context.LoadGlobal(offset); break;
+ case MemoryRegion.Local: value = context.LoadLocal (offset); break;
+ case MemoryRegion.Shared: value = context.LoadShared(offset); break;
+ }
if (isSmallInt)
{
@@ -212,7 +345,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
- private static void StoreLocalOrGlobal(EmitterContext context, bool isGlobal)
+ private static void EmitStore(EmitterContext context, MemoryRegion region)
{
OpCodeMemory op = (OpCodeMemory)context.CurrOp;
@@ -241,31 +374,34 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
Register rd = new Register(op.Rd.Index + index, RegisterType.Gpr);
- if (rd.IsRZ)
- {
- break;
- }
-
Operand value = Register(rd);
Operand offset = context.IAdd(wordOffset, Const(index));
if (isSmallInt)
{
- Operand word = isGlobal
- ? context.LoadGlobal(offset)
- : context.LoadLocal (offset);
+ Operand word = null;
+
+ switch (region)
+ {
+ case MemoryRegion.Global: word = context.LoadGlobal(offset); break;
+ case MemoryRegion.Local: word = context.LoadLocal (offset); break;
+ case MemoryRegion.Shared: word = context.LoadShared(offset); break;
+ }
value = InsertSmallInt(context, op.Size, bitOffset, word, value);
}
- if (isGlobal)
+ switch (region)
{
- context.StoreGlobal(offset, value);
+ case MemoryRegion.Global: context.StoreGlobal(offset, value); break;
+ case MemoryRegion.Local: context.StoreLocal (offset, value); break;
+ case MemoryRegion.Shared: context.StoreShared(offset, value); break;
}
- else
+
+ if (rd.IsRZ)
{
- context.StoreLocal(offset, value);
+ break;
}
}
}
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
index f0792245..5833d879 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
@@ -27,6 +27,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (sysReg)
{
+ case SystemRegister.LaneId: src = Attribute(AttributeConsts.LaneId); break;
+
// TODO: Use value from Y direction GPU register.
case SystemRegister.YDirection: src = ConstF(1); break;
@@ -50,6 +52,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
case SystemRegister.CtaIdX: src = Attribute(AttributeConsts.CtaIdX); break;
case SystemRegister.CtaIdY: src = Attribute(AttributeConsts.CtaIdY); break;
case SystemRegister.CtaIdZ: src = Attribute(AttributeConsts.CtaIdZ); break;
+ case SystemRegister.EqMask: src = Attribute(AttributeConsts.EqMask); break;
+ case SystemRegister.LtMask: src = Attribute(AttributeConsts.LtMask); break;
+ case SystemRegister.LeMask: src = Attribute(AttributeConsts.LeMask); break;
+ case SystemRegister.GtMask: src = Attribute(AttributeConsts.GtMask); break;
+ case SystemRegister.GeMask: src = Attribute(AttributeConsts.GeMask); break;
default: src = Const(0); break;
}
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
new file mode 100644
index 00000000..9c4d5f1a
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
@@ -0,0 +1,48 @@
+using Ryujinx.Graphics.Shader.Decoders;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.Translation;
+
+using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
+using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
+
+namespace Ryujinx.Graphics.Shader.Instructions
+{
+ static partial class InstEmit
+ {
+ public static void Vote(EmitterContext context)
+ {
+ OpCodeVote op = (OpCodeVote)context.CurrOp;
+
+ Operand pred = GetPredicate39(context);
+
+ Operand res = null;
+
+ switch (op.VoteOp)
+ {
+ case VoteOp.All:
+ res = context.VoteAll(pred);
+ break;
+ case VoteOp.Any:
+ res = context.VoteAny(pred);
+ break;
+ case VoteOp.AllEqual:
+ res = context.VoteAllEqual(pred);
+ break;
+ }
+
+ if (res != null)
+ {
+ context.Copy(Register(op.Predicate45), res);
+ }
+ else
+ {
+ // Invalid.
+ }
+
+ if (!op.Rd.IsRZ)
+ {
+ context.Copy(Register(op.Rd), context.Ballot(pred));
+ }
+ }
+ }
+} \ No newline at end of file