TextureView.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Graphics.GAL;
  3. using System;
  4. namespace Ryujinx.Graphics.OpenGL
  5. {
  6. class TextureView : ITexture
  7. {
  8. public int Handle { get; private set; }
  9. private readonly Renderer _renderer;
  10. private readonly TextureStorage _parent;
  11. private TextureView _emulatedViewParent;
  12. private TextureView _incompatibleFormatView;
  13. private readonly TextureCreateInfo _info;
  14. public int FirstLayer { get; private set; }
  15. public int FirstLevel { get; private set; }
  16. public int Width => _info.Width;
  17. public int Height => _info.Height;
  18. public Target Target => _info.Target;
  19. public Format Format => _info.Format;
  20. public TextureView(
  21. Renderer renderer,
  22. TextureStorage parent,
  23. TextureCreateInfo info,
  24. int firstLayer,
  25. int firstLevel)
  26. {
  27. _renderer = renderer;
  28. _parent = parent;
  29. _info = info;
  30. FirstLayer = firstLayer;
  31. FirstLevel = firstLevel;
  32. Handle = GL.GenTexture();
  33. CreateView();
  34. }
  35. private void CreateView()
  36. {
  37. TextureTarget target = Target.Convert();
  38. FormatInfo format = FormatTable.GetFormatInfo(_info.Format);
  39. PixelInternalFormat pixelInternalFormat;
  40. if (format.IsCompressed)
  41. {
  42. pixelInternalFormat = (PixelInternalFormat)format.PixelFormat;
  43. }
  44. else
  45. {
  46. pixelInternalFormat = format.PixelInternalFormat;
  47. }
  48. GL.TextureView(
  49. Handle,
  50. target,
  51. _parent.Handle,
  52. pixelInternalFormat,
  53. FirstLevel,
  54. _info.Levels,
  55. FirstLayer,
  56. _info.GetLayers());
  57. GL.ActiveTexture(TextureUnit.Texture0);
  58. GL.BindTexture(target, Handle);
  59. int[] swizzleRgba = new int[]
  60. {
  61. (int)_info.SwizzleR.Convert(),
  62. (int)_info.SwizzleG.Convert(),
  63. (int)_info.SwizzleB.Convert(),
  64. (int)_info.SwizzleA.Convert()
  65. };
  66. GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
  67. int maxLevel = _info.Levels - 1;
  68. if (maxLevel < 0)
  69. {
  70. maxLevel = 0;
  71. }
  72. GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel);
  73. GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)_info.DepthStencilMode.Convert());
  74. }
  75. public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
  76. {
  77. if (_info.IsCompressed == info.IsCompressed)
  78. {
  79. firstLayer += FirstLayer;
  80. firstLevel += FirstLevel;
  81. return _parent.CreateView(info, firstLayer, firstLevel);
  82. }
  83. else
  84. {
  85. // TODO: Most graphics APIs doesn't support creating a texture view from a compressed format
  86. // with a non-compressed format (or vice-versa), however NVN seems to support it.
  87. // So we emulate that here with a texture copy (see the first CopyTo overload).
  88. // However right now it only does a single copy right after the view is created,
  89. // so it doesn't work for all cases.
  90. TextureView emulatedView = (TextureView)_renderer.CreateTexture(info);
  91. emulatedView._emulatedViewParent = this;
  92. emulatedView.FirstLayer = firstLayer;
  93. emulatedView.FirstLevel = firstLevel;
  94. return emulatedView;
  95. }
  96. }
  97. public int GetIncompatibleFormatViewHandle()
  98. {
  99. // AMD and Intel has a bug where the view format is always ignored,
  100. // it uses the parent format instead.
  101. // As workaround we create a new texture with the correct
  102. // format, and then do a copy after the draw.
  103. if (_parent.Info.Format != Format)
  104. {
  105. if (_incompatibleFormatView == null)
  106. {
  107. _incompatibleFormatView = (TextureView)_renderer.CreateTexture(_info);
  108. }
  109. TextureCopyUnscaled.Copy(_parent.Info, _incompatibleFormatView._info, _parent.Handle, _incompatibleFormatView.Handle, FirstLayer, 0, FirstLevel, 0);
  110. return _incompatibleFormatView.Handle;
  111. }
  112. return Handle;
  113. }
  114. public void SignalModified()
  115. {
  116. if (_incompatibleFormatView != null)
  117. {
  118. TextureCopyUnscaled.Copy(_incompatibleFormatView._info, _parent.Info, _incompatibleFormatView.Handle, _parent.Handle, 0, FirstLayer, 0, FirstLevel);
  119. }
  120. }
  121. public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
  122. {
  123. TextureView destinationView = (TextureView)destination;
  124. TextureCopyUnscaled.Copy(_info, destinationView._info, Handle, destinationView.Handle, 0, firstLayer, 0, firstLevel);
  125. if (destinationView._emulatedViewParent != null)
  126. {
  127. TextureCopyUnscaled.Copy(
  128. _info,
  129. destinationView._emulatedViewParent._info,
  130. Handle,
  131. destinationView._emulatedViewParent.Handle,
  132. 0,
  133. destinationView.FirstLayer,
  134. 0,
  135. destinationView.FirstLevel);
  136. }
  137. }
  138. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  139. {
  140. _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter);
  141. }
  142. public byte[] GetData()
  143. {
  144. int size = 0;
  145. for (int level = 0; level < _info.Levels; level++)
  146. {
  147. size += _info.GetMipSize(level);
  148. }
  149. byte[] data = new byte[size];
  150. unsafe
  151. {
  152. fixed (byte* ptr = data)
  153. {
  154. WriteTo((IntPtr)ptr);
  155. }
  156. }
  157. return data;
  158. }
  159. private void WriteTo(IntPtr ptr)
  160. {
  161. TextureTarget target = Target.Convert();
  162. Bind(target, 0);
  163. FormatInfo format = FormatTable.GetFormatInfo(_info.Format);
  164. int faces = 1;
  165. if (target == TextureTarget.TextureCubeMap)
  166. {
  167. target = TextureTarget.TextureCubeMapPositiveX;
  168. faces = 6;
  169. }
  170. for (int level = 0; level < _info.Levels; level++)
  171. {
  172. for (int face = 0; face < faces; face++)
  173. {
  174. int faceOffset = face * _info.GetMipSize2D(level);
  175. if (format.IsCompressed)
  176. {
  177. GL.GetCompressedTexImage(target + face, level, ptr + faceOffset);
  178. }
  179. else
  180. {
  181. GL.GetTexImage(
  182. target + face,
  183. level,
  184. format.PixelFormat,
  185. format.PixelType,
  186. ptr + faceOffset);
  187. }
  188. }
  189. ptr += _info.GetMipSize(level);
  190. }
  191. }
  192. public void SetData(ReadOnlySpan<byte> data)
  193. {
  194. unsafe
  195. {
  196. fixed (byte* ptr = data)
  197. {
  198. SetData((IntPtr)ptr, data.Length);
  199. }
  200. }
  201. }
  202. private void SetData(IntPtr data, int size)
  203. {
  204. TextureTarget target = Target.Convert();
  205. Bind(target, 0);
  206. FormatInfo format = FormatTable.GetFormatInfo(_info.Format);
  207. int width = _info.Width;
  208. int height = _info.Height;
  209. int depth = _info.Depth;
  210. int offset = 0;
  211. for (int level = 0; level < _info.Levels; level++)
  212. {
  213. int mipSize = _info.GetMipSize(level);
  214. int endOffset = offset + mipSize;
  215. if ((uint)endOffset > (uint)size)
  216. {
  217. return;
  218. }
  219. switch (_info.Target)
  220. {
  221. case Target.Texture1D:
  222. if (format.IsCompressed)
  223. {
  224. GL.CompressedTexSubImage1D(
  225. target,
  226. level,
  227. 0,
  228. width,
  229. format.PixelFormat,
  230. mipSize,
  231. data);
  232. }
  233. else
  234. {
  235. GL.TexSubImage1D(
  236. target,
  237. level,
  238. 0,
  239. width,
  240. format.PixelFormat,
  241. format.PixelType,
  242. data);
  243. }
  244. break;
  245. case Target.Texture1DArray:
  246. case Target.Texture2D:
  247. if (format.IsCompressed)
  248. {
  249. GL.CompressedTexSubImage2D(
  250. target,
  251. level,
  252. 0,
  253. 0,
  254. width,
  255. height,
  256. format.PixelFormat,
  257. mipSize,
  258. data);
  259. }
  260. else
  261. {
  262. GL.TexSubImage2D(
  263. target,
  264. level,
  265. 0,
  266. 0,
  267. width,
  268. height,
  269. format.PixelFormat,
  270. format.PixelType,
  271. data);
  272. }
  273. break;
  274. case Target.Texture2DArray:
  275. case Target.Texture3D:
  276. case Target.CubemapArray:
  277. if (format.IsCompressed)
  278. {
  279. GL.CompressedTexSubImage3D(
  280. target,
  281. level,
  282. 0,
  283. 0,
  284. 0,
  285. width,
  286. height,
  287. depth,
  288. format.PixelFormat,
  289. mipSize,
  290. data);
  291. }
  292. else
  293. {
  294. GL.TexSubImage3D(
  295. target,
  296. level,
  297. 0,
  298. 0,
  299. 0,
  300. width,
  301. height,
  302. depth,
  303. format.PixelFormat,
  304. format.PixelType,
  305. data);
  306. }
  307. break;
  308. case Target.Cubemap:
  309. int faceOffset = 0;
  310. for (int face = 0; face < 6; face++, faceOffset += mipSize / 6)
  311. {
  312. if (format.IsCompressed)
  313. {
  314. GL.CompressedTexSubImage2D(
  315. TextureTarget.TextureCubeMapPositiveX + face,
  316. level,
  317. 0,
  318. 0,
  319. width,
  320. height,
  321. format.PixelFormat,
  322. mipSize / 6,
  323. data + faceOffset);
  324. }
  325. else
  326. {
  327. GL.TexSubImage2D(
  328. TextureTarget.TextureCubeMapPositiveX + face,
  329. level,
  330. 0,
  331. 0,
  332. width,
  333. height,
  334. format.PixelFormat,
  335. format.PixelType,
  336. data + faceOffset);
  337. }
  338. }
  339. break;
  340. }
  341. data += mipSize;
  342. offset += mipSize;
  343. width = Math.Max(1, width >> 1);
  344. height = Math.Max(1, height >> 1);
  345. if (Target == Target.Texture3D)
  346. {
  347. depth = Math.Max(1, depth >> 1);
  348. }
  349. }
  350. }
  351. public void Bind(int unit)
  352. {
  353. Bind(Target.Convert(), unit);
  354. }
  355. private void Bind(TextureTarget target, int unit)
  356. {
  357. GL.ActiveTexture(TextureUnit.Texture0 + unit);
  358. GL.BindTexture(target, Handle);
  359. }
  360. public void Dispose()
  361. {
  362. if (_incompatibleFormatView != null)
  363. {
  364. _incompatibleFormatView.Dispose();
  365. _incompatibleFormatView = null;
  366. }
  367. if (Handle != 0)
  368. {
  369. GL.DeleteTexture(Handle);
  370. _parent.DecrementViewsCount();
  371. Handle = 0;
  372. }
  373. }
  374. }
  375. }