TextureView.cs 14 KB

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