aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
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/InstEmitMemory.cs
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/InstEmitMemory.cs')
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs178
1 files changed, 157 insertions, 21 deletions
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;
}
}
}