ShaderDecodeMem.cs 29 KB

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