diff options
| author | gdk <gab.dark.100@gmail.com> | 2019-11-08 17:29:41 -0300 |
|---|---|---|
| committer | Thog <thog@protonmail.com> | 2020-01-09 02:13:00 +0100 |
| commit | 769c02235f489f02b1791e6e76dc8b3ab18028ee (patch) | |
| tree | ef0a2ffc5030360d5cef78e7c67e131e44348d50 /Ryujinx.Graphics.Shader/Instructions | |
| parent | 1e8bc29f32cde08616175f8f87405dfa7b8c4025 (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')
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 |
