| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878 |
- using Ryujinx.Graphics.Texture;
- using System;
- using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
- namespace Ryujinx.Graphics.Gal.Shader
- {
- static partial class ShaderDecode
- {
- // ReSharper disable InconsistentNaming
- 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;
- // ReSharper restore InconsistentNaming
- 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;
- }
- }
- }
|