InstEmitTexture.cs 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using System;
  5. using System.Collections.Generic;
  6. using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  7. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  8. namespace Ryujinx.Graphics.Shader.Instructions
  9. {
  10. static partial class InstEmit
  11. {
  12. private const bool Sample1DAs2D = true;
  13. public static void Suld(EmitterContext context)
  14. {
  15. context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
  16. OpCodeImage op = (OpCodeImage)context.CurrOp;
  17. SamplerType type = ConvertSamplerType(op.Dimensions);
  18. if (type == SamplerType.None)
  19. {
  20. context.Config.GpuAccessor.Log("Invalid image store sampler type.");
  21. return;
  22. }
  23. // Rb is Rd on the SULD instruction.
  24. int rdIndex = op.Rb.Index;
  25. int raIndex = op.Ra.Index;
  26. Operand Ra()
  27. {
  28. if (raIndex > RegisterConsts.RegisterZeroIndex)
  29. {
  30. return Const(0);
  31. }
  32. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  33. }
  34. List<Operand> sourcesList = new List<Operand>();
  35. if (op.IsBindless)
  36. {
  37. sourcesList.Add(context.Copy(Register(op.Rc)));
  38. }
  39. int coordsCount = type.GetDimensions();
  40. for (int index = 0; index < coordsCount; index++)
  41. {
  42. sourcesList.Add(Ra());
  43. }
  44. if (Sample1DAs2D && (type & SamplerType.Mask) == SamplerType.Texture1D)
  45. {
  46. sourcesList.Add(Const(0));
  47. type &= ~SamplerType.Mask;
  48. type |= SamplerType.Texture2D;
  49. }
  50. if (type.HasFlag(SamplerType.Array))
  51. {
  52. sourcesList.Add(Ra());
  53. type |= SamplerType.Array;
  54. }
  55. Operand[] sources = sourcesList.ToArray();
  56. int handle = !op.IsBindless ? op.HandleOffset : 0;
  57. TextureFlags flags = op.IsBindless ? TextureFlags.Bindless : TextureFlags.None;
  58. if (op.UseComponents)
  59. {
  60. int componentMask = (int)op.Components;
  61. for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  62. {
  63. if ((compMask & 1) == 0)
  64. {
  65. continue;
  66. }
  67. if (rdIndex == RegisterConsts.RegisterZeroIndex)
  68. {
  69. break;
  70. }
  71. Operand rd = Register(rdIndex++, RegisterType.Gpr);
  72. TextureOperation operation = new TextureOperation(
  73. Instruction.ImageLoad,
  74. type,
  75. flags,
  76. handle,
  77. compIndex,
  78. rd,
  79. sources);
  80. if (!op.IsBindless)
  81. {
  82. operation.Format = context.Config.GetTextureFormat(handle);
  83. }
  84. context.Add(operation);
  85. }
  86. }
  87. else
  88. {
  89. if (op.ByteAddress)
  90. {
  91. int xIndex = op.IsBindless ? 1 : 0;
  92. sources[xIndex] = context.ShiftRightS32(sources[xIndex], Const(GetComponentSizeInBytesLog2(op.Size)));
  93. }
  94. int components = GetComponents(op.Size);
  95. for (int compIndex = 0; compIndex < components; compIndex++)
  96. {
  97. if (rdIndex == RegisterConsts.RegisterZeroIndex)
  98. {
  99. break;
  100. }
  101. Operand rd = Register(rdIndex++, RegisterType.Gpr);
  102. TextureOperation operation = new TextureOperation(
  103. Instruction.ImageLoad,
  104. type,
  105. flags,
  106. handle,
  107. compIndex,
  108. rd,
  109. sources)
  110. {
  111. Format = GetTextureFormat(op.Size)
  112. };
  113. context.Add(operation);
  114. switch (op.Size)
  115. {
  116. case IntegerSize.U8: context.Copy(rd, ZeroExtendTo32(context, rd, 8)); break;
  117. case IntegerSize.U16: context.Copy(rd, ZeroExtendTo32(context, rd, 16)); break;
  118. case IntegerSize.S8: context.Copy(rd, SignExtendTo32(context, rd, 8)); break;
  119. case IntegerSize.S16: context.Copy(rd, SignExtendTo32(context, rd, 16)); break;
  120. }
  121. }
  122. }
  123. }
  124. public static void Sust(EmitterContext context)
  125. {
  126. OpCodeImage op = (OpCodeImage)context.CurrOp;
  127. SamplerType type = ConvertSamplerType(op.Dimensions);
  128. if (type == SamplerType.None)
  129. {
  130. context.Config.GpuAccessor.Log("Invalid image store sampler type.");
  131. return;
  132. }
  133. int raIndex = op.Ra.Index;
  134. int rbIndex = op.Rb.Index;
  135. Operand Ra()
  136. {
  137. if (raIndex > RegisterConsts.RegisterZeroIndex)
  138. {
  139. return Const(0);
  140. }
  141. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  142. }
  143. Operand Rb()
  144. {
  145. if (rbIndex > RegisterConsts.RegisterZeroIndex)
  146. {
  147. return Const(0);
  148. }
  149. return context.Copy(Register(rbIndex++, RegisterType.Gpr));
  150. }
  151. List<Operand> sourcesList = new List<Operand>();
  152. if (op.IsBindless)
  153. {
  154. sourcesList.Add(context.Copy(Register(op.Rc)));
  155. }
  156. int coordsCount = type.GetDimensions();
  157. for (int index = 0; index < coordsCount; index++)
  158. {
  159. sourcesList.Add(Ra());
  160. }
  161. if (Sample1DAs2D && (type & SamplerType.Mask) == SamplerType.Texture1D)
  162. {
  163. sourcesList.Add(Const(0));
  164. type &= ~SamplerType.Mask;
  165. type |= SamplerType.Texture2D;
  166. }
  167. if (type.HasFlag(SamplerType.Array))
  168. {
  169. sourcesList.Add(Ra());
  170. type |= SamplerType.Array;
  171. }
  172. TextureFormat format = TextureFormat.Unknown;
  173. if (op.UseComponents)
  174. {
  175. int componentMask = (int)op.Components;
  176. for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  177. {
  178. if ((compMask & 1) != 0)
  179. {
  180. sourcesList.Add(Rb());
  181. }
  182. }
  183. if (!op.IsBindless)
  184. {
  185. format = context.Config.GetTextureFormat(op.HandleOffset);
  186. }
  187. }
  188. else
  189. {
  190. if (op.ByteAddress)
  191. {
  192. int xIndex = op.IsBindless ? 1 : 0;
  193. sourcesList[xIndex] = context.ShiftRightS32(sourcesList[xIndex], Const(GetComponentSizeInBytesLog2(op.Size)));
  194. }
  195. int components = GetComponents(op.Size);
  196. for (int compIndex = 0; compIndex < components; compIndex++)
  197. {
  198. sourcesList.Add(Rb());
  199. }
  200. format = GetTextureFormat(op.Size);
  201. }
  202. Operand[] sources = sourcesList.ToArray();
  203. int handle = !op.IsBindless ? op.HandleOffset : 0;
  204. TextureFlags flags = op.IsBindless ? TextureFlags.Bindless : TextureFlags.None;
  205. TextureOperation operation = new TextureOperation(
  206. Instruction.ImageStore,
  207. type,
  208. flags,
  209. handle,
  210. 0,
  211. null,
  212. sources)
  213. {
  214. Format = format
  215. };
  216. context.Add(operation);
  217. }
  218. public static void Tex(EmitterContext context)
  219. {
  220. EmitTextureSample(context, TextureFlags.None);
  221. }
  222. public static void TexB(EmitterContext context)
  223. {
  224. EmitTextureSample(context, TextureFlags.Bindless);
  225. }
  226. public static void Tld(EmitterContext context)
  227. {
  228. context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
  229. EmitTextureSample(context, TextureFlags.IntCoords);
  230. }
  231. public static void TldB(EmitterContext context)
  232. {
  233. context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
  234. EmitTextureSample(context, TextureFlags.IntCoords | TextureFlags.Bindless);
  235. }
  236. public static void Texs(EmitterContext context)
  237. {
  238. OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp;
  239. if (op.Rd0.IsRZ && op.Rd1.IsRZ)
  240. {
  241. return;
  242. }
  243. List<Operand> sourcesList = new List<Operand>();
  244. int raIndex = op.Ra.Index;
  245. int rbIndex = op.Rb.Index;
  246. Operand Ra()
  247. {
  248. if (raIndex > RegisterConsts.RegisterZeroIndex)
  249. {
  250. return Const(0);
  251. }
  252. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  253. }
  254. Operand Rb()
  255. {
  256. if (rbIndex > RegisterConsts.RegisterZeroIndex)
  257. {
  258. return Const(0);
  259. }
  260. return context.Copy(Register(rbIndex++, RegisterType.Gpr));
  261. }
  262. void AddTextureOffset(int coordsCount, int stride, int size)
  263. {
  264. Operand packedOffs = Rb();
  265. for (int index = 0; index < coordsCount; index++)
  266. {
  267. sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * stride), Const(size)));
  268. }
  269. }
  270. SamplerType type;
  271. TextureFlags flags;
  272. if (op is OpCodeTexs texsOp)
  273. {
  274. type = ConvertSamplerType(texsOp.Target);
  275. if (type == SamplerType.None)
  276. {
  277. context.Config.GpuAccessor.Log("Invalid texture sampler type.");
  278. return;
  279. }
  280. flags = ConvertTextureFlags(texsOp.Target);
  281. // We don't need to handle 1D -> Buffer conversions here as
  282. // only texture sample with integer coordinates can ever use buffer targets.
  283. if ((type & SamplerType.Array) != 0)
  284. {
  285. Operand arrayIndex = Ra();
  286. sourcesList.Add(Ra());
  287. sourcesList.Add(Rb());
  288. sourcesList.Add(arrayIndex);
  289. if ((type & SamplerType.Shadow) != 0)
  290. {
  291. sourcesList.Add(Rb());
  292. }
  293. if ((flags & TextureFlags.LodLevel) != 0)
  294. {
  295. sourcesList.Add(ConstF(0));
  296. }
  297. }
  298. else
  299. {
  300. switch (texsOp.Target)
  301. {
  302. case TextureTarget.Texture1DLodZero:
  303. sourcesList.Add(Ra());
  304. if (Sample1DAs2D)
  305. {
  306. sourcesList.Add(ConstF(0));
  307. type &= ~SamplerType.Mask;
  308. type |= SamplerType.Texture2D;
  309. }
  310. sourcesList.Add(ConstF(0));
  311. break;
  312. case TextureTarget.Texture2D:
  313. sourcesList.Add(Ra());
  314. sourcesList.Add(Rb());
  315. break;
  316. case TextureTarget.Texture2DLodZero:
  317. sourcesList.Add(Ra());
  318. sourcesList.Add(Rb());
  319. sourcesList.Add(ConstF(0));
  320. break;
  321. case TextureTarget.Texture2DLodLevel:
  322. case TextureTarget.Texture2DDepthCompare:
  323. case TextureTarget.Texture3D:
  324. case TextureTarget.TextureCube:
  325. sourcesList.Add(Ra());
  326. sourcesList.Add(Ra());
  327. sourcesList.Add(Rb());
  328. break;
  329. case TextureTarget.Texture2DLodZeroDepthCompare:
  330. case TextureTarget.Texture3DLodZero:
  331. sourcesList.Add(Ra());
  332. sourcesList.Add(Ra());
  333. sourcesList.Add(Rb());
  334. sourcesList.Add(ConstF(0));
  335. break;
  336. case TextureTarget.Texture2DLodLevelDepthCompare:
  337. case TextureTarget.TextureCubeLodLevel:
  338. sourcesList.Add(Ra());
  339. sourcesList.Add(Ra());
  340. sourcesList.Add(Rb());
  341. sourcesList.Add(Rb());
  342. break;
  343. }
  344. }
  345. }
  346. else if (op is OpCodeTlds tldsOp)
  347. {
  348. type = ConvertSamplerType(tldsOp.Target);
  349. if (type == SamplerType.None)
  350. {
  351. context.Config.GpuAccessor.Log("Invalid texel fetch sampler type.");
  352. return;
  353. }
  354. context.Config.SetUsedFeature(FeatureFlags.IntegerSampling);
  355. flags = ConvertTextureFlags(tldsOp.Target) | TextureFlags.IntCoords;
  356. if (tldsOp.Target == TexelLoadTarget.Texture1DLodZero && context.Config.GpuAccessor.QueryIsTextureBuffer(tldsOp.HandleOffset))
  357. {
  358. type = SamplerType.TextureBuffer;
  359. flags &= ~TextureFlags.LodLevel;
  360. }
  361. switch (tldsOp.Target)
  362. {
  363. case TexelLoadTarget.Texture1DLodZero:
  364. sourcesList.Add(Ra());
  365. if (type != SamplerType.TextureBuffer)
  366. {
  367. if (Sample1DAs2D)
  368. {
  369. sourcesList.Add(ConstF(0));
  370. type &= ~SamplerType.Mask;
  371. type |= SamplerType.Texture2D;
  372. }
  373. sourcesList.Add(ConstF(0));
  374. }
  375. break;
  376. case TexelLoadTarget.Texture1DLodLevel:
  377. sourcesList.Add(Ra());
  378. if (Sample1DAs2D)
  379. {
  380. sourcesList.Add(ConstF(0));
  381. type &= ~SamplerType.Mask;
  382. type |= SamplerType.Texture2D;
  383. }
  384. sourcesList.Add(Rb());
  385. break;
  386. case TexelLoadTarget.Texture2DLodZero:
  387. sourcesList.Add(Ra());
  388. sourcesList.Add(Rb());
  389. sourcesList.Add(Const(0));
  390. break;
  391. case TexelLoadTarget.Texture2DLodZeroOffset:
  392. sourcesList.Add(Ra());
  393. sourcesList.Add(Ra());
  394. sourcesList.Add(Const(0));
  395. break;
  396. case TexelLoadTarget.Texture2DLodZeroMultisample:
  397. case TexelLoadTarget.Texture2DLodLevel:
  398. case TexelLoadTarget.Texture2DLodLevelOffset:
  399. sourcesList.Add(Ra());
  400. sourcesList.Add(Ra());
  401. sourcesList.Add(Rb());
  402. break;
  403. case TexelLoadTarget.Texture3DLodZero:
  404. sourcesList.Add(Ra());
  405. sourcesList.Add(Ra());
  406. sourcesList.Add(Rb());
  407. sourcesList.Add(Const(0));
  408. break;
  409. case TexelLoadTarget.Texture2DArrayLodZero:
  410. sourcesList.Add(Rb());
  411. sourcesList.Add(Rb());
  412. sourcesList.Add(Ra());
  413. sourcesList.Add(Const(0));
  414. break;
  415. }
  416. if ((flags & TextureFlags.Offset) != 0)
  417. {
  418. AddTextureOffset(type.GetDimensions(), 4, 4);
  419. }
  420. }
  421. else if (op is OpCodeTld4s tld4sOp)
  422. {
  423. if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset))
  424. {
  425. sourcesList.Add(Ra());
  426. sourcesList.Add(Rb());
  427. }
  428. else
  429. {
  430. sourcesList.Add(Ra());
  431. sourcesList.Add(Ra());
  432. }
  433. type = SamplerType.Texture2D;
  434. flags = TextureFlags.Gather;
  435. if (tld4sOp.HasDepthCompare)
  436. {
  437. sourcesList.Add(Rb());
  438. type |= SamplerType.Shadow;
  439. }
  440. if (tld4sOp.HasOffset)
  441. {
  442. AddTextureOffset(type.GetDimensions(), 8, 6);
  443. flags |= TextureFlags.Offset;
  444. }
  445. sourcesList.Add(Const(tld4sOp.GatherCompIndex));
  446. }
  447. else
  448. {
  449. throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\".");
  450. }
  451. Operand[] sources = sourcesList.ToArray();
  452. Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) };
  453. Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) };
  454. int destIncrement = 0;
  455. Operand GetDest()
  456. {
  457. int high = destIncrement >> 1;
  458. int low = destIncrement & 1;
  459. destIncrement++;
  460. if (op.IsFp16)
  461. {
  462. return high != 0
  463. ? (rd1[low] = Local())
  464. : (rd0[low] = Local());
  465. }
  466. else
  467. {
  468. int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index;
  469. if (rdIndex < RegisterConsts.RegisterZeroIndex)
  470. {
  471. rdIndex += low;
  472. }
  473. return Register(rdIndex, RegisterType.Gpr);
  474. }
  475. }
  476. int handle = op.HandleOffset;
  477. for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  478. {
  479. if ((compMask & 1) != 0)
  480. {
  481. Operand dest = GetDest();
  482. TextureOperation operation = new TextureOperation(
  483. Instruction.TextureSample,
  484. type,
  485. flags,
  486. handle,
  487. compIndex,
  488. dest,
  489. sources);
  490. context.Add(operation);
  491. }
  492. }
  493. if (op.IsFp16)
  494. {
  495. context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1]));
  496. context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1]));
  497. }
  498. }
  499. public static void Tld4(EmitterContext context)
  500. {
  501. IOpCodeTld4 op = (IOpCodeTld4)context.CurrOp;
  502. if (op.Rd.IsRZ)
  503. {
  504. return;
  505. }
  506. int raIndex = op.Ra.Index;
  507. int rbIndex = op.Rb.Index;
  508. Operand Ra()
  509. {
  510. if (raIndex > RegisterConsts.RegisterZeroIndex)
  511. {
  512. return Const(0);
  513. }
  514. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  515. }
  516. Operand Rb()
  517. {
  518. if (rbIndex > RegisterConsts.RegisterZeroIndex)
  519. {
  520. return Const(0);
  521. }
  522. return context.Copy(Register(rbIndex++, RegisterType.Gpr));
  523. }
  524. Operand arrayIndex = op.IsArray ? Ra() : null;
  525. List<Operand> sourcesList = new List<Operand>();
  526. SamplerType type = ConvertSamplerType(op.Dimensions);
  527. TextureFlags flags = TextureFlags.Gather;
  528. if (op.Bindless)
  529. {
  530. sourcesList.Add(Rb());
  531. flags |= TextureFlags.Bindless;
  532. }
  533. int coordsCount = type.GetDimensions();
  534. for (int index = 0; index < coordsCount; index++)
  535. {
  536. sourcesList.Add(Ra());
  537. }
  538. bool is1DTo2D = Sample1DAs2D && type == SamplerType.Texture1D;
  539. if (is1DTo2D)
  540. {
  541. sourcesList.Add(ConstF(0));
  542. type = SamplerType.Texture2D;
  543. }
  544. if (op.IsArray)
  545. {
  546. sourcesList.Add(arrayIndex);
  547. type |= SamplerType.Array;
  548. }
  549. Operand[] packedOffs = new Operand[2];
  550. packedOffs[0] = op.Offset != TextureGatherOffset.None ? Rb() : null;
  551. packedOffs[1] = op.Offset == TextureGatherOffset.Offsets ? Rb() : null;
  552. if (op.HasDepthCompare)
  553. {
  554. sourcesList.Add(Rb());
  555. type |= SamplerType.Shadow;
  556. }
  557. if (op.Offset != TextureGatherOffset.None)
  558. {
  559. int offsetTexelsCount = op.Offset == TextureGatherOffset.Offsets ? 4 : 1;
  560. for (int index = 0; index < coordsCount * offsetTexelsCount; index++)
  561. {
  562. Operand packed = packedOffs[(index >> 2) & 1];
  563. sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6)));
  564. }
  565. if (is1DTo2D)
  566. {
  567. for (int index = 0; index < offsetTexelsCount; index++)
  568. {
  569. sourcesList.Add(Const(0));
  570. }
  571. }
  572. flags |= op.Offset == TextureGatherOffset.Offsets
  573. ? TextureFlags.Offsets
  574. : TextureFlags.Offset;
  575. }
  576. sourcesList.Add(Const(op.GatherCompIndex));
  577. Operand[] sources = sourcesList.ToArray();
  578. int rdIndex = op.Rd.Index;
  579. Operand GetDest()
  580. {
  581. if (rdIndex > RegisterConsts.RegisterZeroIndex)
  582. {
  583. return Const(0);
  584. }
  585. return Register(rdIndex++, RegisterType.Gpr);
  586. }
  587. int handle = op.HandleOffset;
  588. for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  589. {
  590. if ((compMask & 1) != 0)
  591. {
  592. Operand dest = GetDest();
  593. TextureOperation operation = new TextureOperation(
  594. Instruction.TextureSample,
  595. type,
  596. flags,
  597. handle,
  598. compIndex,
  599. dest,
  600. sources);
  601. context.Add(operation);
  602. }
  603. }
  604. }
  605. public static void TmmlB(EmitterContext context)
  606. {
  607. EmitTextureMipMapLevel(context, true);
  608. }
  609. public static void Tmml(EmitterContext context)
  610. {
  611. EmitTextureMipMapLevel(context, false);
  612. }
  613. private static void EmitTextureMipMapLevel(EmitterContext context, bool isBindless)
  614. {
  615. OpCodeTexture op = (OpCodeTexture)context.CurrOp;
  616. if (op.Rd.IsRZ)
  617. {
  618. return;
  619. }
  620. int raIndex = op.Ra.Index;
  621. int rbIndex = op.Rb.Index;
  622. Operand Ra()
  623. {
  624. if (raIndex > RegisterConsts.RegisterZeroIndex)
  625. {
  626. return Const(0);
  627. }
  628. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  629. }
  630. Operand Rb()
  631. {
  632. if (rbIndex > RegisterConsts.RegisterZeroIndex)
  633. {
  634. return Const(0);
  635. }
  636. return context.Copy(Register(rbIndex++, RegisterType.Gpr));
  637. }
  638. TextureFlags flags = TextureFlags.None;
  639. List<Operand> sourcesList = new List<Operand>();
  640. if (isBindless)
  641. {
  642. sourcesList.Add(Rb());
  643. flags |= TextureFlags.Bindless;
  644. }
  645. SamplerType type = ConvertSamplerType(op.Dimensions);
  646. int coordsCount = type.GetDimensions();
  647. Operand arrayIndex = op.IsArray ? Ra() : null;
  648. for (int index = 0; index < coordsCount; index++)
  649. {
  650. sourcesList.Add(Ra());
  651. }
  652. if (Sample1DAs2D && type == SamplerType.Texture1D)
  653. {
  654. sourcesList.Add(ConstF(0));
  655. type = SamplerType.Texture2D;
  656. }
  657. if (op.IsArray)
  658. {
  659. sourcesList.Add(arrayIndex);
  660. type |= SamplerType.Array;
  661. }
  662. Operand[] sources = sourcesList.ToArray();
  663. int rdIndex = op.Rd.Index;
  664. Operand GetDest()
  665. {
  666. if (rdIndex > RegisterConsts.RegisterZeroIndex)
  667. {
  668. return Const(0);
  669. }
  670. return Register(rdIndex++, RegisterType.Gpr);
  671. }
  672. int handle = !isBindless ? op.HandleOffset : 0;
  673. for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  674. {
  675. if ((compMask & 1) != 0)
  676. {
  677. Operand dest = GetDest();
  678. // Components z and w aren't standard, we return 0 in this case and add a comment.
  679. if (compIndex >= 2)
  680. {
  681. context.Add(new CommentNode("Unsupported component z or w found"));
  682. context.Copy(dest, Const(0));
  683. }
  684. else
  685. {
  686. Operand tempDest = Local();
  687. TextureOperation operation = new TextureOperation(
  688. Instruction.Lod,
  689. type,
  690. flags,
  691. handle,
  692. compIndex,
  693. tempDest,
  694. sources);
  695. context.Add(operation);
  696. tempDest = context.FPMultiply(tempDest, ConstF(256.0f));
  697. Operand finalValue = context.FPConvertToS32(tempDest);
  698. context.Copy(dest, finalValue);
  699. }
  700. }
  701. }
  702. }
  703. public static void Txd(EmitterContext context)
  704. {
  705. OpCodeTxd op = (OpCodeTxd)context.CurrOp;
  706. if (op.Rd.IsRZ)
  707. {
  708. return;
  709. }
  710. int raIndex = op.Ra.Index;
  711. int rbIndex = op.Rb.Index;
  712. Operand Ra()
  713. {
  714. if (raIndex > RegisterConsts.RegisterZeroIndex)
  715. {
  716. return Const(0);
  717. }
  718. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  719. }
  720. Operand Rb()
  721. {
  722. if (rbIndex > RegisterConsts.RegisterZeroIndex)
  723. {
  724. return Const(0);
  725. }
  726. return context.Copy(Register(rbIndex++, RegisterType.Gpr));
  727. }
  728. TextureFlags flags = TextureFlags.Derivatives;
  729. List<Operand> sourcesList = new List<Operand>();
  730. if (op.IsBindless)
  731. {
  732. sourcesList.Add(Ra());
  733. flags |= TextureFlags.Bindless;
  734. }
  735. SamplerType type = ConvertSamplerType(op.Dimensions);
  736. int coordsCount = type.GetDimensions();
  737. for (int index = 0; index < coordsCount; index++)
  738. {
  739. sourcesList.Add(Ra());
  740. }
  741. bool is1DTo2D = Sample1DAs2D && type == SamplerType.Texture1D;
  742. if (is1DTo2D)
  743. {
  744. sourcesList.Add(ConstF(0));
  745. type = SamplerType.Texture2D;
  746. }
  747. Operand packedParams = Ra();
  748. if (op.IsArray)
  749. {
  750. sourcesList.Add(context.BitwiseAnd(packedParams, Const(0xffff)));
  751. type |= SamplerType.Array;
  752. }
  753. // Derivatives (X and Y).
  754. for (int dIndex = 0; dIndex < 2 * coordsCount; dIndex++)
  755. {
  756. sourcesList.Add(Rb());
  757. if (is1DTo2D)
  758. {
  759. sourcesList.Add(ConstF(0));
  760. }
  761. }
  762. if (op.HasOffset)
  763. {
  764. for (int index = 0; index < coordsCount; index++)
  765. {
  766. sourcesList.Add(context.BitfieldExtractS32(packedParams, Const(16 + index * 4), Const(4)));
  767. }
  768. if (is1DTo2D)
  769. {
  770. sourcesList.Add(Const(0));
  771. }
  772. flags |= TextureFlags.Offset;
  773. }
  774. Operand[] sources = sourcesList.ToArray();
  775. int rdIndex = op.Rd.Index;
  776. Operand GetDest()
  777. {
  778. if (rdIndex > RegisterConsts.RegisterZeroIndex)
  779. {
  780. return Const(0);
  781. }
  782. return Register(rdIndex++, RegisterType.Gpr);
  783. }
  784. int handle = !op.IsBindless ? op.HandleOffset : 0;
  785. for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  786. {
  787. if ((compMask & 1) != 0)
  788. {
  789. Operand dest = GetDest();
  790. TextureOperation operation = new TextureOperation(
  791. Instruction.TextureSample,
  792. type,
  793. flags,
  794. handle,
  795. compIndex,
  796. dest,
  797. sources);
  798. context.Add(operation);
  799. }
  800. }
  801. }
  802. public static void Txq(EmitterContext context)
  803. {
  804. EmitTextureQuery(context, bindless: false);
  805. }
  806. public static void TxqB(EmitterContext context)
  807. {
  808. EmitTextureQuery(context, bindless: true);
  809. }
  810. private static void EmitTextureQuery(EmitterContext context, bool bindless)
  811. {
  812. OpCodeTex op = (OpCodeTex)context.CurrOp;
  813. if (op.Rd.IsRZ)
  814. {
  815. return;
  816. }
  817. TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6);
  818. // TODO: Validate and use property.
  819. Instruction inst = Instruction.TextureSize;
  820. SamplerType type = SamplerType.Texture2D;
  821. TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;
  822. int raIndex = op.Ra.Index;
  823. Operand Ra()
  824. {
  825. if (raIndex > RegisterConsts.RegisterZeroIndex)
  826. {
  827. return Const(0);
  828. }
  829. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  830. }
  831. List<Operand> sourcesList = new List<Operand>();
  832. if (bindless)
  833. {
  834. sourcesList.Add(Ra());
  835. }
  836. sourcesList.Add(Ra());
  837. Operand[] sources = sourcesList.ToArray();
  838. int rdIndex = op.Rd.Index;
  839. Operand GetDest()
  840. {
  841. if (rdIndex > RegisterConsts.RegisterZeroIndex)
  842. {
  843. return Const(0);
  844. }
  845. return Register(rdIndex++, RegisterType.Gpr);
  846. }
  847. int handle = !bindless ? op.HandleOffset : 0;
  848. for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  849. {
  850. if ((compMask & 1) != 0)
  851. {
  852. Operand dest = GetDest();
  853. TextureOperation operation = new TextureOperation(
  854. inst,
  855. type,
  856. flags,
  857. handle,
  858. compIndex,
  859. dest,
  860. sources);
  861. context.Add(operation);
  862. }
  863. }
  864. }
  865. private static void EmitTextureSample(EmitterContext context, TextureFlags flags)
  866. {
  867. OpCodeTexture op = (OpCodeTexture)context.CurrOp;
  868. bool isBindless = (flags & TextureFlags.Bindless) != 0;
  869. if (op.Rd.IsRZ)
  870. {
  871. return;
  872. }
  873. int raIndex = op.Ra.Index;
  874. int rbIndex = op.Rb.Index;
  875. Operand Ra()
  876. {
  877. if (raIndex > RegisterConsts.RegisterZeroIndex)
  878. {
  879. return Const(0);
  880. }
  881. return context.Copy(Register(raIndex++, RegisterType.Gpr));
  882. }
  883. Operand Rb()
  884. {
  885. if (rbIndex > RegisterConsts.RegisterZeroIndex)
  886. {
  887. return Const(0);
  888. }
  889. return context.Copy(Register(rbIndex++, RegisterType.Gpr));
  890. }
  891. Operand arrayIndex = op.IsArray ? Ra() : null;
  892. List<Operand> sourcesList = new List<Operand>();
  893. if (isBindless)
  894. {
  895. sourcesList.Add(Rb());
  896. }
  897. SamplerType type = ConvertSamplerType(op.Dimensions);
  898. bool hasLod = op.LodMode > TextureLodMode.LodZero;
  899. if (type == SamplerType.Texture1D && (flags & ~TextureFlags.Bindless) == TextureFlags.IntCoords && !(hasLod ||
  900. op.HasDepthCompare ||
  901. op.HasOffset ||
  902. op.IsArray ||
  903. op.IsMultisample))
  904. {
  905. // For bindless, we don't have any way to know the texture type,
  906. // so we assume it's texture buffer when the sampler type is 1D, since that's more common.
  907. bool isTypeBuffer = isBindless || context.Config.GpuAccessor.QueryIsTextureBuffer(op.HandleOffset);
  908. if (isTypeBuffer)
  909. {
  910. type = SamplerType.TextureBuffer;
  911. }
  912. }
  913. int coordsCount = type.GetDimensions();
  914. for (int index = 0; index < coordsCount; index++)
  915. {
  916. sourcesList.Add(Ra());
  917. }
  918. if (Sample1DAs2D && type == SamplerType.Texture1D)
  919. {
  920. sourcesList.Add(ConstF(0));
  921. type = SamplerType.Texture2D;
  922. }
  923. if (op.IsArray)
  924. {
  925. sourcesList.Add(arrayIndex);
  926. type |= SamplerType.Array;
  927. }
  928. Operand lodValue = hasLod ? Rb() : ConstF(0);
  929. Operand packedOffs = op.HasOffset ? Rb() : null;
  930. if (op.HasDepthCompare)
  931. {
  932. sourcesList.Add(Rb());
  933. type |= SamplerType.Shadow;
  934. }
  935. if ((op.LodMode == TextureLodMode.LodZero ||
  936. op.LodMode == TextureLodMode.LodLevel ||
  937. op.LodMode == TextureLodMode.LodLevelA) && !op.IsMultisample && type != SamplerType.TextureBuffer)
  938. {
  939. sourcesList.Add(lodValue);
  940. flags |= TextureFlags.LodLevel;
  941. }
  942. if (op.HasOffset)
  943. {
  944. for (int index = 0; index < coordsCount; index++)
  945. {
  946. sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4)));
  947. }
  948. flags |= TextureFlags.Offset;
  949. }
  950. if (op.LodMode == TextureLodMode.LodBias ||
  951. op.LodMode == TextureLodMode.LodBiasA)
  952. {
  953. sourcesList.Add(lodValue);
  954. flags |= TextureFlags.LodBias;
  955. }
  956. if (op.IsMultisample)
  957. {
  958. sourcesList.Add(Rb());
  959. type |= SamplerType.Multisample;
  960. }
  961. Operand[] sources = sourcesList.ToArray();
  962. int rdIndex = op.Rd.Index;
  963. Operand GetDest()
  964. {
  965. if (rdIndex > RegisterConsts.RegisterZeroIndex)
  966. {
  967. return Const(0);
  968. }
  969. return Register(rdIndex++, RegisterType.Gpr);
  970. }
  971. int handle = !isBindless ? op.HandleOffset : 0;
  972. for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
  973. {
  974. if ((compMask & 1) != 0)
  975. {
  976. Operand dest = GetDest();
  977. TextureOperation operation = new TextureOperation(
  978. Instruction.TextureSample,
  979. type,
  980. flags,
  981. handle,
  982. compIndex,
  983. dest,
  984. sources);
  985. context.Add(operation);
  986. }
  987. }
  988. }
  989. private static int GetComponents(IntegerSize size)
  990. {
  991. return size switch
  992. {
  993. IntegerSize.B64 => 2,
  994. IntegerSize.B128 => 4,
  995. IntegerSize.UB128 => 4,
  996. _ => 1
  997. };
  998. }
  999. private static int GetComponentSizeInBytesLog2(IntegerSize size)
  1000. {
  1001. return size switch
  1002. {
  1003. IntegerSize.U8 => 0,
  1004. IntegerSize.S8 => 0,
  1005. IntegerSize.U16 => 1,
  1006. IntegerSize.S16 => 1,
  1007. IntegerSize.B32 => 2,
  1008. IntegerSize.B64 => 3,
  1009. IntegerSize.B128 => 4,
  1010. IntegerSize.UB128 => 4,
  1011. _ => 2
  1012. };
  1013. }
  1014. private static TextureFormat GetTextureFormat(IntegerSize size)
  1015. {
  1016. return size switch
  1017. {
  1018. IntegerSize.U8 => TextureFormat.R8Uint,
  1019. IntegerSize.S8 => TextureFormat.R8Sint,
  1020. IntegerSize.U16 => TextureFormat.R16Uint,
  1021. IntegerSize.S16 => TextureFormat.R16Sint,
  1022. IntegerSize.B32 => TextureFormat.R32Uint,
  1023. IntegerSize.B64 => TextureFormat.R32G32Uint,
  1024. IntegerSize.B128 => TextureFormat.R32G32B32A32Uint,
  1025. IntegerSize.UB128 => TextureFormat.R32G32B32A32Uint,
  1026. _ => TextureFormat.R32Uint
  1027. };
  1028. }
  1029. private static SamplerType ConvertSamplerType(ImageDimensions target)
  1030. {
  1031. return target switch
  1032. {
  1033. ImageDimensions.Image1D => SamplerType.Texture1D,
  1034. ImageDimensions.ImageBuffer => SamplerType.TextureBuffer,
  1035. ImageDimensions.Image1DArray => SamplerType.Texture1D | SamplerType.Array,
  1036. ImageDimensions.Image2D => SamplerType.Texture2D,
  1037. ImageDimensions.Image2DArray => SamplerType.Texture2D | SamplerType.Array,
  1038. ImageDimensions.Image3D => SamplerType.Texture3D,
  1039. _ => SamplerType.None
  1040. };
  1041. }
  1042. private static SamplerType ConvertSamplerType(TextureDimensions dimensions)
  1043. {
  1044. return dimensions switch
  1045. {
  1046. TextureDimensions.Texture1D => SamplerType.Texture1D,
  1047. TextureDimensions.Texture2D => SamplerType.Texture2D,
  1048. TextureDimensions.Texture3D => SamplerType.Texture3D,
  1049. TextureDimensions.TextureCube => SamplerType.TextureCube,
  1050. _ => throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".")
  1051. };
  1052. }
  1053. private static SamplerType ConvertSamplerType(TextureTarget type)
  1054. {
  1055. switch (type)
  1056. {
  1057. case TextureTarget.Texture1DLodZero:
  1058. return SamplerType.Texture1D;
  1059. case TextureTarget.Texture2D:
  1060. case TextureTarget.Texture2DLodZero:
  1061. case TextureTarget.Texture2DLodLevel:
  1062. return SamplerType.Texture2D;
  1063. case TextureTarget.Texture2DDepthCompare:
  1064. case TextureTarget.Texture2DLodLevelDepthCompare:
  1065. case TextureTarget.Texture2DLodZeroDepthCompare:
  1066. return SamplerType.Texture2D | SamplerType.Shadow;
  1067. case TextureTarget.Texture2DArray:
  1068. case TextureTarget.Texture2DArrayLodZero:
  1069. return SamplerType.Texture2D | SamplerType.Array;
  1070. case TextureTarget.Texture2DArrayLodZeroDepthCompare:
  1071. return SamplerType.Texture2D | SamplerType.Array | SamplerType.Shadow;
  1072. case TextureTarget.Texture3D:
  1073. case TextureTarget.Texture3DLodZero:
  1074. return SamplerType.Texture3D;
  1075. case TextureTarget.TextureCube:
  1076. case TextureTarget.TextureCubeLodLevel:
  1077. return SamplerType.TextureCube;
  1078. }
  1079. return SamplerType.None;
  1080. }
  1081. private static SamplerType ConvertSamplerType(TexelLoadTarget type)
  1082. {
  1083. switch (type)
  1084. {
  1085. case TexelLoadTarget.Texture1DLodZero:
  1086. case TexelLoadTarget.Texture1DLodLevel:
  1087. return SamplerType.Texture1D;
  1088. case TexelLoadTarget.Texture2DLodZero:
  1089. case TexelLoadTarget.Texture2DLodZeroOffset:
  1090. case TexelLoadTarget.Texture2DLodLevel:
  1091. case TexelLoadTarget.Texture2DLodLevelOffset:
  1092. return SamplerType.Texture2D;
  1093. case TexelLoadTarget.Texture2DLodZeroMultisample:
  1094. return SamplerType.Texture2D | SamplerType.Multisample;
  1095. case TexelLoadTarget.Texture3DLodZero:
  1096. return SamplerType.Texture3D;
  1097. case TexelLoadTarget.Texture2DArrayLodZero:
  1098. return SamplerType.Texture2D | SamplerType.Array;
  1099. }
  1100. return SamplerType.None;
  1101. }
  1102. private static TextureFlags ConvertTextureFlags(TextureTarget type)
  1103. {
  1104. switch (type)
  1105. {
  1106. case TextureTarget.Texture1DLodZero:
  1107. case TextureTarget.Texture2DLodZero:
  1108. case TextureTarget.Texture2DLodLevel:
  1109. case TextureTarget.Texture2DLodLevelDepthCompare:
  1110. case TextureTarget.Texture2DLodZeroDepthCompare:
  1111. case TextureTarget.Texture2DArrayLodZero:
  1112. case TextureTarget.Texture2DArrayLodZeroDepthCompare:
  1113. case TextureTarget.Texture3DLodZero:
  1114. case TextureTarget.TextureCubeLodLevel:
  1115. return TextureFlags.LodLevel;
  1116. case TextureTarget.Texture2D:
  1117. case TextureTarget.Texture2DDepthCompare:
  1118. case TextureTarget.Texture2DArray:
  1119. case TextureTarget.Texture3D:
  1120. case TextureTarget.TextureCube:
  1121. return TextureFlags.None;
  1122. }
  1123. return TextureFlags.None;
  1124. }
  1125. private static TextureFlags ConvertTextureFlags(TexelLoadTarget type)
  1126. {
  1127. switch (type)
  1128. {
  1129. case TexelLoadTarget.Texture1DLodZero:
  1130. case TexelLoadTarget.Texture1DLodLevel:
  1131. case TexelLoadTarget.Texture2DLodZero:
  1132. case TexelLoadTarget.Texture2DLodLevel:
  1133. case TexelLoadTarget.Texture2DLodZeroMultisample:
  1134. case TexelLoadTarget.Texture3DLodZero:
  1135. case TexelLoadTarget.Texture2DArrayLodZero:
  1136. return TextureFlags.LodLevel;
  1137. case TexelLoadTarget.Texture2DLodZeroOffset:
  1138. case TexelLoadTarget.Texture2DLodLevelOffset:
  1139. return TextureFlags.LodLevel | TextureFlags.Offset;
  1140. }
  1141. return TextureFlags.None;
  1142. }
  1143. }
  1144. }