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));
            }
        }
Exemple #3
0
        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))));
            }
        }
Exemple #4
0
        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)));
        }
Exemple #5
0
        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)));
        }
Exemple #6
0
        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))));
            }
        }
Exemple #7
0
        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));
            }
        }
Exemple #8
0
        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));
            }
        }
Exemple #9
0
        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)));
            }
        }
Exemple #14
0
        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)));
            }
        }
Exemple #15
0
        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);
        }
Exemple #16
0
        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)));
            }
        }
Exemple #19
0
        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));
            }
        }
Exemple #21
0
        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));
        }
Exemple #24
0
        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));
        }
Exemple #27
0
        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)));
                }
            }
        }
Exemple #29
0
        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)));
            }
        }