Add ATOMS, LDS, POPC, RED, STS and VOTE shader instructions, start changing the way how global memory is handled
This commit is contained in:
parent
1e8bc29f32
commit
769c02235f
44 changed files with 949 additions and 242 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
private static void LoadLocalOrGlobal(EmitterContext context, bool isGlobal)
|
||||
public static void Sts(EmitterContext context)
|
||||
{
|
||||
EmitStore(context, MemoryRegion.Shared);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
48
Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
Normal file
48
Ryujinx.Graphics.Shader/Instructions/InstEmitVote.cs
Normal file
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue