InstEmitMove.cs
  1  using Ryujinx.Graphics.Shader.Decoders;
  2  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3  using Ryujinx.Graphics.Shader.Translation;
  4  
  5  using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  6  using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  7  
  8  namespace Ryujinx.Graphics.Shader.Instructions
  9  {
 10      static partial class InstEmit
 11      {
 12          public static void MovR(EmitterContext context)
 13          {
 14              InstMovR op = context.GetOp<InstMovR>();
 15  
 16              context.Copy(GetDest(op.Dest), GetSrcReg(context, op.SrcA));
 17          }
 18  
 19          public static void MovI(EmitterContext context)
 20          {
 21              InstMovI op = context.GetOp<InstMovI>();
 22  
 23              context.Copy(GetDest(op.Dest), GetSrcImm(context, op.Imm20));
 24          }
 25  
 26          public static void MovC(EmitterContext context)
 27          {
 28              InstMovC op = context.GetOp<InstMovC>();
 29  
 30              context.Copy(GetDest(op.Dest), GetSrcCbuf(context, op.CbufSlot, op.CbufOffset));
 31          }
 32  
 33          public static void Mov32i(EmitterContext context)
 34          {
 35              InstMov32i op = context.GetOp<InstMov32i>();
 36  
 37              context.Copy(GetDest(op.Dest), GetSrcImm(context, op.Imm32));
 38          }
 39  
 40          public static void R2pR(EmitterContext context)
 41          {
 42              InstR2pR op = context.GetOp<InstR2pR>();
 43  
 44              Operand value = GetSrcReg(context, op.SrcA);
 45              Operand mask = GetSrcReg(context, op.SrcB);
 46  
 47              EmitR2p(context, value, mask, op.ByteSel, op.Ccpr);
 48          }
 49  
 50          public static void R2pI(EmitterContext context)
 51          {
 52              InstR2pI op = context.GetOp<InstR2pI>();
 53  
 54              Operand value = GetSrcReg(context, op.SrcA);
 55              Operand mask = GetSrcImm(context, Imm20ToSInt(op.Imm20));
 56  
 57              EmitR2p(context, value, mask, op.ByteSel, op.Ccpr);
 58          }
 59  
 60          public static void R2pC(EmitterContext context)
 61          {
 62              InstR2pC op = context.GetOp<InstR2pC>();
 63  
 64              Operand value = GetSrcReg(context, op.SrcA);
 65              Operand mask = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
 66  
 67              EmitR2p(context, value, mask, op.ByteSel, op.Ccpr);
 68          }
 69  
 70          public static void S2r(EmitterContext context)
 71          {
 72              InstS2r op = context.GetOp<InstS2r>();
 73  
 74              Operand src;
 75  
 76              switch (op.SReg)
 77              {
 78                  case SReg.LaneId:
 79                      src = EmitLoadSubgroupLaneId(context);
 80                      break;
 81  
 82                  case SReg.InvocationId:
 83                      src = context.Load(StorageKind.Input, IoVariable.InvocationId);
 84                      break;
 85  
 86                  case SReg.YDirection:
 87                      src = ConstF(1); // TODO: Use value from Y direction GPU register.
 88                      break;
 89  
 90                  case SReg.ThreadKill:
 91                      src = context.TranslatorContext.Definitions.Stage == ShaderStage.Fragment ? context.Load(StorageKind.Input, IoVariable.ThreadKill) : Const(0);
 92                      break;
 93  
 94                  case SReg.InvocationInfo:
 95                      if (context.TranslatorContext.Definitions.Stage != ShaderStage.Compute && context.TranslatorContext.Definitions.Stage != ShaderStage.Fragment)
 96                      {
 97                          // Note: Lowest 8-bits seems to contain some primitive index,
 98                          // but it seems to be NVIDIA implementation specific as it's only used
 99                          // to calculate ISBE offsets, so we can just keep it as zero.
100  
101                          if (context.TranslatorContext.Definitions.Stage == ShaderStage.TessellationControl ||
102                              context.TranslatorContext.Definitions.Stage == ShaderStage.TessellationEvaluation)
103                          {
104                              src = context.ShiftLeft(context.Load(StorageKind.Input, IoVariable.PatchVertices), Const(16));
105                          }
106                          else
107                          {
108                              src = Const(context.TranslatorContext.Definitions.InputTopology.ToInputVertices() << 16);
109                          }
110                      }
111                      else
112                      {
113                          src = Const(0);
114                      }
115                      break;
116  
117                  case SReg.TId:
118                      Operand tidX = context.Load(StorageKind.Input, IoVariable.ThreadId, null, Const(0));
119                      Operand tidY = context.Load(StorageKind.Input, IoVariable.ThreadId, null, Const(1));
120                      Operand tidZ = context.Load(StorageKind.Input, IoVariable.ThreadId, null, Const(2));
121  
122                      tidY = context.ShiftLeft(tidY, Const(16));
123                      tidZ = context.ShiftLeft(tidZ, Const(26));
124  
125                      src = context.BitwiseOr(tidX, context.BitwiseOr(tidY, tidZ));
126                      break;
127  
128                  case SReg.TIdX:
129                      src = context.Load(StorageKind.Input, IoVariable.ThreadId, null, Const(0));
130                      break;
131                  case SReg.TIdY:
132                      src = context.Load(StorageKind.Input, IoVariable.ThreadId, null, Const(1));
133                      break;
134                  case SReg.TIdZ:
135                      src = context.Load(StorageKind.Input, IoVariable.ThreadId, null, Const(2));
136                      break;
137  
138                  case SReg.CtaIdX:
139                      src = context.Load(StorageKind.Input, IoVariable.CtaId, null, Const(0));
140                      break;
141                  case SReg.CtaIdY:
142                      src = context.Load(StorageKind.Input, IoVariable.CtaId, null, Const(1));
143                      break;
144                  case SReg.CtaIdZ:
145                      src = context.Load(StorageKind.Input, IoVariable.CtaId, null, Const(2));
146                      break;
147  
148                  case SReg.EqMask:
149                      src = EmitLoadSubgroupMask(context, IoVariable.SubgroupEqMask);
150                      break;
151                  case SReg.LtMask:
152                      src = EmitLoadSubgroupMask(context, IoVariable.SubgroupLtMask);
153                      break;
154                  case SReg.LeMask:
155                      src = EmitLoadSubgroupMask(context, IoVariable.SubgroupLeMask);
156                      break;
157                  case SReg.GtMask:
158                      src = EmitLoadSubgroupMask(context, IoVariable.SubgroupGtMask);
159                      break;
160                  case SReg.GeMask:
161                      src = EmitLoadSubgroupMask(context, IoVariable.SubgroupGeMask);
162                      break;
163  
164                  default:
165                      src = Const(0);
166                      break;
167              }
168  
169              context.Copy(GetDest(op.Dest), src);
170          }
171  
172          private static Operand EmitLoadSubgroupLaneId(EmitterContext context)
173          {
174              if (context.TranslatorContext.GpuAccessor.QueryHostSubgroupSize() <= 32)
175              {
176                  return context.Load(StorageKind.Input, IoVariable.SubgroupLaneId);
177              }
178  
179              return context.BitwiseAnd(context.Load(StorageKind.Input, IoVariable.SubgroupLaneId), Const(0x1f));
180          }
181  
182          private static Operand EmitLoadSubgroupMask(EmitterContext context, IoVariable ioVariable)
183          {
184              int subgroupSize = context.TranslatorContext.GpuAccessor.QueryHostSubgroupSize();
185  
186              if (subgroupSize <= 32)
187              {
188                  return context.Load(StorageKind.Input, ioVariable, null, Const(0));
189              }
190              else if (subgroupSize == 64)
191              {
192                  Operand laneId = context.Load(StorageKind.Input, IoVariable.SubgroupLaneId);
193                  Operand low = context.Load(StorageKind.Input, ioVariable, null, Const(0));
194                  Operand high = context.Load(StorageKind.Input, ioVariable, null, Const(1));
195  
196                  return context.ConditionalSelect(context.BitwiseAnd(laneId, Const(32)), high, low);
197              }
198              else
199              {
200                  Operand laneId = context.Load(StorageKind.Input, IoVariable.SubgroupLaneId);
201                  Operand element = context.ShiftRightU32(laneId, Const(5));
202  
203                  Operand res = context.Load(StorageKind.Input, ioVariable, null, Const(0));
204                  res = context.ConditionalSelect(
205                      context.ICompareEqual(element, Const(1)),
206                      context.Load(StorageKind.Input, ioVariable, null, Const(1)), res);
207                  res = context.ConditionalSelect(
208                      context.ICompareEqual(element, Const(2)),
209                      context.Load(StorageKind.Input, ioVariable, null, Const(2)), res);
210                  res = context.ConditionalSelect(
211                      context.ICompareEqual(element, Const(3)),
212                      context.Load(StorageKind.Input, ioVariable, null, Const(3)), res);
213  
214                  return res;
215              }
216          }
217  
218          public static void SelR(EmitterContext context)
219          {
220              InstSelR op = context.GetOp<InstSelR>();
221  
222              Operand srcA = GetSrcReg(context, op.SrcA);
223              Operand srcB = GetSrcReg(context, op.SrcB);
224              Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
225  
226              EmitSel(context, srcA, srcB, srcPred, op.Dest);
227          }
228  
229          public static void SelI(EmitterContext context)
230          {
231              InstSelI op = context.GetOp<InstSelI>();
232  
233              Operand srcA = GetSrcReg(context, op.SrcA);
234              Operand srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
235              Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
236  
237              EmitSel(context, srcA, srcB, srcPred, op.Dest);
238          }
239  
240          public static void SelC(EmitterContext context)
241          {
242              InstSelC op = context.GetOp<InstSelC>();
243  
244              Operand srcA = GetSrcReg(context, op.SrcA);
245              Operand srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
246              Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
247  
248              EmitSel(context, srcA, srcB, srcPred, op.Dest);
249          }
250  
251          private static void EmitR2p(EmitterContext context, Operand value, Operand mask, ByteSel byteSel, bool ccpr)
252          {
253              Operand Test(Operand value, int bit)
254              {
255                  return context.ICompareNotEqual(context.BitwiseAnd(value, Const(1 << bit)), Const(0));
256              }
257  
258              int count = ccpr ? RegisterConsts.FlagsCount : RegisterConsts.PredsCount;
259              RegisterType type = ccpr ? RegisterType.Flag : RegisterType.Predicate;
260              int shift = (int)byteSel * 8;
261  
262              for (int bit = 0; bit < count; bit++)
263              {
264                  Operand flag = Register(bit, type);
265                  Operand res = context.ConditionalSelect(Test(mask, bit), Test(value, bit + shift), flag);
266                  context.Copy(flag, res);
267              }
268          }
269  
270          private static void EmitSel(EmitterContext context, Operand srcA, Operand srcB, Operand srcPred, int rd)
271          {
272              Operand res = context.ConditionalSelect(srcPred, srcA, srcB);
273  
274              context.Copy(GetDest(rd), res);
275          }
276      }
277  }