Texture.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.GAL;
  4. using Ryujinx.Graphics.Gpu.Memory;
  5. using Ryujinx.Graphics.Texture;
  6. using Ryujinx.Graphics.Texture.Astc;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Diagnostics;
  10. namespace Ryujinx.Graphics.Gpu.Image
  11. {
  12. class Texture : IRange<Texture>
  13. {
  14. private GpuContext _context;
  15. private SizeInfo _sizeInfo;
  16. public Format Format => Info.FormatInfo.Format;
  17. public TextureInfo Info { get; private set; }
  18. private int _depth;
  19. private int _layers;
  20. private readonly int _firstLayer;
  21. private readonly int _firstLevel;
  22. private bool _hasData;
  23. private ITexture _arrayViewTexture;
  24. private Target _arrayViewTarget;
  25. private Texture _viewStorage;
  26. private List<Texture> _views;
  27. public ITexture HostTexture { get; private set; }
  28. public LinkedListNode<Texture> CacheNode { get; set; }
  29. public bool Modified { get; set; }
  30. public ulong Address => Info.Address;
  31. public ulong EndAddress => Info.Address + Size;
  32. public ulong Size => (ulong)_sizeInfo.TotalSize;
  33. private int _referenceCount;
  34. private int _sequenceNumber;
  35. private Texture(
  36. GpuContext context,
  37. TextureInfo info,
  38. SizeInfo sizeInfo,
  39. int firstLayer,
  40. int firstLevel)
  41. {
  42. InitializeTexture(context, info, sizeInfo);
  43. _firstLayer = firstLayer;
  44. _firstLevel = firstLevel;
  45. _hasData = true;
  46. }
  47. public Texture(GpuContext context, TextureInfo info, SizeInfo sizeInfo)
  48. {
  49. InitializeTexture(context, info, sizeInfo);
  50. TextureCreateInfo createInfo = TextureManager.GetCreateInfo(info, context.Capabilities);
  51. HostTexture = _context.Renderer.CreateTexture(createInfo);
  52. }
  53. private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo)
  54. {
  55. _context = context;
  56. _sizeInfo = sizeInfo;
  57. SetInfo(info);
  58. _viewStorage = this;
  59. _views = new List<Texture>();
  60. }
  61. public Texture CreateView(TextureInfo info, SizeInfo sizeInfo, int firstLayer, int firstLevel)
  62. {
  63. Texture texture = new Texture(
  64. _context,
  65. info,
  66. sizeInfo,
  67. _firstLayer + firstLayer,
  68. _firstLevel + firstLevel);
  69. TextureCreateInfo createInfo = TextureManager.GetCreateInfo(info, _context.Capabilities);
  70. texture.HostTexture = HostTexture.CreateView(createInfo, firstLayer, firstLevel);
  71. _viewStorage.AddView(texture);
  72. return texture;
  73. }
  74. private void AddView(Texture texture)
  75. {
  76. _views.Add(texture);
  77. texture._viewStorage = this;
  78. }
  79. private void RemoveView(Texture texture)
  80. {
  81. _views.Remove(texture);
  82. texture._viewStorage = null;
  83. DeleteIfNotUsed();
  84. }
  85. public void ChangeSize(int width, int height, int depthOrLayers)
  86. {
  87. width <<= _firstLevel;
  88. height <<= _firstLevel;
  89. if (Info.Target == Target.Texture3D)
  90. {
  91. depthOrLayers <<= _firstLevel;
  92. }
  93. else
  94. {
  95. depthOrLayers = _viewStorage.Info.DepthOrLayers;
  96. }
  97. _viewStorage.RecreateStorageOrView(width, height, depthOrLayers);
  98. foreach (Texture view in _viewStorage._views)
  99. {
  100. int viewWidth = Math.Max(1, width >> view._firstLevel);
  101. int viewHeight = Math.Max(1, height >> view._firstLevel);
  102. int viewDepthOrLayers;
  103. if (view.Info.Target == Target.Texture3D)
  104. {
  105. viewDepthOrLayers = Math.Max(1, depthOrLayers >> view._firstLevel);
  106. }
  107. else
  108. {
  109. viewDepthOrLayers = view.Info.DepthOrLayers;
  110. }
  111. view.RecreateStorageOrView(viewWidth, viewHeight, viewDepthOrLayers);
  112. }
  113. }
  114. private void RecreateStorageOrView(int width, int height, int depthOrLayers)
  115. {
  116. SetInfo(new TextureInfo(
  117. Info.Address,
  118. width,
  119. height,
  120. depthOrLayers,
  121. Info.Levels,
  122. Info.SamplesInX,
  123. Info.SamplesInY,
  124. Info.Stride,
  125. Info.IsLinear,
  126. Info.GobBlocksInY,
  127. Info.GobBlocksInZ,
  128. Info.GobBlocksInTileX,
  129. Info.Target,
  130. Info.FormatInfo,
  131. Info.DepthStencilMode,
  132. Info.SwizzleR,
  133. Info.SwizzleG,
  134. Info.SwizzleB,
  135. Info.SwizzleA));
  136. TextureCreateInfo createInfo = TextureManager.GetCreateInfo(Info, _context.Capabilities);
  137. if (_viewStorage != this)
  138. {
  139. ReplaceStorage(_viewStorage.HostTexture.CreateView(createInfo, _firstLayer, _firstLevel));
  140. }
  141. else
  142. {
  143. ITexture newStorage = _context.Renderer.CreateTexture(createInfo);
  144. HostTexture.CopyTo(newStorage, 0, 0);
  145. ReplaceStorage(newStorage);
  146. }
  147. }
  148. public void SynchronizeMemory()
  149. {
  150. if (_sequenceNumber == _context.SequenceNumber && _hasData)
  151. {
  152. return;
  153. }
  154. _sequenceNumber = _context.SequenceNumber;
  155. bool modified = _context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.Texture).Length != 0;
  156. if (!modified && _hasData)
  157. {
  158. return;
  159. }
  160. Span<byte> data = _context.PhysicalMemory.Read(Address, Size);
  161. if (Info.IsLinear)
  162. {
  163. data = LayoutConverter.ConvertLinearStridedToLinear(
  164. Info.Width,
  165. Info.Height,
  166. Info.FormatInfo.BlockWidth,
  167. Info.FormatInfo.BlockHeight,
  168. Info.Stride,
  169. Info.FormatInfo.BytesPerPixel,
  170. data);
  171. }
  172. else
  173. {
  174. data = LayoutConverter.ConvertBlockLinearToLinear(
  175. Info.Width,
  176. Info.Height,
  177. _depth,
  178. Info.Levels,
  179. _layers,
  180. Info.FormatInfo.BlockWidth,
  181. Info.FormatInfo.BlockHeight,
  182. Info.FormatInfo.BytesPerPixel,
  183. Info.GobBlocksInY,
  184. Info.GobBlocksInZ,
  185. Info.GobBlocksInTileX,
  186. _sizeInfo,
  187. data);
  188. }
  189. if (!_context.Capabilities.SupportsAstcCompression && Info.FormatInfo.Format.IsAstc())
  190. {
  191. if (!AstcDecoder.TryDecodeToRgba8(
  192. data.ToArray(),
  193. Info.FormatInfo.BlockWidth,
  194. Info.FormatInfo.BlockHeight,
  195. Info.Width,
  196. Info.Height,
  197. _depth,
  198. Info.Levels,
  199. out Span<byte> decoded))
  200. {
  201. string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";
  202. Logger.PrintError(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.Address:X} ({texInfo}).");
  203. }
  204. data = decoded;
  205. }
  206. HostTexture.SetData(data);
  207. _hasData = true;
  208. }
  209. public void Flush()
  210. {
  211. Span<byte> data = HostTexture.GetData();
  212. if (Info.IsLinear)
  213. {
  214. data = LayoutConverter.ConvertLinearToLinearStrided(
  215. Info.Width,
  216. Info.Height,
  217. Info.FormatInfo.BlockWidth,
  218. Info.FormatInfo.BlockHeight,
  219. Info.Stride,
  220. Info.FormatInfo.BytesPerPixel,
  221. data);
  222. }
  223. else
  224. {
  225. data = LayoutConverter.ConvertLinearToBlockLinear(
  226. Info.Width,
  227. Info.Height,
  228. _depth,
  229. Info.Levels,
  230. _layers,
  231. Info.FormatInfo.BlockWidth,
  232. Info.FormatInfo.BlockHeight,
  233. Info.FormatInfo.BytesPerPixel,
  234. Info.GobBlocksInY,
  235. Info.GobBlocksInZ,
  236. Info.GobBlocksInTileX,
  237. _sizeInfo,
  238. data);
  239. }
  240. _context.PhysicalMemory.Write(Address, data);
  241. }
  242. public bool IsPerfectMatch(TextureInfo info, TextureSearchFlags flags)
  243. {
  244. if (!FormatMatches(info, (flags & TextureSearchFlags.Strict) != 0))
  245. {
  246. return false;
  247. }
  248. if (!LayoutMatches(info))
  249. {
  250. return false;
  251. }
  252. if (!SizeMatches(info, (flags & TextureSearchFlags.Strict) == 0))
  253. {
  254. return false;
  255. }
  256. if ((flags & TextureSearchFlags.Sampler) != 0)
  257. {
  258. if (!SamplerParamsMatches(info))
  259. {
  260. return false;
  261. }
  262. }
  263. if ((flags & TextureSearchFlags.IgnoreMs) != 0)
  264. {
  265. bool msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D;
  266. if (!msTargetCompatible && !TargetAndSamplesCompatible(info))
  267. {
  268. return false;
  269. }
  270. }
  271. else if (!TargetAndSamplesCompatible(info))
  272. {
  273. return false;
  274. }
  275. return Info.Address == info.Address && Info.Levels == info.Levels;
  276. }
  277. private bool FormatMatches(TextureInfo info, bool strict)
  278. {
  279. // D32F and R32F texture have the same representation internally,
  280. // however the R32F format is used to sample from depth textures.
  281. if (Info.FormatInfo.Format == Format.D32Float && info.FormatInfo.Format == Format.R32Float && !strict)
  282. {
  283. return true;
  284. }
  285. return Info.FormatInfo.Format == info.FormatInfo.Format;
  286. }
  287. private bool LayoutMatches(TextureInfo info)
  288. {
  289. if (Info.IsLinear != info.IsLinear)
  290. {
  291. return false;
  292. }
  293. // For linear textures, gob block sizes are ignored.
  294. // For block linear textures, the stride is ignored.
  295. if (info.IsLinear)
  296. {
  297. return Info.Stride == info.Stride;
  298. }
  299. else
  300. {
  301. return Info.GobBlocksInY == info.GobBlocksInY &&
  302. Info.GobBlocksInZ == info.GobBlocksInZ;
  303. }
  304. }
  305. public bool SizeMatches(TextureInfo info)
  306. {
  307. return SizeMatches(info, alignSizes: false);
  308. }
  309. public bool SizeMatches(TextureInfo info, int level)
  310. {
  311. return Math.Max(1, Info.Width >> level) == info.Width &&
  312. Math.Max(1, Info.Height >> level) == info.Height &&
  313. Math.Max(1, Info.GetDepth() >> level) == info.GetDepth();
  314. }
  315. private bool SizeMatches(TextureInfo info, bool alignSizes)
  316. {
  317. if (Info.GetLayers() != info.GetLayers())
  318. {
  319. return false;
  320. }
  321. if (alignSizes)
  322. {
  323. Size size0 = GetAlignedSize(Info);
  324. Size size1 = GetAlignedSize(info);
  325. return size0.Width == size1.Width &&
  326. size0.Height == size1.Height &&
  327. size0.Depth == size1.Depth;
  328. }
  329. else
  330. {
  331. return Info.Width == info.Width &&
  332. Info.Height == info.Height &&
  333. Info.GetDepth() == info.GetDepth();
  334. }
  335. }
  336. private bool SamplerParamsMatches(TextureInfo info)
  337. {
  338. return Info.DepthStencilMode == info.DepthStencilMode &&
  339. Info.SwizzleR == info.SwizzleR &&
  340. Info.SwizzleG == info.SwizzleG &&
  341. Info.SwizzleB == info.SwizzleB &&
  342. Info.SwizzleA == info.SwizzleA;
  343. }
  344. private bool TargetAndSamplesCompatible(TextureInfo info)
  345. {
  346. return Info.Target == info.Target &&
  347. Info.SamplesInX == info.SamplesInX &&
  348. Info.SamplesInY == info.SamplesInY;
  349. }
  350. public bool IsViewCompatible(
  351. TextureInfo info,
  352. ulong size,
  353. out int firstLayer,
  354. out int firstLevel)
  355. {
  356. return IsViewCompatible(info, size, isCopy: false, out firstLayer, out firstLevel);
  357. }
  358. public bool IsViewCompatible(
  359. TextureInfo info,
  360. ulong size,
  361. bool isCopy,
  362. out int firstLayer,
  363. out int firstLevel)
  364. {
  365. // Out of range.
  366. if (info.Address < Address || info.Address + size > EndAddress)
  367. {
  368. firstLayer = 0;
  369. firstLevel = 0;
  370. return false;
  371. }
  372. int offset = (int)(info.Address - Address);
  373. if (!_sizeInfo.FindView(offset, (int)size, out firstLayer, out firstLevel))
  374. {
  375. return false;
  376. }
  377. if (!ViewLayoutCompatible(info, firstLevel))
  378. {
  379. return false;
  380. }
  381. if (!ViewFormatCompatible(info))
  382. {
  383. return false;
  384. }
  385. if (!ViewSizeMatches(info, firstLevel, isCopy))
  386. {
  387. return false;
  388. }
  389. if (!ViewTargetCompatible(info, isCopy))
  390. {
  391. return false;
  392. }
  393. return Info.SamplesInX == info.SamplesInX &&
  394. Info.SamplesInY == info.SamplesInY;
  395. }
  396. private bool ViewLayoutCompatible(TextureInfo info, int level)
  397. {
  398. if (Info.IsLinear != info.IsLinear)
  399. {
  400. return false;
  401. }
  402. // For linear textures, gob block sizes are ignored.
  403. // For block linear textures, the stride is ignored.
  404. if (info.IsLinear)
  405. {
  406. int width = Math.Max(1, Info.Width >> level);
  407. int stride = width * Info.FormatInfo.BytesPerPixel;
  408. stride = BitUtils.AlignUp(stride, 32);
  409. return stride == info.Stride;
  410. }
  411. else
  412. {
  413. int height = Math.Max(1, Info.Height >> level);
  414. int depth = Math.Max(1, Info.GetDepth() >> level);
  415. (int gobBlocksInY, int gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(
  416. height,
  417. depth,
  418. Info.FormatInfo.BlockHeight,
  419. Info.GobBlocksInY,
  420. Info.GobBlocksInZ);
  421. return gobBlocksInY == info.GobBlocksInY &&
  422. gobBlocksInZ == info.GobBlocksInZ;
  423. }
  424. }
  425. private bool ViewFormatCompatible(TextureInfo info)
  426. {
  427. return TextureCompatibility.FormatCompatible(Info.FormatInfo, info.FormatInfo);
  428. }
  429. private bool ViewSizeMatches(TextureInfo info, int level, bool isCopy)
  430. {
  431. Size size = GetAlignedSize(Info, level);
  432. Size otherSize = GetAlignedSize(info);
  433. // For copies, we can copy a subset of the 3D texture slices,
  434. // so the depth may be different in this case.
  435. if (!isCopy && info.Target == Target.Texture3D && size.Depth != otherSize.Depth)
  436. {
  437. return false;
  438. }
  439. return size.Width == otherSize.Width &&
  440. size.Height == otherSize.Height;
  441. }
  442. private bool ViewTargetCompatible(TextureInfo info, bool isCopy)
  443. {
  444. switch (Info.Target)
  445. {
  446. case Target.Texture1D:
  447. case Target.Texture1DArray:
  448. return info.Target == Target.Texture1D ||
  449. info.Target == Target.Texture1DArray;
  450. case Target.Texture2D:
  451. return info.Target == Target.Texture2D ||
  452. info.Target == Target.Texture2DArray;
  453. case Target.Texture2DArray:
  454. case Target.Cubemap:
  455. case Target.CubemapArray:
  456. return info.Target == Target.Texture2D ||
  457. info.Target == Target.Texture2DArray ||
  458. info.Target == Target.Cubemap ||
  459. info.Target == Target.CubemapArray;
  460. case Target.Texture2DMultisample:
  461. case Target.Texture2DMultisampleArray:
  462. return info.Target == Target.Texture2DMultisample ||
  463. info.Target == Target.Texture2DMultisampleArray;
  464. case Target.Texture3D:
  465. return info.Target == Target.Texture3D ||
  466. (info.Target == Target.Texture2D && isCopy);
  467. }
  468. return false;
  469. }
  470. private static Size GetAlignedSize(TextureInfo info, int level = 0)
  471. {
  472. int width = Math.Max(1, info.Width >> level);
  473. int height = Math.Max(1, info.Height >> level);
  474. if (info.IsLinear)
  475. {
  476. return SizeCalculator.GetLinearAlignedSize(
  477. width,
  478. height,
  479. info.FormatInfo.BlockWidth,
  480. info.FormatInfo.BlockHeight,
  481. info.FormatInfo.BytesPerPixel);
  482. }
  483. else
  484. {
  485. int depth = Math.Max(1, info.GetDepth() >> level);
  486. (int gobBlocksInY, int gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(
  487. height,
  488. depth,
  489. info.FormatInfo.BlockHeight,
  490. info.GobBlocksInY,
  491. info.GobBlocksInZ);
  492. return SizeCalculator.GetBlockLinearAlignedSize(
  493. width,
  494. height,
  495. depth,
  496. info.FormatInfo.BlockWidth,
  497. info.FormatInfo.BlockHeight,
  498. info.FormatInfo.BytesPerPixel,
  499. gobBlocksInY,
  500. gobBlocksInZ,
  501. info.GobBlocksInTileX);
  502. }
  503. }
  504. public ITexture GetTargetTexture(Target target)
  505. {
  506. if (target == Info.Target)
  507. {
  508. return HostTexture;
  509. }
  510. if (_arrayViewTexture == null && IsSameDimensionsTarget(target))
  511. {
  512. TextureCreateInfo createInfo = new TextureCreateInfo(
  513. Info.Width,
  514. Info.Height,
  515. target == Target.CubemapArray ? 6 : 1,
  516. Info.Levels,
  517. Info.Samples,
  518. Info.FormatInfo.BlockWidth,
  519. Info.FormatInfo.BlockHeight,
  520. Info.FormatInfo.BytesPerPixel,
  521. Info.FormatInfo.Format,
  522. Info.DepthStencilMode,
  523. target,
  524. Info.SwizzleR,
  525. Info.SwizzleG,
  526. Info.SwizzleB,
  527. Info.SwizzleA);
  528. ITexture viewTexture = HostTexture.CreateView(createInfo, 0, 0);
  529. _arrayViewTexture = viewTexture;
  530. _arrayViewTarget = target;
  531. return viewTexture;
  532. }
  533. else if (_arrayViewTarget == target)
  534. {
  535. return _arrayViewTexture;
  536. }
  537. return null;
  538. }
  539. private bool IsSameDimensionsTarget(Target target)
  540. {
  541. switch (Info.Target)
  542. {
  543. case Target.Texture1D:
  544. case Target.Texture1DArray:
  545. return target == Target.Texture1D ||
  546. target == Target.Texture1DArray;
  547. case Target.Texture2D:
  548. case Target.Texture2DArray:
  549. return target == Target.Texture2D ||
  550. target == Target.Texture2DArray;
  551. case Target.Cubemap:
  552. case Target.CubemapArray:
  553. return target == Target.Cubemap ||
  554. target == Target.CubemapArray;
  555. case Target.Texture2DMultisample:
  556. case Target.Texture2DMultisampleArray:
  557. return target == Target.Texture2DMultisample ||
  558. target == Target.Texture2DMultisampleArray;
  559. case Target.Texture3D:
  560. return target == Target.Texture3D;
  561. }
  562. return false;
  563. }
  564. public void ReplaceView(Texture parent, TextureInfo info, ITexture hostTexture)
  565. {
  566. ReplaceStorage(hostTexture);
  567. parent._viewStorage.AddView(this);
  568. SetInfo(info);
  569. }
  570. private void SetInfo(TextureInfo info)
  571. {
  572. Info = info;
  573. _depth = info.GetDepth();
  574. _layers = info.GetLayers();
  575. }
  576. private void ReplaceStorage(ITexture hostTexture)
  577. {
  578. DisposeTextures();
  579. HostTexture = hostTexture;
  580. }
  581. public bool OverlapsWith(ulong address, ulong size)
  582. {
  583. return Address < address + size && address < EndAddress;
  584. }
  585. public void IncrementReferenceCount()
  586. {
  587. _referenceCount++;
  588. }
  589. public void DecrementReferenceCount()
  590. {
  591. int newRefCount = --_referenceCount;
  592. if (newRefCount == 0)
  593. {
  594. if (_viewStorage != this)
  595. {
  596. _viewStorage.RemoveView(this);
  597. }
  598. _context.Methods.TextureManager.RemoveTextureFromCache(this);
  599. }
  600. Debug.Assert(newRefCount >= 0);
  601. DeleteIfNotUsed();
  602. }
  603. private void DeleteIfNotUsed()
  604. {
  605. // We can delete the texture as long it is not being used
  606. // in any cache (the reference count is 0 in this case), and
  607. // also all views that may be created from this texture were
  608. // already deleted (views count is 0).
  609. if (_referenceCount == 0 && _views.Count == 0)
  610. {
  611. DisposeTextures();
  612. }
  613. }
  614. private void DisposeTextures()
  615. {
  616. HostTexture.Dispose();
  617. _arrayViewTexture?.Dispose();
  618. _arrayViewTexture = null;
  619. }
  620. }
  621. }