ShaderDecodeMem.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. using Ryujinx.Graphics.Texture;
  2. using System;
  3. using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
  4. namespace Ryujinx.Graphics.Gal.Shader
  5. {
  6. static partial class ShaderDecode
  7. {
  8. private const int ____ = 0x0;
  9. private const int R___ = 0x1;
  10. private const int _G__ = 0x2;
  11. private const int RG__ = 0x3;
  12. private const int __B_ = 0x4;
  13. private const int RGB_ = 0x7;
  14. private const int ___A = 0x8;
  15. private const int R__A = 0x9;
  16. private const int _G_A = 0xa;
  17. private const int RG_A = 0xb;
  18. private const int __BA = 0xc;
  19. private const int R_BA = 0xd;
  20. private const int _GBA = 0xe;
  21. private const int RGBA = 0xf;
  22. private static int[,] MaskLut = new int[,]
  23. {
  24. { ____, ____, ____, ____, ____, ____, ____, ____ },
  25. { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA },
  26. { R___, _G__, __B_, ___A, RG__, ____, ____, ____ },
  27. { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
  28. };
  29. private static GalTextureTarget TexToTextureTarget(int TexType, bool IsArray)
  30. {
  31. switch (TexType)
  32. {
  33. case 0:
  34. return IsArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD;
  35. case 2:
  36. return IsArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD;
  37. case 4:
  38. if (IsArray)
  39. throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!");
  40. return GalTextureTarget.ThreeD;
  41. case 6:
  42. return IsArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap;
  43. default:
  44. throw new InvalidOperationException();
  45. }
  46. }
  47. private static GalTextureTarget TexsToTextureTarget(int TexType)
  48. {
  49. switch (TexType)
  50. {
  51. case 0:
  52. return GalTextureTarget.OneD;
  53. case 2:
  54. case 4:
  55. case 6:
  56. case 8:
  57. case 0xa:
  58. case 0xc:
  59. return GalTextureTarget.TwoD;
  60. case 0xe:
  61. case 0x10:
  62. case 0x12:
  63. return GalTextureTarget.TwoDArray;
  64. case 0x14:
  65. case 0x16:
  66. return GalTextureTarget.ThreeD;
  67. case 0x18:
  68. case 0x1a:
  69. return GalTextureTarget.CubeMap;
  70. default:
  71. throw new InvalidOperationException();
  72. }
  73. }
  74. public static GalTextureTarget TldsToTextureTarget(int TexType)
  75. {
  76. switch (TexType)
  77. {
  78. case 0:
  79. case 2:
  80. return GalTextureTarget.OneD;
  81. case 4:
  82. case 8:
  83. case 0xa:
  84. case 0xc:
  85. case 0x18:
  86. return GalTextureTarget.TwoD;
  87. case 0x10:
  88. return GalTextureTarget.TwoDArray;
  89. case 0xe:
  90. return GalTextureTarget.ThreeD;
  91. default:
  92. throw new InvalidOperationException();
  93. }
  94. }
  95. public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
  96. {
  97. ShaderIrNode[] Opers = OpCode.Abuf20();
  98. //Used by GS
  99. ShaderIrOperGpr Vertex = OpCode.Gpr39();
  100. int Index = 0;
  101. foreach (ShaderIrNode OperA in Opers)
  102. {
  103. ShaderIrOperGpr OperD = OpCode.Gpr0();
  104. OperD.Index += Index++;
  105. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, OperA)));
  106. }
  107. }
  108. public static void Ld_C(ShaderIrBlock Block, long OpCode, int Position)
  109. {
  110. int CbufPos = OpCode.Read(22, 0x3fff);
  111. int CbufIndex = OpCode.Read(36, 0x1f);
  112. int Type = OpCode.Read(48, 7);
  113. if (Type > 5)
  114. {
  115. throw new InvalidOperationException();
  116. }
  117. ShaderIrOperGpr Temp = ShaderIrOperGpr.MakeTemporary();
  118. Block.AddNode(new ShaderIrAsg(Temp, OpCode.Gpr8()));
  119. int Count = Type == 5 ? 2 : 1;
  120. for (int Index = 0; Index < Count; Index++)
  121. {
  122. ShaderIrOperCbuf OperA = new ShaderIrOperCbuf(CbufIndex, CbufPos, Temp);
  123. ShaderIrOperGpr OperD = OpCode.Gpr0();
  124. OperA.Pos += Index;
  125. OperD.Index += Index;
  126. if (!OperD.IsValidRegister)
  127. {
  128. break;
  129. }
  130. ShaderIrNode Node = OperA;
  131. if (Type < 4)
  132. {
  133. //This is a 8 or 16 bits type.
  134. bool Signed = (Type & 1) != 0;
  135. int Size = 8 << (Type >> 1);
  136. Node = ExtendTo32(Node, Signed, Size);
  137. }
  138. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, Node)));
  139. }
  140. }
  141. public static void St_A(ShaderIrBlock Block, long OpCode, int Position)
  142. {
  143. ShaderIrNode[] Opers = OpCode.Abuf20();
  144. int Index = 0;
  145. foreach (ShaderIrNode OperA in Opers)
  146. {
  147. ShaderIrOperGpr OperD = OpCode.Gpr0();
  148. OperD.Index += Index++;
  149. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, OperD)));
  150. }
  151. }
  152. public static void Texq(ShaderIrBlock Block, long OpCode, int Position)
  153. {
  154. ShaderIrNode OperD = OpCode.Gpr0();
  155. ShaderIrNode OperA = OpCode.Gpr8();
  156. ShaderTexqInfo Info = (ShaderTexqInfo)(OpCode.Read(22, 0x1f));
  157. ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
  158. ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);
  159. ShaderIrNode OperC = OpCode.Imm13_36();
  160. ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
  161. ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);
  162. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, Op0)));
  163. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
  164. }
  165. public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
  166. {
  167. TextureInstructionSuffix Suffix;
  168. int RawSuffix = OpCode.Read(0x34, 0x38);
  169. switch (RawSuffix)
  170. {
  171. case 0:
  172. Suffix = TextureInstructionSuffix.None;
  173. break;
  174. case 0x8:
  175. Suffix = TextureInstructionSuffix.LZ;
  176. break;
  177. case 0x10:
  178. Suffix = TextureInstructionSuffix.LB;
  179. break;
  180. case 0x18:
  181. Suffix = TextureInstructionSuffix.LL;
  182. break;
  183. case 0x30:
  184. Suffix = TextureInstructionSuffix.LBA;
  185. break;
  186. case 0x38:
  187. Suffix = TextureInstructionSuffix.LLA;
  188. break;
  189. default:
  190. throw new InvalidOperationException($"Invalid Suffix for TEX instruction {RawSuffix}");
  191. }
  192. bool IsOffset = OpCode.Read(0x36);
  193. if (IsOffset)
  194. Suffix |= TextureInstructionSuffix.AOffI;
  195. EmitTex(Block, OpCode, Suffix, GprHandle: false);
  196. }
  197. public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
  198. {
  199. TextureInstructionSuffix Suffix;
  200. int RawSuffix = OpCode.Read(0x24, 0xe);
  201. switch (RawSuffix)
  202. {
  203. case 0:
  204. Suffix = TextureInstructionSuffix.None;
  205. break;
  206. case 0x2:
  207. Suffix = TextureInstructionSuffix.LZ;
  208. break;
  209. case 0x4:
  210. Suffix = TextureInstructionSuffix.LB;
  211. break;
  212. case 0x6:
  213. Suffix = TextureInstructionSuffix.LL;
  214. break;
  215. case 0xc:
  216. Suffix = TextureInstructionSuffix.LBA;
  217. break;
  218. case 0xe:
  219. Suffix = TextureInstructionSuffix.LLA;
  220. break;
  221. default:
  222. throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {RawSuffix}");
  223. }
  224. bool IsOffset = OpCode.Read(0x23);
  225. if (IsOffset)
  226. Suffix |= TextureInstructionSuffix.AOffI;
  227. EmitTex(Block, OpCode, Suffix, GprHandle: true);
  228. }
  229. private static void EmitTex(ShaderIrBlock Block, long OpCode, TextureInstructionSuffix TextureInstructionSuffix, bool GprHandle)
  230. {
  231. bool IsArray = OpCode.HasArray();
  232. GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
  233. bool HasDepthCompare = OpCode.Read(0x32);
  234. if (HasDepthCompare)
  235. {
  236. TextureInstructionSuffix |= TextureInstructionSuffix.DC;
  237. }
  238. ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)];
  239. int IndexExtraCoord = 0;
  240. if (IsArray)
  241. {
  242. IndexExtraCoord++;
  243. Coords[Coords.Length - 1] = OpCode.Gpr8();
  244. }
  245. for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++)
  246. {
  247. ShaderIrOperGpr CoordReg = OpCode.Gpr8();
  248. CoordReg.Index += Index;
  249. CoordReg.Index += IndexExtraCoord;
  250. if (!CoordReg.IsValidRegister)
  251. {
  252. CoordReg.Index = ShaderIrOperGpr.ZRIndex;
  253. }
  254. Coords[Index] = CoordReg;
  255. }
  256. int ChMask = OpCode.Read(31, 0xf);
  257. ShaderIrOperGpr LevelOfDetail = null;
  258. ShaderIrOperGpr Offset = null;
  259. ShaderIrOperGpr DepthCompare = null;
  260. // TODO: determine first argument when TEX.B is used
  261. int OperBIndex = GprHandle ? 1 : 0;
  262. if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0 ||
  263. (TextureInstructionSuffix & TextureInstructionSuffix.LB) != 0 ||
  264. (TextureInstructionSuffix & TextureInstructionSuffix.LBA) != 0 ||
  265. (TextureInstructionSuffix & TextureInstructionSuffix.LLA) != 0)
  266. {
  267. LevelOfDetail = OpCode.Gpr20();
  268. LevelOfDetail.Index += OperBIndex;
  269. OperBIndex++;
  270. }
  271. if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
  272. {
  273. Offset = OpCode.Gpr20();
  274. Offset.Index += OperBIndex;
  275. OperBIndex++;
  276. }
  277. if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
  278. {
  279. DepthCompare = OpCode.Gpr20();
  280. DepthCompare.Index += OperBIndex;
  281. OperBIndex++;
  282. }
  283. // ???
  284. ShaderIrNode OperC = GprHandle
  285. ? (ShaderIrNode)OpCode.Gpr20()
  286. : (ShaderIrNode)OpCode.Imm13_36();
  287. ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs;
  288. Coords = CoordsRegistersToTempRegisters(Block, Coords);
  289. int RegInc = 0;
  290. for (int Ch = 0; Ch < 4; Ch++)
  291. {
  292. if (!IsChannelUsed(ChMask, Ch))
  293. {
  294. continue;
  295. }
  296. ShaderIrOperGpr Dst = OpCode.Gpr0();
  297. Dst.Index += RegInc++;
  298. if (!Dst.IsValidRegister || Dst.IsConst)
  299. {
  300. continue;
  301. }
  302. ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords)
  303. {
  304. LevelOfDetail = LevelOfDetail,
  305. Offset = Offset,
  306. DepthCompare = DepthCompare
  307. };
  308. ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords.Length > 1 ? Coords[1] : null, OperC, Meta);
  309. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
  310. }
  311. }
  312. public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
  313. {
  314. TextureInstructionSuffix Suffix;
  315. int RawSuffix = OpCode.Read(0x34, 0x1e);
  316. switch (RawSuffix)
  317. {
  318. case 0:
  319. case 0x4:
  320. case 0x10:
  321. case 0x16:
  322. Suffix = TextureInstructionSuffix.LZ;
  323. break;
  324. case 0x6:
  325. case 0x1a:
  326. Suffix = TextureInstructionSuffix.LL;
  327. break;
  328. case 0x8:
  329. Suffix = TextureInstructionSuffix.DC;
  330. break;
  331. case 0x2:
  332. case 0xe:
  333. case 0x14:
  334. case 0x18:
  335. Suffix = TextureInstructionSuffix.None;
  336. break;
  337. case 0xa:
  338. Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.DC;
  339. break;
  340. case 0xc:
  341. case 0x12:
  342. Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC;
  343. break;
  344. default:
  345. throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {RawSuffix}");
  346. }
  347. GalTextureTarget TextureTarget = TexsToTextureTarget(OpCode.Read(52, 0x1e));
  348. EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureTarget, Suffix);
  349. }
  350. public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
  351. {
  352. TextureInstructionSuffix Suffix;
  353. int RawSuffix = OpCode.Read(0x34, 0x1e);
  354. switch (RawSuffix)
  355. {
  356. case 0:
  357. case 0x4:
  358. case 0x8:
  359. Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOffI;
  360. break;
  361. case 0xc:
  362. Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ;
  363. break;
  364. case 0xe:
  365. case 0x10:
  366. Suffix = TextureInstructionSuffix.LZ;
  367. break;
  368. case 0x2:
  369. case 0xa:
  370. Suffix = TextureInstructionSuffix.LL;
  371. break;
  372. case 0x18:
  373. Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.AOffI;
  374. break;
  375. default:
  376. throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {RawSuffix}");
  377. }
  378. GalTextureTarget TextureTarget = TldsToTextureTarget(OpCode.Read(52, 0x1e));
  379. EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureTarget, Suffix);
  380. }
  381. public static void Tld4(ShaderIrBlock Block, long OpCode, int Position)
  382. {
  383. TextureInstructionSuffix Suffix;
  384. int RawSuffix = OpCode.Read(0x34, 0xc);
  385. switch (RawSuffix)
  386. {
  387. case 0:
  388. Suffix = TextureInstructionSuffix.None;
  389. break;
  390. case 0x4:
  391. Suffix = TextureInstructionSuffix.AOffI;
  392. break;
  393. case 0x8:
  394. Suffix = TextureInstructionSuffix.PTP;
  395. break;
  396. default:
  397. throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}");
  398. }
  399. bool IsShadow = OpCode.Read(0x32);
  400. bool IsArray = OpCode.HasArray();
  401. int ChMask = OpCode.Read(31, 0xf);
  402. GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
  403. if (IsShadow)
  404. {
  405. Suffix |= TextureInstructionSuffix.DC;
  406. }
  407. EmitTld4(Block, OpCode, TextureTarget, Suffix, ChMask, OpCode.Read(0x38, 0x3), false);
  408. }
  409. public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position)
  410. {
  411. TextureInstructionSuffix Suffix = TextureInstructionSuffix.None;
  412. bool IsOffset = OpCode.Read(0x33);
  413. bool IsShadow = OpCode.Read(0x32);
  414. if (IsOffset)
  415. {
  416. Suffix |= TextureInstructionSuffix.AOffI;
  417. }
  418. if (IsShadow)
  419. {
  420. Suffix |= TextureInstructionSuffix.DC;
  421. }
  422. // TLD4S seems to only support 2D textures with RGBA mask?
  423. EmitTld4(Block, OpCode, GalTextureTarget.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true);
  424. }
  425. private static void EmitTexs(ShaderIrBlock Block,
  426. long OpCode,
  427. ShaderIrInst Inst,
  428. GalTextureTarget TextureTarget,
  429. TextureInstructionSuffix TextureInstructionSuffix)
  430. {
  431. if (Inst == ShaderIrInst.Txlf && TextureTarget == GalTextureTarget.CubeArray)
  432. {
  433. throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!");
  434. }
  435. bool IsArray = ImageUtils.IsArray(TextureTarget);
  436. ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)];
  437. ShaderIrOperGpr OperA = OpCode.Gpr8();
  438. ShaderIrOperGpr OperB = OpCode.Gpr20();
  439. ShaderIrOperGpr SuffixExtra = OpCode.Gpr20();
  440. SuffixExtra.Index += 1;
  441. int CoordStartIndex = 0;
  442. if (IsArray)
  443. {
  444. CoordStartIndex++;
  445. Coords[Coords.Length - 1] = OpCode.Gpr8();
  446. }
  447. switch (Coords.Length - CoordStartIndex)
  448. {
  449. case 1:
  450. Coords[0] = OpCode.Gpr8();
  451. break;
  452. case 2:
  453. Coords[0] = OpCode.Gpr8();
  454. Coords[0].Index += CoordStartIndex;
  455. break;
  456. case 3:
  457. Coords[0] = OpCode.Gpr8();
  458. Coords[0].Index += CoordStartIndex;
  459. Coords[1] = OpCode.Gpr8();
  460. Coords[1].Index += 1 + CoordStartIndex;
  461. break;
  462. default:
  463. throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TEXS");
  464. }
  465. int OperBIndex = 0;
  466. ShaderIrOperGpr LevelOfDetail = null;
  467. ShaderIrOperGpr Offset = null;
  468. ShaderIrOperGpr DepthCompare = null;
  469. // OperB is always the last value
  470. // Not applicable to 1d textures
  471. if (Coords.Length - CoordStartIndex != 1)
  472. {
  473. Coords[Coords.Length - CoordStartIndex - 1] = OperB;
  474. OperBIndex++;
  475. }
  476. // Encoding of TEXS/TLDS is a bit special and change for 2d textures
  477. // NOTE: OperA seems to hold at best two args.
  478. // 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.
  479. if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureInstructionSuffix != TextureInstructionSuffix.LZ && TextureTarget == GalTextureTarget.TwoD)
  480. {
  481. Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8();
  482. Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1;
  483. OperBIndex--;
  484. }
  485. // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?)
  486. if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0)
  487. {
  488. LevelOfDetail = OpCode.Gpr20();
  489. LevelOfDetail.Index += OperBIndex;
  490. OperBIndex++;
  491. }
  492. if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
  493. {
  494. Offset = OpCode.Gpr20();
  495. Offset.Index += OperBIndex;
  496. OperBIndex++;
  497. }
  498. if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
  499. {
  500. DepthCompare = OpCode.Gpr20();
  501. DepthCompare.Index += OperBIndex;
  502. OperBIndex++;
  503. }
  504. int LutIndex;
  505. LutIndex = !OpCode.Gpr0().IsConst ? 1 : 0;
  506. LutIndex |= !OpCode.Gpr28().IsConst ? 2 : 0;
  507. if (LutIndex == 0)
  508. {
  509. //Both destination registers are RZ, do nothing.
  510. return;
  511. }
  512. bool Fp16 = !OpCode.Read(59);
  513. int DstIncrement = 0;
  514. ShaderIrOperGpr GetDst()
  515. {
  516. ShaderIrOperGpr Dst;
  517. if (Fp16)
  518. {
  519. //FP16 mode, two components are packed on the two
  520. //halfs of a 32-bits register, as two half-float values.
  521. int HalfPart = DstIncrement & 1;
  522. switch (LutIndex)
  523. {
  524. case 1: Dst = OpCode.GprHalf0(HalfPart); break;
  525. case 2: Dst = OpCode.GprHalf28(HalfPart); break;
  526. case 3: Dst = (DstIncrement >> 1) != 0
  527. ? OpCode.GprHalf28(HalfPart)
  528. : OpCode.GprHalf0(HalfPart); break;
  529. default: throw new InvalidOperationException();
  530. }
  531. }
  532. else
  533. {
  534. //32-bits mode, each component uses one register.
  535. //Two components uses two consecutive registers.
  536. switch (LutIndex)
  537. {
  538. case 1: Dst = OpCode.Gpr0(); break;
  539. case 2: Dst = OpCode.Gpr28(); break;
  540. case 3: Dst = (DstIncrement >> 1) != 0
  541. ? OpCode.Gpr28()
  542. : OpCode.Gpr0(); break;
  543. default: throw new InvalidOperationException();
  544. }
  545. Dst.Index += DstIncrement & 1;
  546. }
  547. DstIncrement++;
  548. return Dst;
  549. }
  550. int ChMask = MaskLut[LutIndex, OpCode.Read(50, 7)];
  551. if (ChMask == 0)
  552. {
  553. //All channels are disabled, do nothing.
  554. return;
  555. }
  556. ShaderIrNode OperC = OpCode.Imm13_36();
  557. Coords = CoordsRegistersToTempRegisters(Block, Coords);
  558. for (int Ch = 0; Ch < 4; Ch++)
  559. {
  560. if (!IsChannelUsed(ChMask, Ch))
  561. {
  562. continue;
  563. }
  564. ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords)
  565. {
  566. LevelOfDetail = LevelOfDetail,
  567. Offset = Offset,
  568. DepthCompare = DepthCompare
  569. };
  570. ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);
  571. ShaderIrOperGpr Dst = GetDst();
  572. if (Dst.IsValidRegister && !Dst.IsConst)
  573. {
  574. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
  575. }
  576. }
  577. }
  578. private static void EmitTld4(ShaderIrBlock Block, long OpCode, GalTextureTarget TextureType, TextureInstructionSuffix TextureInstructionSuffix, int ChMask, int Component, bool Scalar)
  579. {
  580. ShaderIrOperGpr OperA = OpCode.Gpr8();
  581. ShaderIrOperGpr OperB = OpCode.Gpr20();
  582. ShaderIrOperImm OperC = OpCode.Imm13_36();
  583. ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureType)];
  584. ShaderIrOperGpr Offset = null;
  585. ShaderIrOperGpr DepthCompare = null;
  586. bool IsArray = ImageUtils.IsArray(TextureType);
  587. int OperBIndex = 0;
  588. if (Scalar)
  589. {
  590. int CoordStartIndex = 0;
  591. if (IsArray)
  592. {
  593. CoordStartIndex++;
  594. Coords[Coords.Length - 1] = OperB;
  595. }
  596. switch (Coords.Length - CoordStartIndex)
  597. {
  598. case 1:
  599. Coords[0] = OpCode.Gpr8();
  600. break;
  601. case 2:
  602. Coords[0] = OpCode.Gpr8();
  603. Coords[0].Index += CoordStartIndex;
  604. break;
  605. case 3:
  606. Coords[0] = OpCode.Gpr8();
  607. Coords[0].Index += CoordStartIndex;
  608. Coords[1] = OpCode.Gpr8();
  609. Coords[1].Index += 1 + CoordStartIndex;
  610. break;
  611. default:
  612. throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TLD4S");
  613. }
  614. if (Coords.Length - CoordStartIndex != 1)
  615. {
  616. Coords[Coords.Length - CoordStartIndex - 1] = OperB;
  617. OperBIndex++;
  618. }
  619. if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureType == GalTextureTarget.TwoD)
  620. {
  621. Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8();
  622. Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1;
  623. OperBIndex--;
  624. }
  625. }
  626. else
  627. {
  628. int IndexExtraCoord = 0;
  629. if (IsArray)
  630. {
  631. IndexExtraCoord++;
  632. Coords[Coords.Length - 1] = OpCode.Gpr8();
  633. }
  634. for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++)
  635. {
  636. Coords[Index] = OpCode.Gpr8();
  637. Coords[Index].Index += Index;
  638. Coords[Index].Index += IndexExtraCoord;
  639. if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex)
  640. {
  641. Coords[Index].Index = ShaderIrOperGpr.ZRIndex;
  642. }
  643. }
  644. }
  645. if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
  646. {
  647. Offset = OpCode.Gpr20();
  648. Offset.Index += OperBIndex;
  649. OperBIndex++;
  650. }
  651. if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
  652. {
  653. DepthCompare = OpCode.Gpr20();
  654. DepthCompare.Index += OperBIndex;
  655. OperBIndex++;
  656. }
  657. Coords = CoordsRegistersToTempRegisters(Block, Coords);
  658. int RegInc = 0;
  659. for (int Ch = 0; Ch < 4; Ch++)
  660. {
  661. if (!IsChannelUsed(ChMask, Ch))
  662. {
  663. continue;
  664. }
  665. ShaderIrOperGpr Dst = OpCode.Gpr0();
  666. Dst.Index += RegInc++;
  667. if (!Dst.IsValidRegister || Dst.IsConst)
  668. {
  669. continue;
  670. }
  671. ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords)
  672. {
  673. Component = Component,
  674. Offset = Offset,
  675. DepthCompare = DepthCompare
  676. };
  677. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Tld4, OperA, OperB, OperC, Meta);
  678. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
  679. }
  680. }
  681. private static bool IsChannelUsed(int ChMask, int Ch)
  682. {
  683. return (ChMask & (1 << Ch)) != 0;
  684. }
  685. private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock Block, params ShaderIrOperGpr[] Registers)
  686. {
  687. ShaderIrOperGpr[] Res = new ShaderIrOperGpr[Registers.Length];
  688. for (int Index = 0; Index < Res.Length; Index++)
  689. {
  690. Res[Index] = ShaderIrOperGpr.MakeTemporary(Index);
  691. Block.AddNode(new ShaderIrAsg(Res[Index], Registers[Index]));
  692. }
  693. return Res;
  694. }
  695. }
  696. }