TextureView.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Graphics.GAL;
  3. using System;
  4. namespace Ryujinx.Graphics.OpenGL
  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)
  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);
  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);
  100. }
  101. TextureCopyUnscaled.Copy(_parent.Info, _incompatibleFormatView.Info, _parent.Handle, _incompatibleFormatView.Handle, FirstLayer, 0, FirstLevel, 0);
  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);
  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);
  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. }
  129. }
  130. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  131. {
  132. _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter);
  133. }
  134. public byte[] GetData()
  135. {
  136. int size = 0;
  137. for (int level = 0; level < Info.Levels; level++)
  138. {
  139. size += Info.GetMipSize(level);
  140. }
  141. byte[] data = new byte[size];
  142. unsafe
  143. {
  144. fixed (byte* ptr = data)
  145. {
  146. WriteTo((IntPtr)ptr);
  147. }
  148. }
  149. return data;
  150. }
  151. private void WriteTo(IntPtr ptr)
  152. {
  153. TextureTarget target = Target.Convert();
  154. Bind(target, 0);
  155. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  156. int faces = 1;
  157. if (target == TextureTarget.TextureCubeMap)
  158. {
  159. target = TextureTarget.TextureCubeMapPositiveX;
  160. faces = 6;
  161. }
  162. for (int level = 0; level < Info.Levels; level++)
  163. {
  164. for (int face = 0; face < faces; face++)
  165. {
  166. int faceOffset = face * Info.GetMipSize2D(level);
  167. if (format.IsCompressed)
  168. {
  169. GL.GetCompressedTexImage(target + face, level, ptr + faceOffset);
  170. }
  171. else
  172. {
  173. GL.GetTexImage(
  174. target + face,
  175. level,
  176. format.PixelFormat,
  177. format.PixelType,
  178. ptr + faceOffset);
  179. }
  180. }
  181. ptr += Info.GetMipSize(level);
  182. }
  183. }
  184. public void SetData(ReadOnlySpan<byte> data)
  185. {
  186. unsafe
  187. {
  188. fixed (byte* ptr = data)
  189. {
  190. SetData((IntPtr)ptr, data.Length);
  191. }
  192. }
  193. }
  194. private void SetData(IntPtr data, int size)
  195. {
  196. TextureTarget target = Target.Convert();
  197. Bind(target, 0);
  198. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  199. int width = Info.Width;
  200. int height = Info.Height;
  201. int depth = Info.Depth;
  202. int offset = 0;
  203. for (int level = 0; level < Info.Levels; level++)
  204. {
  205. int mipSize = Info.GetMipSize(level);
  206. int endOffset = offset + mipSize;
  207. if ((uint)endOffset > (uint)size)
  208. {
  209. return;
  210. }
  211. switch (Info.Target)
  212. {
  213. case Target.Texture1D:
  214. if (format.IsCompressed)
  215. {
  216. GL.CompressedTexSubImage1D(
  217. target,
  218. level,
  219. 0,
  220. width,
  221. format.PixelFormat,
  222. mipSize,
  223. data);
  224. }
  225. else
  226. {
  227. GL.TexSubImage1D(
  228. target,
  229. level,
  230. 0,
  231. width,
  232. format.PixelFormat,
  233. format.PixelType,
  234. data);
  235. }
  236. break;
  237. case Target.Texture1DArray:
  238. case Target.Texture2D:
  239. if (format.IsCompressed)
  240. {
  241. GL.CompressedTexSubImage2D(
  242. target,
  243. level,
  244. 0,
  245. 0,
  246. width,
  247. height,
  248. format.PixelFormat,
  249. mipSize,
  250. data);
  251. }
  252. else
  253. {
  254. GL.TexSubImage2D(
  255. target,
  256. level,
  257. 0,
  258. 0,
  259. width,
  260. height,
  261. format.PixelFormat,
  262. format.PixelType,
  263. data);
  264. }
  265. break;
  266. case Target.Texture2DArray:
  267. case Target.Texture3D:
  268. case Target.CubemapArray:
  269. if (format.IsCompressed)
  270. {
  271. GL.CompressedTexSubImage3D(
  272. target,
  273. level,
  274. 0,
  275. 0,
  276. 0,
  277. width,
  278. height,
  279. depth,
  280. format.PixelFormat,
  281. mipSize,
  282. data);
  283. }
  284. else
  285. {
  286. GL.TexSubImage3D(
  287. target,
  288. level,
  289. 0,
  290. 0,
  291. 0,
  292. width,
  293. height,
  294. depth,
  295. format.PixelFormat,
  296. format.PixelType,
  297. data);
  298. }
  299. break;
  300. case Target.Cubemap:
  301. int faceOffset = 0;
  302. for (int face = 0; face < 6; face++, faceOffset += mipSize / 6)
  303. {
  304. if (format.IsCompressed)
  305. {
  306. GL.CompressedTexSubImage2D(
  307. TextureTarget.TextureCubeMapPositiveX + face,
  308. level,
  309. 0,
  310. 0,
  311. width,
  312. height,
  313. format.PixelFormat,
  314. mipSize / 6,
  315. data + faceOffset);
  316. }
  317. else
  318. {
  319. GL.TexSubImage2D(
  320. TextureTarget.TextureCubeMapPositiveX + face,
  321. level,
  322. 0,
  323. 0,
  324. width,
  325. height,
  326. format.PixelFormat,
  327. format.PixelType,
  328. data + faceOffset);
  329. }
  330. }
  331. break;
  332. }
  333. data += mipSize;
  334. offset += mipSize;
  335. width = Math.Max(1, width >> 1);
  336. height = Math.Max(1, height >> 1);
  337. if (Target == Target.Texture3D)
  338. {
  339. depth = Math.Max(1, depth >> 1);
  340. }
  341. }
  342. }
  343. public void SetStorage(BufferRange buffer)
  344. {
  345. throw new NotSupportedException();
  346. }
  347. public void Dispose()
  348. {
  349. if (_incompatibleFormatView != null)
  350. {
  351. _incompatibleFormatView.Dispose();
  352. _incompatibleFormatView = null;
  353. }
  354. if (Handle != 0)
  355. {
  356. GL.DeleteTexture(Handle);
  357. _parent.DecrementViewsCount();
  358. Handle = 0;
  359. }
  360. }
  361. }
  362. }