InstEmitTexture.cs 41 KB

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