TextureView.cs 26 KB

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