TextureView.cs 13 KB

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