Пример #1
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));
            }
        }
Пример #2
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));
            }
        }
Пример #3
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)));
            }
        }
Пример #4
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);

            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));
            }
        }
Пример #5
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));
                }
            }
        }
Пример #6
0
        private void Traverse(ShaderIrNode[] nodes, ShaderIrNode parent, ShaderIrNode node)
        {
            switch (node)
            {
            case ShaderIrAsg asg:
            {
                Traverse(nodes, asg, asg.Dst);
                Traverse(nodes, asg, asg.Src);

                break;
            }

            case ShaderIrCond cond:
            {
                Traverse(nodes, cond, cond.Pred);
                Traverse(nodes, cond, cond.Child);

                break;
            }

            case ShaderIrOp op:
            {
                Traverse(nodes, op, op.OperandA);
                Traverse(nodes, op, op.OperandB);
                Traverse(nodes, op, op.OperandC);

                if (op.Inst == ShaderIrInst.Texq ||
                    op.Inst == ShaderIrInst.Texs ||
                    op.Inst == ShaderIrInst.Tld4 ||
                    op.Inst == ShaderIrInst.Txlf)
                {
                    int handle = ((ShaderIrOperImm)op.OperandC).Value;

                    int index = handle - TexStartIndex;

                    string name = _stagePrefix + TextureName + index;

                    GalTextureTarget textureTarget;

                    TextureInstructionSuffix textureInstructionSuffix;

                    // TODO: Non 2D texture type for TEXQ?
                    if (op.Inst == ShaderIrInst.Texq)
                    {
                        textureTarget            = GalTextureTarget.TwoD;
                        textureInstructionSuffix = TextureInstructionSuffix.None;
                    }
                    else
                    {
                        ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);

                        textureTarget            = meta.TextureTarget;
                        textureInstructionSuffix = meta.TextureInstructionSuffix;
                    }

                    m_Textures.TryAdd(handle, new ShaderDeclInfo(name, handle, false, 0, 1, textureTarget, textureInstructionSuffix));
                }
                else if (op.Inst == ShaderIrInst.Texb)
                {
                    ShaderIrNode handleSrc = null;

                    int index = Array.IndexOf(nodes, parent) - 1;

                    for (; index >= 0; index--)
                    {
                        ShaderIrNode curr = nodes[index];

                        if (curr is ShaderIrAsg asg && asg.Dst is ShaderIrOperGpr gpr)
                        {
                            if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index)
                            {
                                handleSrc = asg.Src;

                                break;
                            }
                        }
                    }

                    if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf)
                    {
                        ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
                        string          name = _stagePrefix + TextureName + "_cb" + cbuf.Index + "_" + cbuf.Pos;

                        m_CbTextures.Add(op, new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index, 1, meta.TextureTarget, meta.TextureInstructionSuffix));
                    }
                    else
                    {
                        throw new NotImplementedException("Shader TEX.B instruction is not fully supported!");
                    }
                }
                break;
            }

            case ShaderIrOperCbuf cbuf:
            {
                if (!m_Uniforms.ContainsKey(cbuf.Index))
                {
                    string name = _stagePrefix + UniformName + cbuf.Index;

                    ShaderDeclInfo declInfo = new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index);

                    m_Uniforms.Add(cbuf.Index, declInfo);
                }
                break;
            }

            case ShaderIrOperAbuf abuf:
            {
                //This is a built-in variable.
                if (abuf.Offs == LayerAttr ||
                    abuf.Offs == PointSizeAttr ||
                    abuf.Offs == PointCoordAttrX ||
                    abuf.Offs == PointCoordAttrY ||
                    abuf.Offs == VertexIdAttr ||
                    abuf.Offs == InstanceIdAttr ||
                    abuf.Offs == FaceAttr)
                {
                    break;
                }

                int index = abuf.Offs >> 4;
                int elem  = (abuf.Offs >> 2) & 3;

                int glslIndex = index - AttrStartIndex;

                if (glslIndex < 0)
                {
                    return;
                }

                ShaderDeclInfo declInfo;

                if (parent is ShaderIrAsg asg && asg.Dst == node)
                {
                    if (!m_OutAttributes.TryGetValue(index, out declInfo))
                    {
                        declInfo = new ShaderDeclInfo(OutAttrName + glslIndex, glslIndex);

                        m_OutAttributes.Add(index, declInfo);
                    }
                }
Пример #7
0
        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)));
            }
        }
Пример #8
0
        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)));
                }
            }
        }
Пример #9
0
        private static void EmitTex(ShaderIrBlock block, long opCode, TextureInstructionSuffix textureInstructionSuffix, bool gprHandle)
        {
            bool isArray = opCode.HasArray();

            GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray);

            bool hasDepthCompare = opCode.Read(0x32);

            if (hasDepthCompare)
            {
                textureInstructionSuffix |= TextureInstructionSuffix.Dc;
            }

            ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)];

            int indexExtraCoord = 0;

            if (isArray)
            {
                indexExtraCoord++;

                coords[coords.Length - 1] = opCode.Gpr8();
            }


            for (int index = 0; index < coords.Length - indexExtraCoord; index++)
            {
                ShaderIrOperGpr coordReg = opCode.Gpr8();

                coordReg.Index += index;

                coordReg.Index += indexExtraCoord;

                if (!coordReg.IsValidRegister)
                {
                    coordReg.Index = ShaderIrOperGpr.ZrIndex;
                }

                coords[index] = coordReg;
            }

            int chMask = opCode.Read(31, 0xf);

            ShaderIrOperGpr levelOfDetail = null;
            ShaderIrOperGpr offset        = null;
            ShaderIrOperGpr depthCompare  = null;

            // TODO: determine first argument when TEX.B is used
            int operBIndex = gprHandle ? 1 : 0;

            if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0 ||
                (textureInstructionSuffix & TextureInstructionSuffix.Lb) != 0 ||
                (textureInstructionSuffix & TextureInstructionSuffix.Lba) != 0 ||
                (textureInstructionSuffix & TextureInstructionSuffix.Lla) != 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++;
            }

            // ???
            ShaderIrNode operC = gprHandle
                ? (ShaderIrNode)opCode.Gpr20()
                : (ShaderIrNode)opCode.Imm13_36();

            ShaderIrInst inst = gprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs;

            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, textureTarget, textureInstructionSuffix, coords)
                {
                    LevelOfDetail = levelOfDetail,
                    Offset        = offset,
                    DepthCompare  = depthCompare
                };

                ShaderIrOp op = new ShaderIrOp(inst, coords[0], coords.Length > 1 ? coords[1] : null, operC, meta);

                block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op)));
            }
        }
Пример #10
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);

            bool TwoDests = GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex;

            int ChMask;

            switch ((OpCode >> 50) & 7)
            {
            case 0: ChMask = TwoDests ? 0x7 : 0x1; break;

            case 1: ChMask = TwoDests ? 0xb : 0x2; break;

            case 2: ChMask = TwoDests ? 0xd : 0x4; break;

            case 3: ChMask = TwoDests ? 0xe : 0x8; break;

            case 4: ChMask = TwoDests ? 0xf : 0x3; break;

            default: throw new InvalidOperationException();
            }

            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));
            }
        }
Пример #11
0
        private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
        {
            //TODO: Support other formats.
            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();

            ShaderIrOperGpr Coord0 = ShaderIrOperGpr.MakeTemporary(0);
            ShaderIrOperGpr Coord1 = ShaderIrOperGpr.MakeTemporary(1);

            Block.AddNode(new ShaderIrAsg(Coord0, OpCode.Gpr8()));
            Block.AddNode(new ShaderIrAsg(Coord1, OpCode.Gpr20()));

            for (int Ch = 0; Ch < 4; Ch++)
            {
                if (!IsChannelUsed(ChMask, Ch))
                {
                    continue;
                }

                ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);

                ShaderIrOp Op = new ShaderIrOp(Inst, Coord0, Coord1, OperC, Meta);

                ShaderIrOperGpr Dst = GetDst();

                if (Dst.IsValidRegister && !Dst.IsConst)
                {
                    Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
                }
            }
        }