TextureView.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Common;
  3. using Ryujinx.Common.Memory;
  4. using Ryujinx.Graphics.GAL;
  5. using System;
  6. namespace Ryujinx.Graphics.OpenGL.Image
  7. {
  8. class TextureView : TextureBase, ITexture, ITextureInfo
  9. {
  10. private readonly OpenGLRenderer _renderer;
  11. private readonly TextureStorage _parent;
  12. public ITextureInfo Storage => _parent;
  13. public int FirstLayer { get; private set; }
  14. public int FirstLevel { get; private set; }
  15. public TextureView(
  16. OpenGLRenderer renderer,
  17. TextureStorage parent,
  18. TextureCreateInfo info,
  19. int firstLayer,
  20. int firstLevel) : base(info, parent.ScaleFactor)
  21. {
  22. _renderer = renderer;
  23. _parent = parent;
  24. FirstLayer = firstLayer;
  25. FirstLevel = firstLevel;
  26. CreateView();
  27. }
  28. private void CreateView()
  29. {
  30. TextureTarget target = Target.Convert();
  31. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  32. PixelInternalFormat pixelInternalFormat;
  33. if (format.IsCompressed)
  34. {
  35. pixelInternalFormat = (PixelInternalFormat)format.PixelFormat;
  36. }
  37. else
  38. {
  39. pixelInternalFormat = format.PixelInternalFormat;
  40. }
  41. int levels = Info.GetLevelsClamped();
  42. GL.TextureView(
  43. Handle,
  44. target,
  45. _parent.Handle,
  46. pixelInternalFormat,
  47. FirstLevel,
  48. levels,
  49. FirstLayer,
  50. Info.GetLayers());
  51. GL.ActiveTexture(TextureUnit.Texture0);
  52. GL.BindTexture(target, Handle);
  53. int[] swizzleRgba = new int[]
  54. {
  55. (int)Info.SwizzleR.Convert(),
  56. (int)Info.SwizzleG.Convert(),
  57. (int)Info.SwizzleB.Convert(),
  58. (int)Info.SwizzleA.Convert()
  59. };
  60. if (Info.Format == Format.A1B5G5R5Unorm)
  61. {
  62. int temp = swizzleRgba[0];
  63. int temp2 = swizzleRgba[1];
  64. swizzleRgba[0] = swizzleRgba[3];
  65. swizzleRgba[1] = swizzleRgba[2];
  66. swizzleRgba[2] = temp2;
  67. swizzleRgba[3] = temp;
  68. }
  69. else if (Info.Format.IsBgr())
  70. {
  71. // Swap B <-> R for BGRA formats, as OpenGL has no support for them
  72. // and we need to manually swap the components on read/write on the GPU.
  73. int temp = swizzleRgba[0];
  74. swizzleRgba[0] = swizzleRgba[2];
  75. swizzleRgba[2] = temp;
  76. }
  77. GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
  78. int maxLevel = levels - 1;
  79. if (maxLevel < 0)
  80. {
  81. maxLevel = 0;
  82. }
  83. GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel);
  84. GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)Info.DepthStencilMode.Convert());
  85. }
  86. public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
  87. {
  88. firstLayer += FirstLayer;
  89. firstLevel += FirstLevel;
  90. return _parent.CreateView(info, firstLayer, firstLevel);
  91. }
  92. public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
  93. {
  94. TextureView destinationView = (TextureView)destination;
  95. if (!destinationView.Target.IsMultisample() && Target.IsMultisample())
  96. {
  97. int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
  98. _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, 0, firstLayer, layers);
  99. }
  100. else if (destinationView.Target.IsMultisample() && !Target.IsMultisample())
  101. {
  102. int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
  103. _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, layers);
  104. }
  105. else
  106. {
  107. _renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
  108. }
  109. }
  110. public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
  111. {
  112. TextureView destinationView = (TextureView)destination;
  113. if (!destinationView.Target.IsMultisample() && Target.IsMultisample())
  114. {
  115. _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer,1);
  116. }
  117. else if (destinationView.Target.IsMultisample() && !Target.IsMultisample())
  118. {
  119. _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, srcLayer, dstLayer, 1);
  120. }
  121. else
  122. {
  123. _renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
  124. }
  125. }
  126. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  127. {
  128. _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter);
  129. }
  130. public unsafe ReadOnlySpan<byte> GetData()
  131. {
  132. int size = 0;
  133. int levels = Info.GetLevelsClamped();
  134. for (int level = 0; level < levels; level++)
  135. {
  136. size += Info.GetMipSize(level);
  137. }
  138. ReadOnlySpan<byte> data;
  139. if (HwCapabilities.UsePersistentBufferForFlush)
  140. {
  141. data = _renderer.PersistentBuffers.Default.GetTextureData(this, size);
  142. }
  143. else
  144. {
  145. IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size);
  146. WriteTo(target);
  147. data = new ReadOnlySpan<byte>(target.ToPointer(), size);
  148. }
  149. if (Format == Format.S8UintD24Unorm)
  150. {
  151. data = FormatConverter.ConvertD24S8ToS8D24(data);
  152. }
  153. return data;
  154. }
  155. public unsafe ReadOnlySpan<byte> GetData(int layer, int level)
  156. {
  157. int size = Info.GetMipSize(level);
  158. if (HwCapabilities.UsePersistentBufferForFlush)
  159. {
  160. return _renderer.PersistentBuffers.Default.GetTextureData(this, size, layer, level);
  161. }
  162. else
  163. {
  164. IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size);
  165. int offset = WriteTo2D(target, layer, level);
  166. return new ReadOnlySpan<byte>(target.ToPointer(), size).Slice(offset);
  167. }
  168. }
  169. public void WriteToPbo(int offset, bool forceBgra)
  170. {
  171. WriteTo(IntPtr.Zero + offset, forceBgra);
  172. }
  173. public int WriteToPbo2D(int offset, int layer, int level)
  174. {
  175. return WriteTo2D(IntPtr.Zero + offset, layer, level);
  176. }
  177. private int WriteTo2D(IntPtr data, int layer, int level)
  178. {
  179. TextureTarget target = Target.Convert();
  180. Bind(target, 0);
  181. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  182. PixelFormat pixelFormat = format.PixelFormat;
  183. PixelType pixelType = format.PixelType;
  184. if (target == TextureTarget.TextureCubeMap || target == TextureTarget.TextureCubeMapArray)
  185. {
  186. target = TextureTarget.TextureCubeMapPositiveX + (layer % 6);
  187. }
  188. int mipSize = Info.GetMipSize2D(level);
  189. if (format.IsCompressed)
  190. {
  191. GL.GetCompressedTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, mipSize, data);
  192. }
  193. else if (format.PixelFormat != PixelFormat.DepthStencil)
  194. {
  195. GL.GetTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, pixelFormat, pixelType, mipSize, data);
  196. }
  197. else
  198. {
  199. GL.GetTexImage(target, level, pixelFormat, pixelType, data);
  200. // The GL function returns all layers. Must return the offset of the layer we're interested in.
  201. return target switch
  202. {
  203. TextureTarget.TextureCubeMapArray => (layer / 6) * mipSize,
  204. TextureTarget.Texture1DArray => layer * mipSize,
  205. TextureTarget.Texture2DArray => layer * mipSize,
  206. _ => 0
  207. };
  208. }
  209. return 0;
  210. }
  211. private void WriteTo(IntPtr data, bool forceBgra = false)
  212. {
  213. TextureTarget target = Target.Convert();
  214. Bind(target, 0);
  215. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  216. PixelFormat pixelFormat = format.PixelFormat;
  217. PixelType pixelType = format.PixelType;
  218. if (forceBgra)
  219. {
  220. if (pixelType == PixelType.UnsignedShort565)
  221. {
  222. pixelType = PixelType.UnsignedShort565Reversed;
  223. }
  224. else if (pixelType == PixelType.UnsignedShort565Reversed)
  225. {
  226. pixelType = PixelType.UnsignedShort565;
  227. }
  228. else
  229. {
  230. pixelFormat = PixelFormat.Bgra;
  231. }
  232. }
  233. int faces = 1;
  234. if (target == TextureTarget.TextureCubeMap)
  235. {
  236. target = TextureTarget.TextureCubeMapPositiveX;
  237. faces = 6;
  238. }
  239. int levels = Info.GetLevelsClamped();
  240. for (int level = 0; level < levels; level++)
  241. {
  242. for (int face = 0; face < faces; face++)
  243. {
  244. int faceOffset = face * Info.GetMipSize2D(level);
  245. if (format.IsCompressed)
  246. {
  247. GL.GetCompressedTexImage(target + face, level, data + faceOffset);
  248. }
  249. else
  250. {
  251. GL.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset);
  252. }
  253. }
  254. data += Info.GetMipSize(level);
  255. }
  256. }
  257. public void SetData(SpanOrArray<byte> data)
  258. {
  259. var dataSpan = data.AsSpan();
  260. if (Format == Format.S8UintD24Unorm)
  261. {
  262. dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
  263. }
  264. unsafe
  265. {
  266. fixed (byte* ptr = dataSpan)
  267. {
  268. ReadFrom((IntPtr)ptr, dataSpan.Length);
  269. }
  270. }
  271. }
  272. public void SetData(SpanOrArray<byte> data, int layer, int level)
  273. {
  274. var dataSpan = data.AsSpan();
  275. if (Format == Format.S8UintD24Unorm)
  276. {
  277. dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
  278. }
  279. unsafe
  280. {
  281. fixed (byte* ptr = dataSpan)
  282. {
  283. int width = Math.Max(Info.Width >> level, 1);
  284. int height = Math.Max(Info.Height >> level, 1);
  285. ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
  286. }
  287. }
  288. }
  289. public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
  290. {
  291. var dataSpan = data.AsSpan();
  292. if (Format == Format.S8UintD24Unorm)
  293. {
  294. dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
  295. }
  296. int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
  297. int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
  298. unsafe
  299. {
  300. fixed (byte* ptr = dataSpan)
  301. {
  302. ReadFrom2D(
  303. (IntPtr)ptr,
  304. layer,
  305. level,
  306. region.X,
  307. region.Y,
  308. region.Width,
  309. region.Height,
  310. BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
  311. }
  312. }
  313. }
  314. public void ReadFromPbo(int offset, int size)
  315. {
  316. ReadFrom(IntPtr.Zero + offset, size);
  317. }
  318. public void ReadFromPbo2D(int offset, int layer, int level, int width, int height)
  319. {
  320. ReadFrom2D(IntPtr.Zero + offset, layer, level, 0, 0, width, height);
  321. }
  322. private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height)
  323. {
  324. int mipSize = Info.GetMipSize2D(level);
  325. ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
  326. }
  327. private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
  328. {
  329. TextureTarget target = Target.Convert();
  330. Bind(target, 0);
  331. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  332. switch (Target)
  333. {
  334. case Target.Texture1D:
  335. if (format.IsCompressed)
  336. {
  337. GL.CompressedTexSubImage1D(
  338. target,
  339. level,
  340. x,
  341. width,
  342. format.PixelFormat,
  343. mipSize,
  344. data);
  345. }
  346. else
  347. {
  348. GL.TexSubImage1D(
  349. target,
  350. level,
  351. x,
  352. width,
  353. format.PixelFormat,
  354. format.PixelType,
  355. data);
  356. }
  357. break;
  358. case Target.Texture1DArray:
  359. if (format.IsCompressed)
  360. {
  361. GL.CompressedTexSubImage2D(
  362. target,
  363. level,
  364. x,
  365. layer,
  366. width,
  367. 1,
  368. format.PixelFormat,
  369. mipSize,
  370. data);
  371. }
  372. else
  373. {
  374. GL.TexSubImage2D(
  375. target,
  376. level,
  377. x,
  378. layer,
  379. width,
  380. 1,
  381. format.PixelFormat,
  382. format.PixelType,
  383. data);
  384. }
  385. break;
  386. case Target.Texture2D:
  387. if (format.IsCompressed)
  388. {
  389. GL.CompressedTexSubImage2D(
  390. target,
  391. level,
  392. x,
  393. y,
  394. width,
  395. height,
  396. format.PixelFormat,
  397. mipSize,
  398. data);
  399. }
  400. else
  401. {
  402. GL.TexSubImage2D(
  403. target,
  404. level,
  405. x,
  406. y,
  407. width,
  408. height,
  409. format.PixelFormat,
  410. format.PixelType,
  411. data);
  412. }
  413. break;
  414. case Target.Texture2DArray:
  415. case Target.Texture3D:
  416. case Target.CubemapArray:
  417. if (format.IsCompressed)
  418. {
  419. GL.CompressedTexSubImage3D(
  420. target,
  421. level,
  422. x,
  423. y,
  424. layer,
  425. width,
  426. height,
  427. 1,
  428. format.PixelFormat,
  429. mipSize,
  430. data);
  431. }
  432. else
  433. {
  434. GL.TexSubImage3D(
  435. target,
  436. level,
  437. x,
  438. y,
  439. layer,
  440. width,
  441. height,
  442. 1,
  443. format.PixelFormat,
  444. format.PixelType,
  445. data);
  446. }
  447. break;
  448. case Target.Cubemap:
  449. if (format.IsCompressed)
  450. {
  451. GL.CompressedTexSubImage2D(
  452. TextureTarget.TextureCubeMapPositiveX + layer,
  453. level,
  454. x,
  455. y,
  456. width,
  457. height,
  458. format.PixelFormat,
  459. mipSize,
  460. data);
  461. }
  462. else
  463. {
  464. GL.TexSubImage2D(
  465. TextureTarget.TextureCubeMapPositiveX + layer,
  466. level,
  467. x,
  468. y,
  469. width,
  470. height,
  471. format.PixelFormat,
  472. format.PixelType,
  473. data);
  474. }
  475. break;
  476. }
  477. }
  478. private void ReadFrom(IntPtr data, int size)
  479. {
  480. TextureTarget target = Target.Convert();
  481. int baseLevel = 0;
  482. // glTexSubImage on cubemap views is broken on Intel, we have to use the storage instead.
  483. if (Target == Target.Cubemap && HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows)
  484. {
  485. GL.ActiveTexture(TextureUnit.Texture0);
  486. GL.BindTexture(target, Storage.Handle);
  487. baseLevel = FirstLevel;
  488. }
  489. else
  490. {
  491. Bind(target, 0);
  492. }
  493. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  494. int width = Info.Width;
  495. int height = Info.Height;
  496. int depth = Info.Depth;
  497. int levels = Info.GetLevelsClamped();
  498. int offset = 0;
  499. for (int level = 0; level < levels; level++)
  500. {
  501. int mipSize = Info.GetMipSize(level);
  502. int endOffset = offset + mipSize;
  503. if ((uint)endOffset > (uint)size)
  504. {
  505. return;
  506. }
  507. switch (Target)
  508. {
  509. case Target.Texture1D:
  510. if (format.IsCompressed)
  511. {
  512. GL.CompressedTexSubImage1D(
  513. target,
  514. level,
  515. 0,
  516. width,
  517. format.PixelFormat,
  518. mipSize,
  519. data);
  520. }
  521. else
  522. {
  523. GL.TexSubImage1D(
  524. target,
  525. level,
  526. 0,
  527. width,
  528. format.PixelFormat,
  529. format.PixelType,
  530. data);
  531. }
  532. break;
  533. case Target.Texture1DArray:
  534. case Target.Texture2D:
  535. if (format.IsCompressed)
  536. {
  537. GL.CompressedTexSubImage2D(
  538. target,
  539. level,
  540. 0,
  541. 0,
  542. width,
  543. height,
  544. format.PixelFormat,
  545. mipSize,
  546. data);
  547. }
  548. else
  549. {
  550. GL.TexSubImage2D(
  551. target,
  552. level,
  553. 0,
  554. 0,
  555. width,
  556. height,
  557. format.PixelFormat,
  558. format.PixelType,
  559. data);
  560. }
  561. break;
  562. case Target.Texture2DArray:
  563. case Target.Texture3D:
  564. case Target.CubemapArray:
  565. if (format.IsCompressed)
  566. {
  567. GL.CompressedTexSubImage3D(
  568. target,
  569. level,
  570. 0,
  571. 0,
  572. 0,
  573. width,
  574. height,
  575. depth,
  576. format.PixelFormat,
  577. mipSize,
  578. data);
  579. }
  580. else
  581. {
  582. GL.TexSubImage3D(
  583. target,
  584. level,
  585. 0,
  586. 0,
  587. 0,
  588. width,
  589. height,
  590. depth,
  591. format.PixelFormat,
  592. format.PixelType,
  593. data);
  594. }
  595. break;
  596. case Target.Cubemap:
  597. int faceOffset = 0;
  598. for (int face = 0; face < 6; face++, faceOffset += mipSize / 6)
  599. {
  600. if (format.IsCompressed)
  601. {
  602. GL.CompressedTexSubImage2D(
  603. TextureTarget.TextureCubeMapPositiveX + face,
  604. baseLevel + level,
  605. 0,
  606. 0,
  607. width,
  608. height,
  609. format.PixelFormat,
  610. mipSize / 6,
  611. data + faceOffset);
  612. }
  613. else
  614. {
  615. GL.TexSubImage2D(
  616. TextureTarget.TextureCubeMapPositiveX + face,
  617. baseLevel + level,
  618. 0,
  619. 0,
  620. width,
  621. height,
  622. format.PixelFormat,
  623. format.PixelType,
  624. data + faceOffset);
  625. }
  626. }
  627. break;
  628. }
  629. data += mipSize;
  630. offset += mipSize;
  631. width = Math.Max(1, width >> 1);
  632. height = Math.Max(1, height >> 1);
  633. if (Target == Target.Texture3D)
  634. {
  635. depth = Math.Max(1, depth >> 1);
  636. }
  637. }
  638. }
  639. public void SetStorage(BufferRange buffer)
  640. {
  641. throw new NotSupportedException();
  642. }
  643. private void DisposeHandles()
  644. {
  645. if (Handle != 0)
  646. {
  647. GL.DeleteTexture(Handle);
  648. Handle = 0;
  649. }
  650. }
  651. /// <summary>
  652. /// Release the view without necessarily disposing the parent if we are the default view.
  653. /// This allows it to be added to the resource pool and reused later.
  654. /// </summary>
  655. public void Release()
  656. {
  657. bool hadHandle = Handle != 0;
  658. if (_parent.DefaultView != this)
  659. {
  660. DisposeHandles();
  661. }
  662. if (hadHandle)
  663. {
  664. _parent.DecrementViewsCount();
  665. }
  666. }
  667. public void Dispose()
  668. {
  669. if (_parent.DefaultView == this)
  670. {
  671. // Remove the default view (us), so that the texture cannot be released to the cache.
  672. _parent.DeleteDefault();
  673. }
  674. Release();
  675. }
  676. }
  677. }