| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876 |
- using Ryujinx.Graphics.Texture;
- using System;
- using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
- namespace Ryujinx.Graphics.Gal.Shader
- {
- static partial class ShaderDecode
- {
- private const int ____ = 0x0;
- private const int R___ = 0x1;
- private const int _G__ = 0x2;
- private const int RG__ = 0x3;
- private const int __B_ = 0x4;
- private const int RGB_ = 0x7;
- private const int ___A = 0x8;
- private const int R__A = 0x9;
- private const int _G_A = 0xa;
- private const int RG_A = 0xb;
- private const int __BA = 0xc;
- private const int R_BA = 0xd;
- private const int _GBA = 0xe;
- private const int RGBA = 0xf;
- private static int[,] MaskLut = new int[,]
- {
- { ____, ____, ____, ____, ____, ____, ____, ____ },
- { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA },
- { R___, _G__, __B_, ___A, RG__, ____, ____, ____ },
- { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
- };
- private static GalTextureTarget TexToTextureTarget(int TexType, bool IsArray)
- {
- switch (TexType)
- {
- case 0:
- return IsArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD;
- case 2:
- return IsArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD;
- case 4:
- if (IsArray)
- throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!");
- return GalTextureTarget.ThreeD;
- case 6:
- return IsArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap;
- default:
- throw new InvalidOperationException();
- }
- }
- private static GalTextureTarget TexsToTextureTarget(int TexType)
- {
- switch (TexType)
- {
- case 0:
- return GalTextureTarget.OneD;
- case 2:
- case 4:
- case 6:
- case 8:
- case 0xa:
- case 0xc:
- return GalTextureTarget.TwoD;
- case 0xe:
- case 0x10:
- case 0x12:
- return GalTextureTarget.TwoDArray;
- case 0x14:
- case 0x16:
- return GalTextureTarget.ThreeD;
- case 0x18:
- case 0x1a:
- return GalTextureTarget.CubeMap;
- default:
- throw new InvalidOperationException();
- }
- }
- public static GalTextureTarget TldsToTextureTarget(int TexType)
- {
- switch (TexType)
- {
- case 0:
- case 2:
- return GalTextureTarget.OneD;
- case 4:
- case 8:
- case 0xa:
- case 0xc:
- case 0x18:
- return GalTextureTarget.TwoD;
- case 0x10:
- return GalTextureTarget.TwoDArray;
- case 0xe:
- return GalTextureTarget.ThreeD;
- default:
- throw new InvalidOperationException();
- }
- }
- public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
- {
- ShaderIrNode[] Opers = OpCode.Abuf20();
- //Used by GS
- ShaderIrOperGpr Vertex = OpCode.Gpr39();
- int Index = 0;
- foreach (ShaderIrNode OperA in Opers)
- {
- ShaderIrOperGpr OperD = OpCode.Gpr0();
- OperD.Index += Index++;
- Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, OperA)));
- }
- }
- 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 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 Texq(ShaderIrBlock Block, long OpCode, int Position)
- {
- ShaderIrNode OperD = OpCode.Gpr0();
- ShaderIrNode OperA = OpCode.Gpr8();
- ShaderTexqInfo Info = (ShaderTexqInfo)(OpCode.Read(22, 0x1f));
- ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
- ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);
- ShaderIrNode OperC = OpCode.Imm13_36();
- ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
- ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);
- Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, Op0)));
- Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
- }
- public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
- {
- TextureInstructionSuffix Suffix;
- int RawSuffix = OpCode.Read(0x34, 0x38);
- switch (RawSuffix)
- {
- case 0:
- Suffix = TextureInstructionSuffix.None;
- break;
- case 0x8:
- Suffix = TextureInstructionSuffix.LZ;
- break;
- case 0x10:
- Suffix = TextureInstructionSuffix.LB;
- break;
- case 0x18:
- Suffix = TextureInstructionSuffix.LL;
- break;
- case 0x30:
- Suffix = TextureInstructionSuffix.LBA;
- break;
- case 0x38:
- Suffix = TextureInstructionSuffix.LLA;
- break;
- default:
- throw new InvalidOperationException($"Invalid Suffix for TEX instruction {RawSuffix}");
- }
- bool IsOffset = OpCode.Read(0x36);
- if (IsOffset)
- Suffix |= TextureInstructionSuffix.AOffI;
- EmitTex(Block, OpCode, Suffix, GprHandle: false);
- }
- public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
- {
- TextureInstructionSuffix Suffix;
- int RawSuffix = OpCode.Read(0x24, 0xe);
- switch (RawSuffix)
- {
- case 0:
- Suffix = TextureInstructionSuffix.None;
- break;
- case 0x2:
- Suffix = TextureInstructionSuffix.LZ;
- break;
- case 0x4:
- Suffix = TextureInstructionSuffix.LB;
- break;
- case 0x6:
- Suffix = TextureInstructionSuffix.LL;
- break;
- case 0xc:
- Suffix = TextureInstructionSuffix.LBA;
- break;
- case 0xe:
- Suffix = TextureInstructionSuffix.LLA;
- break;
- default:
- throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {RawSuffix}");
- }
- bool IsOffset = OpCode.Read(0x23);
- if (IsOffset)
- Suffix |= TextureInstructionSuffix.AOffI;
- EmitTex(Block, OpCode, Suffix, GprHandle: true);
- }
- 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)));
- }
- }
- public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
- {
- TextureInstructionSuffix Suffix;
- int RawSuffix = OpCode.Read(0x34, 0x1e);
- switch (RawSuffix)
- {
- case 0:
- case 0x4:
- case 0x10:
- case 0x16:
- Suffix = TextureInstructionSuffix.LZ;
- break;
- case 0x6:
- case 0x1a:
- Suffix = TextureInstructionSuffix.LL;
- break;
- case 0x8:
- Suffix = TextureInstructionSuffix.DC;
- break;
- case 0x2:
- case 0xe:
- case 0x14:
- case 0x18:
- Suffix = TextureInstructionSuffix.None;
- break;
- case 0xa:
- Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.DC;
- break;
- case 0xc:
- case 0x12:
- Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC;
- break;
- default:
- throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {RawSuffix}");
- }
- GalTextureTarget TextureTarget = TexsToTextureTarget(OpCode.Read(52, 0x1e));
- EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureTarget, Suffix);
- }
- public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
- {
- TextureInstructionSuffix Suffix;
- int RawSuffix = OpCode.Read(0x34, 0x1e);
- switch (RawSuffix)
- {
- case 0:
- case 0x4:
- case 0x8:
- Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOffI;
- break;
- case 0xc:
- Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ;
- break;
- case 0xe:
- case 0x10:
- Suffix = TextureInstructionSuffix.LZ;
- break;
- case 0x2:
- case 0xa:
- Suffix = TextureInstructionSuffix.LL;
- break;
- case 0x18:
- Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.AOffI;
- break;
- default:
- throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {RawSuffix}");
- }
- GalTextureTarget TextureTarget = TldsToTextureTarget(OpCode.Read(52, 0x1e));
- EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureTarget, Suffix);
- }
- public static void Tld4(ShaderIrBlock Block, long OpCode, int Position)
- {
- TextureInstructionSuffix Suffix;
- int RawSuffix = OpCode.Read(0x34, 0xc);
- switch (RawSuffix)
- {
- case 0:
- Suffix = TextureInstructionSuffix.None;
- break;
- case 0x4:
- Suffix = TextureInstructionSuffix.AOffI;
- break;
- case 0x8:
- Suffix = TextureInstructionSuffix.PTP;
- break;
- default:
- throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}");
- }
- bool IsShadow = OpCode.Read(0x32);
- bool IsArray = OpCode.HasArray();
- int ChMask = OpCode.Read(31, 0xf);
- GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
- if (IsShadow)
- {
- Suffix |= TextureInstructionSuffix.DC;
- }
- EmitTld4(Block, OpCode, TextureTarget, Suffix, ChMask, OpCode.Read(0x38, 0x3), false);
- }
- public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position)
- {
- TextureInstructionSuffix Suffix = TextureInstructionSuffix.None;
- bool IsOffset = OpCode.Read(0x33);
- bool IsShadow = OpCode.Read(0x32);
- if (IsOffset)
- {
- Suffix |= TextureInstructionSuffix.AOffI;
- }
- if (IsShadow)
- {
- Suffix |= TextureInstructionSuffix.DC;
- }
- // TLD4S seems to only support 2D textures with RGBA mask?
- EmitTld4(Block, OpCode, GalTextureTarget.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true);
- }
- 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 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)));
- }
- }
- private static bool IsChannelUsed(int ChMask, int Ch)
- {
- return (ChMask & (1 << Ch)) != 0;
- }
- 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;
- }
- }
- }
|