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 }