public static void Vmad(ShaderIrBlock Block, long OpCode) { ShaderIrNode OperA = GetOperGpr8(OpCode); ShaderIrNode OperB; if (((OpCode >> 50) & 1) != 0) { OperB = GetOperGpr20(OpCode); } else { OperB = GetOperImm19_20(OpCode); } ShaderIrOperGpr OperC = GetOperGpr39(OpCode); ShaderIrNode Tmp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB); ShaderIrNode Final = new ShaderIrOp(ShaderIrInst.Add, Tmp, OperC); int Shr = (int)((OpCode >> 51) & 3); if (Shr != 0) { int Shift = (Shr == 2) ? 15 : 7; Final = new ShaderIrOp(ShaderIrInst.Lsr, Final, new ShaderIrOperImm(Shift)); } Block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c")); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Final), OpCode)); }
public static void Ld_C(ShaderIrBlock Block, long OpCode) { int Type = (int)(OpCode >> 48) & 7; if (Type > 5) { throw new InvalidOperationException(); } int Count = Type == 5 ? 2 : 1; for (int Index = 0; Index < Count; Index++) { ShaderIrOperCbuf OperA = GetOperCbuf36(OpCode); ShaderIrOperGpr OperD = GetOperGpr0(OpCode); OperA.Pos += Index; OperD.Index += Index; ShaderIrNode Node = OperA; if (Type < 4) { //This is a 8 or 16 bits type. bool Signed = (Type & 1) != 0; int Size = 8 << (Type >> 1); Node = ExtendTo32(Node, Signed, Size); } Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Node), OpCode)); } }
private static void EmitBinaryHalfOp(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) { bool AbsB = OpCode.Read(30); bool NegB = OpCode.Read(31); bool Sat = OpCode.Read(32); bool AbsA = OpCode.Read(44); ShaderIrOperGpr[] VecA = OpCode.GprHalfVec8(); ShaderIrOperGpr[] VecB = OpCode.GprHalfVec20(); HalfOutputType OutputType = (HalfOutputType)OpCode.Read(49, 3); int Elems = OutputType == HalfOutputType.PackedFp16 ? 2 : 1; int First = OutputType == HalfOutputType.MergeH1 ? 1 : 0; for (int Index = First; Index < Elems; Index++) { ShaderIrNode OperA = GetAluFabs(VecA[Index], AbsA); ShaderIrNode OperB = GetAluFabsFneg(VecB[Index], AbsB, NegB); ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB); ShaderIrOperGpr Dst = GetHalfDst(OpCode, OutputType, Index); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, GetAluFsat(Op, Sat)))); } }
public static void Vmad(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode OperA = OpCode.Gpr8(); ShaderIrNode OperB; if (OpCode.Read(50)) { OperB = OpCode.Gpr20(); } else { OperB = OpCode.Imm19_20(); } ShaderIrOperGpr OperC = OpCode.Gpr39(); ShaderIrNode Tmp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB); ShaderIrNode Final = new ShaderIrOp(ShaderIrInst.Add, Tmp, OperC); int Shr = OpCode.Read(51, 3); if (Shr != 0) { int Shift = (Shr == 2) ? 15 : 7; Final = new ShaderIrOp(ShaderIrInst.Lsr, Final, new ShaderIrOperImm(Shift)); } Block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c")); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final))); }
public static void Vmad(ShaderIrBlock block, long opCode, int position) { ShaderIrNode operA = opCode.Gpr8(); ShaderIrNode operB; if (opCode.Read(50)) { operB = opCode.Gpr20(); } else { operB = opCode.Imm19_20(); } ShaderIrOperGpr operC = opCode.Gpr39(); ShaderIrNode tmp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB); ShaderIrNode final = new ShaderIrOp(ShaderIrInst.Add, tmp, operC); int shr = opCode.Read(51, 3); if (shr != 0) { int shift = (shr == 2) ? 15 : 7; final = new ShaderIrOp(ShaderIrInst.Lsr, final, new ShaderIrOperImm(shift)); } block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c")); block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), final))); }
private static void EmitBinaryHalfOp(ShaderIrBlock block, long opCode, ShaderIrInst inst) { bool absB = opCode.Read(30); bool negB = opCode.Read(31); bool sat = opCode.Read(32); bool absA = opCode.Read(44); ShaderIrOperGpr[] vecA = opCode.GprHalfVec8(); ShaderIrOperGpr[] vecB = opCode.GprHalfVec20(); HalfOutputType outputType = (HalfOutputType)opCode.Read(49, 3); int elems = outputType == HalfOutputType.PackedFp16 ? 2 : 1; int first = outputType == HalfOutputType.MergeH1 ? 1 : 0; for (int index = first; index < elems; index++) { ShaderIrNode operA = GetAluFabs(vecA[index], absA); ShaderIrNode operB = GetAluFabsFneg(vecB[index], absB, negB); ShaderIrNode op = new ShaderIrOp(inst, operA, operB); ShaderIrOperGpr dst = GetHalfDst(opCode, outputType, index); block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, GetAluFsat(op, sat)))); } }
private static void EmitTex(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) { //TODO: Support other formats. ShaderIrNode OperA = GetOperGpr8(OpCode); ShaderIrNode OperB = GetOperGpr20(OpCode); ShaderIrNode OperC = GetOperImm13_36(OpCode); for (int Ch = 0; Ch < 4; Ch++) { //Assign it to a temp because the destination registers //may be used as texture coord input aswell. ShaderIrOperGpr Dst = new ShaderIrOperGpr(0x100 + Ch); ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode)); } for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOperGpr Src = new ShaderIrOperGpr(0x100 + Ch); ShaderIrOperGpr Dst = (Ch >> 1) != 0 ? GetOperGpr28(OpCode) : GetOperGpr0(OpCode); Dst.Index += Ch & 1; Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode)); } }
private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle) { //TODO: Support other formats. ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2]; for (int Index = 0; Index < Coords.Length; Index++) { Coords[Index] = GetOperGpr8(OpCode); Coords[Index].Index += Index; if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex) { Coords[Index].Index = ShaderIrOperGpr.ZRIndex; } } int ChMask = (int)(OpCode >> 31) & 0xf; ShaderIrNode OperC = GprHandle ? (ShaderIrNode)GetOperGpr20(OpCode) : (ShaderIrNode)GetOperImm13_36(OpCode); ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta); Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode)); } int RegInc = 0; for (int Ch = 0; Ch < 4; Ch++) { if (!IsChannelUsed(ChMask, Ch)) { continue; } ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrOperGpr Dst = GetOperGpr0(OpCode); Dst.Index += RegInc++; if (Dst.Index >= ShaderIrOperGpr.ZRIndex) { continue; } Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode)); } }
private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle) { //TODO: Support other formats. ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2]; for (int Index = 0; Index < Coords.Length; Index++) { ShaderIrOperGpr CoordReg = OpCode.Gpr8(); CoordReg.Index += Index; if (!CoordReg.IsValidRegister) { CoordReg.Index = ShaderIrOperGpr.ZRIndex; } Coords[Index] = ShaderIrOperGpr.MakeTemporary(Index); Block.AddNode(new ShaderIrAsg(Coords[Index], CoordReg)); } int ChMask = OpCode.Read(31, 0xf); ShaderIrNode OperC = GprHandle ? (ShaderIrNode)OpCode.Gpr20() : (ShaderIrNode)OpCode.Imm13_36(); ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; int RegInc = 0; for (int Ch = 0; Ch < 4; Ch++) { if (!IsChannelUsed(ChMask, Ch)) { continue; } ShaderIrOperGpr Dst = OpCode.Gpr0(); Dst.Index += RegInc++; if (!Dst.IsValidRegister || Dst.IsConst) { continue; } ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); } }
private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock block, params ShaderIrOperGpr[] registers) { ShaderIrOperGpr[] res = new ShaderIrOperGpr[registers.Length]; for (int index = 0; index < res.Length; index++) { res[index] = ShaderIrOperGpr.MakeTemporary(index); block.AddNode(new ShaderIrAsg(res[index], registers[index])); } return(res); }
private static void EmitTex(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) { //TODO: Support other formats. ShaderIrNode OperA = GetOperGpr8(OpCode); ShaderIrNode OperB = GetOperGpr20(OpCode); ShaderIrNode OperC = GetOperImm13_36(OpCode); int LutIndex; LutIndex = GetOperGpr0(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0; LutIndex |= GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 2 : 0; int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7]; for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode)); } int RegInc = 0; for (int Ch = 0; Ch < 4; Ch++) { if (!IsChannelUsed(ChMask, Ch)) { continue; } ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrOperGpr Dst = (RegInc >> 1) != 0 ? GetOperGpr28(OpCode) : GetOperGpr0(OpCode); Dst.Index += RegInc++ & 1; if (Dst.Index >= ShaderIrOperGpr.ZRIndex) { continue; } Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode)); } }
public static void Ld_A(ShaderIrBlock Block, long OpCode) { ShaderIrNode[] Opers = GetOperAbuf20(OpCode); int Index = 0; foreach (ShaderIrNode OperA in Opers) { ShaderIrOperGpr OperD = GetOperGpr0(OpCode); OperD.Index += Index++; Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, OperA), OpCode)); } }
public static void St_A(ShaderIrBlock block, long opCode, int position) { ShaderIrNode[] opers = opCode.Abuf20(); int index = 0; foreach (ShaderIrNode operA in opers) { ShaderIrOperGpr operD = opCode.Gpr0(); operD.Index += index++; block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, operD))); } }
public static void St_A(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode[] Opers = OpCode.Abuf20(); int Index = 0; foreach (ShaderIrNode OperA in Opers) { ShaderIrOperGpr OperD = OpCode.Gpr0(); OperD.Index += Index++; Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, OperD))); } }
public static ShaderIrOperAbuf[] GetOperAbuf20(long OpCode) { int Abuf = (int)(OpCode >> 20) & 0x3ff; int Size = (int)(OpCode >> 47) & 3; ShaderIrOperGpr Vertex = GetOperGpr39(OpCode); ShaderIrOperAbuf[] Opers = new ShaderIrOperAbuf[Size + 1]; for (int Index = 0; Index <= Size; Index++) { Opers[Index] = new ShaderIrOperAbuf(Abuf + Index * 4, Vertex); } return(Opers); }
private static ShaderIrOperAbuf[] Abuf20(this long OpCode) { int Abuf = OpCode.Read(20, 0x3ff); int Size = OpCode.Read(47, 3); ShaderIrOperGpr Vertex = OpCode.Gpr39(); ShaderIrOperAbuf[] Opers = new ShaderIrOperAbuf[Size + 1]; for (int Index = 0; Index <= Size; Index++) { Opers[Index] = new ShaderIrOperAbuf(Abuf + Index * 4, Vertex); } return(Opers); }
private static ShaderIrOperAbuf[] Abuf20(this long opCode) { int abuf = opCode.Read(20, 0x3ff); int size = opCode.Read(47, 3); ShaderIrOperGpr vertex = opCode.Gpr39(); ShaderIrOperAbuf[] opers = new ShaderIrOperAbuf[size + 1]; for (int index = 0; index <= size; index++) { opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex); } return(opers); }
public static void Ld_C(ShaderIrBlock block, long opCode, int position) { int cbufPos = opCode.Read(22, 0x3fff); int cbufIndex = opCode.Read(36, 0x1f); int type = opCode.Read(48, 7); if (type > 5) { throw new InvalidOperationException(); } ShaderIrOperGpr temp = ShaderIrOperGpr.MakeTemporary(); block.AddNode(new ShaderIrAsg(temp, opCode.Gpr8())); int count = type == 5 ? 2 : 1; for (int index = 0; index < count; index++) { ShaderIrOperCbuf operA = new ShaderIrOperCbuf(cbufIndex, cbufPos, temp); ShaderIrOperGpr operD = opCode.Gpr0(); operA.Pos += index; operD.Index += index; if (!operD.IsValidRegister) { break; } ShaderIrNode node = operA; if (type < 4) { //This is a 8 or 16 bits type. bool signed = (type & 1) != 0; int size = 8 << (type >> 1); node = ExtendTo32(node, signed, size); } block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, node))); } }
public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position) { int CbufPos = (int)(OpCode >> 22) & 0x3fff; int CbufIndex = (int)(OpCode >> 36) & 0x1f; int Type = (int)(OpCode >> 48) & 7; if (Type > 5) { throw new InvalidOperationException(); } ShaderIrOperGpr Temp = ShaderIrOperGpr.MakeTemporary(); Block.AddNode(new ShaderIrAsg(Temp, GetOperGpr8(OpCode))); int Count = Type == 5 ? 2 : 1; for (int Index = 0; Index < Count; Index++) { ShaderIrOperCbuf OperA = new ShaderIrOperCbuf(CbufIndex, CbufPos, Temp); ShaderIrOperGpr OperD = GetOperGpr0(OpCode); OperA.Pos += Index; OperD.Index += Index; if (!OperD.IsValidRegister) { break; } ShaderIrNode Node = OperA; if (Type < 4) { //This is a 8 or 16 bits type. bool Signed = (Type & 1) != 0; int Size = 8 << (Type >> 1); Node = ExtendTo32(Node, Signed, Size); } Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Node), OpCode)); } }
public static void Out_R(ShaderIrBlock Block, long OpCode, long Position) { //TODO: Those registers have to be used for something ShaderIrOperGpr Gpr0 = GetOperGpr0(OpCode); ShaderIrOperGpr Gpr8 = GetOperGpr8(OpCode); ShaderIrOperGpr Gpr20 = GetOperGpr20(OpCode); int Type = (int)((OpCode >> 39) & 3); if ((Type & 1) != 0) { Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Emit), OpCode)); } if ((Type & 2) != 0) { Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Cut), OpCode)); } }
public static void Texs(ShaderIrBlock Block, long OpCode) { //TODO: Support other formats. ShaderIrNode OperA = GetOperGpr8(OpCode); ShaderIrNode OperB = GetOperGpr20(OpCode); ShaderIrNode OperC = GetOperGpr28(OpCode); ShaderIrNode OperD = GetOperImm13_36(OpCode); for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Texr + Ch, OperA, OperB, OperD); ShaderIrOperGpr Dst = GetOperGpr0(OpCode); Dst.Index += Ch; Block.AddNode(new ShaderIrAsg(Dst, Op)); } }
private static ShaderIrOperGpr[] GetGprHalfVec2(int gpr, int mask) { if (mask == 1) { //This value is used for FP32, the whole 32-bits register //is used as each element on the vector. return(new ShaderIrOperGpr[] { new ShaderIrOperGpr(gpr), new ShaderIrOperGpr(gpr) }); } ShaderIrOperGpr low = new ShaderIrOperGpr(gpr, 0); ShaderIrOperGpr high = new ShaderIrOperGpr(gpr, 1); return(new ShaderIrOperGpr[] { (mask & 1) != 0 ? high : low, (mask & 2) != 0 ? high : low }); }
private static void EmitSel(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { ShaderIrOperGpr Dst = GetOperGpr0(OpCode); ShaderIrNode Pred = GetOperPred39N(OpCode); ShaderIrNode ResultA = GetOperGpr8(OpCode); ShaderIrNode ResultB; switch (Oper) { case ShaderOper.CR: ResultB = GetOperCbuf34(OpCode); break; case ShaderOper.Imm: ResultB = GetOperImm19_20(OpCode); break; case ShaderOper.RR: ResultB = GetOperGpr20(OpCode); break; default: throw new ArgumentException(nameof(Oper)); } Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultA), false), OpCode)); Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultB), true), OpCode)); }
private static void EmitSel(ShaderIrBlock block, long opCode, ShaderOper oper) { ShaderIrOperGpr dst = opCode.Gpr0(); ShaderIrNode pred = opCode.Pred39N(); ShaderIrNode resultA = opCode.Gpr8(); ShaderIrNode resultB; switch (oper) { case ShaderOper.Cr: resultB = opCode.Cbuf34(); break; case ShaderOper.Imm: resultB = opCode.Imm19_20(); break; case ShaderOper.Rr: resultB = opCode.Gpr20(); break; default: throw new ArgumentException(nameof(oper)); } block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultA), false))); block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultB), true))); }
public static void Mov_R(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrOperGpr Gpr = OpCode.Gpr20(); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Gpr))); }
public static void Mov_R(ShaderIrBlock Block, long OpCode, long Position) { ShaderIrOperGpr Gpr = GetOperGpr20(OpCode); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode)); }
public static void Mov_R(ShaderIrBlock block, long opCode, int position) { ShaderIrOperGpr gpr = opCode.Gpr20(); block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), gpr))); }
private static void EmitTexs(ShaderIrBlock block, long opCode, ShaderIrInst inst, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix) { if (inst == ShaderIrInst.Txlf && textureTarget == GalTextureTarget.CubeArray) { throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); } bool isArray = ImageUtils.IsArray(textureTarget); ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; ShaderIrOperGpr operA = opCode.Gpr8(); ShaderIrOperGpr operB = opCode.Gpr20(); ShaderIrOperGpr suffixExtra = opCode.Gpr20(); suffixExtra.Index += 1; int coordStartIndex = 0; if (isArray) { coordStartIndex++; coords[coords.Length - 1] = opCode.Gpr8(); } switch (coords.Length - coordStartIndex) { case 1: coords[0] = opCode.Gpr8(); break; case 2: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; break; case 3: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; coords[1] = opCode.Gpr8(); coords[1].Index += 1 + coordStartIndex; break; default: throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TEXS"); } int operBIndex = 0; ShaderIrOperGpr levelOfDetail = null; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; // OperB is always the last value // Not applicable to 1d textures if (coords.Length - coordStartIndex != 1) { coords[coords.Length - coordStartIndex - 1] = operB; operBIndex++; } // Encoding of TEXS/TLDS is a bit special and change for 2d textures // NOTE: OperA seems to hold at best two args. // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. if (textureInstructionSuffix != TextureInstructionSuffix.None && textureInstructionSuffix != TextureInstructionSuffix.Lz && textureTarget == GalTextureTarget.TwoD) { coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; operBIndex--; } // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?) if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0) { levelOfDetail = opCode.Gpr20(); levelOfDetail.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } int lutIndex; lutIndex = !opCode.Gpr0().IsConst ? 1 : 0; lutIndex |= !opCode.Gpr28().IsConst ? 2 : 0; if (lutIndex == 0) { //Both destination registers are RZ, do nothing. return; } bool fp16 = !opCode.Read(59); int dstIncrement = 0; ShaderIrOperGpr GetDst() { ShaderIrOperGpr dst; if (fp16) { //FP16 mode, two components are packed on the two //halfs of a 32-bits register, as two half-float values. int halfPart = dstIncrement & 1; switch (lutIndex) { case 1: dst = opCode.GprHalf0(halfPart); break; case 2: dst = opCode.GprHalf28(halfPart); break; case 3: dst = (dstIncrement >> 1) != 0 ? opCode.GprHalf28(halfPart) : opCode.GprHalf0(halfPart); break; default: throw new InvalidOperationException(); } } else { //32-bits mode, each component uses one register. //Two components uses two consecutive registers. switch (lutIndex) { case 1: dst = opCode.Gpr0(); break; case 2: dst = opCode.Gpr28(); break; case 3: dst = (dstIncrement >> 1) != 0 ? opCode.Gpr28() : opCode.Gpr0(); break; default: throw new InvalidOperationException(); } dst.Index += dstIncrement & 1; } dstIncrement++; return(dst); } int chMask = _maskLut[lutIndex, opCode.Read(50, 7)]; if (chMask == 0) { //All channels are disabled, do nothing. return; } ShaderIrNode operC = opCode.Imm13_36(); coords = CoordsRegistersToTempRegisters(block, coords); for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { LevelOfDetail = levelOfDetail, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(inst, operA, operB, operC, meta); ShaderIrOperGpr dst = GetDst(); if (dst.IsValidRegister && !dst.IsConst) { block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } } }
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) { //TODO: Support other formats. ShaderIrNode OperA = GetOperGpr8(OpCode); ShaderIrNode OperB = GetOperGpr20(OpCode); ShaderIrNode OperC = GetOperImm13_36(OpCode); int LutIndex; LutIndex = GetOperGpr0(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 1 : 0; LutIndex |= GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex ? 2 : 0; if (LutIndex == 0) { //Both registers are RZ, color is not written anywhere. //So, the intruction is basically a no-op. return; } int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7]; for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode)); } int RegInc = 0; ShaderIrOperGpr GetDst() { ShaderIrOperGpr Dst; switch (LutIndex) { case 1: Dst = GetOperGpr0(OpCode); break; case 2: Dst = GetOperGpr28(OpCode); break; case 3: Dst = (RegInc >> 1) != 0 ? GetOperGpr28(OpCode) : GetOperGpr0(OpCode); break; default: throw new InvalidOperationException(); } Dst.Index += RegInc++ & 1; return(Dst); } for (int Ch = 0; Ch < 4; Ch++) { if (!IsChannelUsed(ChMask, Ch)) { continue; } ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrOperGpr Dst = GetDst(); if (Dst.Index != ShaderIrOperGpr.ZRIndex) { Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode)); } } }
private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar) { ShaderIrOperGpr operA = opCode.Gpr8(); ShaderIrOperGpr operB = opCode.Gpr20(); ShaderIrOperImm operC = opCode.Imm13_36(); ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)]; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; bool isArray = ImageUtils.IsArray(textureType); int operBIndex = 0; if (scalar) { int coordStartIndex = 0; if (isArray) { coordStartIndex++; coords[coords.Length - 1] = operB; } switch (coords.Length - coordStartIndex) { case 1: coords[0] = opCode.Gpr8(); break; case 2: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; break; case 3: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; coords[1] = opCode.Gpr8(); coords[1].Index += 1 + coordStartIndex; break; default: throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S"); } if (coords.Length - coordStartIndex != 1) { coords[coords.Length - coordStartIndex - 1] = operB; operBIndex++; } if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD) { coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; operBIndex--; } } else { int indexExtraCoord = 0; if (isArray) { indexExtraCoord++; coords[coords.Length - 1] = opCode.Gpr8(); } for (int index = 0; index < coords.Length - indexExtraCoord; index++) { coords[index] = opCode.Gpr8(); coords[index].Index += index; coords[index].Index += indexExtraCoord; if (coords[index].Index > ShaderIrOperGpr.ZrIndex) { coords[index].Index = ShaderIrOperGpr.ZrIndex; } } } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } coords = CoordsRegistersToTempRegisters(block, coords); int regInc = 0; for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrOperGpr dst = opCode.Gpr0(); dst.Index += regInc++; if (!dst.IsValidRegister || dst.IsConst) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords) { Component = component, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Tld4, operA, operB, operC, meta); block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } }