OglTexture.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Graphics.Texture;
  3. using System;
  4. namespace Ryujinx.Graphics.Gal.OpenGL
  5. {
  6. class OglTexture : IGalTexture
  7. {
  8. private const long MaxTextureCacheSize = 768 * 1024 * 1024;
  9. private OglCachedResource<ImageHandler> _textureCache;
  10. public EventHandler<int> TextureDeleted { get; set; }
  11. public OglTexture()
  12. {
  13. _textureCache = new OglCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
  14. }
  15. public void LockCache()
  16. {
  17. _textureCache.Lock();
  18. }
  19. public void UnlockCache()
  20. {
  21. _textureCache.Unlock();
  22. }
  23. private void DeleteTexture(ImageHandler cachedImage)
  24. {
  25. TextureDeleted?.Invoke(this, cachedImage.Handle);
  26. GL.DeleteTexture(cachedImage.Handle);
  27. }
  28. public void Create(long key, int size, GalImage image)
  29. {
  30. int handle = GL.GenTexture();
  31. TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
  32. GL.BindTexture(target, handle);
  33. const int level = 0; //TODO: Support mipmap textures.
  34. const int border = 0;
  35. _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)size);
  36. if (ImageUtils.IsCompressed(image.Format))
  37. {
  38. throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
  39. }
  40. (PixelInternalFormat internalFmt,
  41. PixelFormat format,
  42. PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
  43. switch (target)
  44. {
  45. case TextureTarget.Texture1D:
  46. GL.TexImage1D(
  47. target,
  48. level,
  49. internalFmt,
  50. image.Width,
  51. border,
  52. format,
  53. type,
  54. IntPtr.Zero);
  55. break;
  56. case TextureTarget.Texture2D:
  57. GL.TexImage2D(
  58. target,
  59. level,
  60. internalFmt,
  61. image.Width,
  62. image.Height,
  63. border,
  64. format,
  65. type,
  66. IntPtr.Zero);
  67. break;
  68. case TextureTarget.Texture3D:
  69. GL.TexImage3D(
  70. target,
  71. level,
  72. internalFmt,
  73. image.Width,
  74. image.Height,
  75. image.Depth,
  76. border,
  77. format,
  78. type,
  79. IntPtr.Zero);
  80. break;
  81. case TextureTarget.Texture2DArray:
  82. GL.TexImage3D(
  83. target,
  84. level,
  85. internalFmt,
  86. image.Width,
  87. image.Height,
  88. image.LayerCount,
  89. border,
  90. format,
  91. type,
  92. IntPtr.Zero);
  93. break;
  94. default:
  95. throw new NotImplementedException($"Unsupported texture target type: {target}");
  96. }
  97. }
  98. public void Create(long key, byte[] data, GalImage image)
  99. {
  100. int handle = GL.GenTexture();
  101. TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
  102. GL.BindTexture(target, handle);
  103. const int level = 0; //TODO: Support mipmap textures.
  104. const int border = 0;
  105. _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)data.Length);
  106. if (ImageUtils.IsCompressed(image.Format) && !IsAstc(image.Format))
  107. {
  108. InternalFormat internalFmt = OglEnumConverter.GetCompressedImageFormat(image.Format);
  109. switch (target)
  110. {
  111. case TextureTarget.Texture1D:
  112. GL.CompressedTexImage1D(
  113. target,
  114. level,
  115. internalFmt,
  116. image.Width,
  117. border,
  118. data.Length,
  119. data);
  120. break;
  121. case TextureTarget.Texture2D:
  122. GL.CompressedTexImage2D(
  123. target,
  124. level,
  125. internalFmt,
  126. image.Width,
  127. image.Height,
  128. border,
  129. data.Length,
  130. data);
  131. break;
  132. case TextureTarget.Texture3D:
  133. GL.CompressedTexImage3D(
  134. target,
  135. level,
  136. internalFmt,
  137. image.Width,
  138. image.Height,
  139. image.Depth,
  140. border,
  141. data.Length,
  142. data);
  143. break;
  144. case TextureTarget.Texture2DArray:
  145. GL.CompressedTexImage3D(
  146. target,
  147. level,
  148. internalFmt,
  149. image.Width,
  150. image.Height,
  151. image.LayerCount,
  152. border,
  153. data.Length,
  154. data);
  155. break;
  156. case TextureTarget.TextureCubeMap:
  157. Span<byte> array = new Span<byte>(data);
  158. int faceSize = ImageUtils.GetSize(image) / 6;
  159. for (int Face = 0; Face < 6; Face++)
  160. {
  161. GL.CompressedTexImage2D(
  162. TextureTarget.TextureCubeMapPositiveX + Face,
  163. level,
  164. internalFmt,
  165. image.Width,
  166. image.Height,
  167. border,
  168. faceSize,
  169. array.Slice(Face * faceSize, faceSize).ToArray());
  170. }
  171. break;
  172. default:
  173. throw new NotImplementedException($"Unsupported texture target type: {target}");
  174. }
  175. }
  176. else
  177. {
  178. //TODO: Use KHR_texture_compression_astc_hdr when available
  179. if (IsAstc(image.Format))
  180. {
  181. int textureBlockWidth = ImageUtils.GetBlockWidth(image.Format);
  182. int textureBlockHeight = ImageUtils.GetBlockHeight(image.Format);
  183. int textureBlockDepth = ImageUtils.GetBlockDepth(image.Format);
  184. data = AstcDecoder.DecodeToRgba8888(
  185. data,
  186. textureBlockWidth,
  187. textureBlockHeight,
  188. textureBlockDepth,
  189. image.Width,
  190. image.Height,
  191. image.Depth);
  192. image.Format = GalImageFormat.Rgba8 | (image.Format & GalImageFormat.TypeMask);
  193. }
  194. (PixelInternalFormat internalFmt,
  195. PixelFormat format,
  196. PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
  197. switch (target)
  198. {
  199. case TextureTarget.Texture1D:
  200. GL.TexImage1D(
  201. target,
  202. level,
  203. internalFmt,
  204. image.Width,
  205. border,
  206. format,
  207. type,
  208. data);
  209. break;
  210. case TextureTarget.Texture2D:
  211. GL.TexImage2D(
  212. target,
  213. level,
  214. internalFmt,
  215. image.Width,
  216. image.Height,
  217. border,
  218. format,
  219. type,
  220. data);
  221. break;
  222. case TextureTarget.Texture3D:
  223. GL.TexImage3D(
  224. target,
  225. level,
  226. internalFmt,
  227. image.Width,
  228. image.Height,
  229. image.Depth,
  230. border,
  231. format,
  232. type,
  233. data);
  234. break;
  235. case TextureTarget.Texture2DArray:
  236. GL.TexImage3D(
  237. target,
  238. level,
  239. internalFmt,
  240. image.Width,
  241. image.Height,
  242. image.LayerCount,
  243. border,
  244. format,
  245. type,
  246. data);
  247. break;
  248. case TextureTarget.TextureCubeMap:
  249. Span<byte> array = new Span<byte>(data);
  250. int faceSize = ImageUtils.GetSize(image) / 6;
  251. for (int face = 0; face < 6; face++)
  252. {
  253. GL.TexImage2D(
  254. TextureTarget.TextureCubeMapPositiveX + face,
  255. level,
  256. internalFmt,
  257. image.Width,
  258. image.Height,
  259. border,
  260. format,
  261. type,
  262. array.Slice(face * faceSize, faceSize).ToArray());
  263. }
  264. break;
  265. default:
  266. throw new NotImplementedException($"Unsupported texture target type: {target}");
  267. }
  268. }
  269. }
  270. private static bool IsAstc(GalImageFormat format)
  271. {
  272. format &= GalImageFormat.FormatMask;
  273. return format > GalImageFormat.Astc2DStart && format < GalImageFormat.Astc2DEnd;
  274. }
  275. public bool TryGetImage(long key, out GalImage image)
  276. {
  277. if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
  278. {
  279. image = cachedImage.Image;
  280. return true;
  281. }
  282. image = default(GalImage);
  283. return false;
  284. }
  285. public bool TryGetImageHandler(long key, out ImageHandler cachedImage)
  286. {
  287. if (_textureCache.TryGetValue(key, out cachedImage))
  288. {
  289. return true;
  290. }
  291. cachedImage = null;
  292. return false;
  293. }
  294. public void Bind(long key, int index, GalImage image)
  295. {
  296. if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
  297. {
  298. GL.ActiveTexture(TextureUnit.Texture0 + index);
  299. TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
  300. GL.BindTexture(target, cachedImage.Handle);
  301. int[] swizzleRgba = new int[]
  302. {
  303. (int)OglEnumConverter.GetTextureSwizzle(image.XSource),
  304. (int)OglEnumConverter.GetTextureSwizzle(image.YSource),
  305. (int)OglEnumConverter.GetTextureSwizzle(image.ZSource),
  306. (int)OglEnumConverter.GetTextureSwizzle(image.WSource)
  307. };
  308. GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
  309. }
  310. }
  311. public void SetSampler(GalImage image, GalTextureSampler sampler)
  312. {
  313. int wrapS = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressU);
  314. int wrapT = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressV);
  315. int wrapR = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressP);
  316. int minFilter = (int)OglEnumConverter.GetTextureMinFilter(sampler.MinFilter, sampler.MipFilter);
  317. int magFilter = (int)OglEnumConverter.GetTextureMagFilter(sampler.MagFilter);
  318. TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
  319. GL.TexParameter(target, TextureParameterName.TextureWrapS, wrapS);
  320. GL.TexParameter(target, TextureParameterName.TextureWrapT, wrapT);
  321. GL.TexParameter(target, TextureParameterName.TextureWrapR, wrapR);
  322. GL.TexParameter(target, TextureParameterName.TextureMinFilter, minFilter);
  323. GL.TexParameter(target, TextureParameterName.TextureMagFilter, magFilter);
  324. float[] color = new float[]
  325. {
  326. sampler.BorderColor.Red,
  327. sampler.BorderColor.Green,
  328. sampler.BorderColor.Blue,
  329. sampler.BorderColor.Alpha
  330. };
  331. GL.TexParameter(target, TextureParameterName.TextureBorderColor, color);
  332. if (sampler.DepthCompare)
  333. {
  334. GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
  335. GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)OglEnumConverter.GetDepthCompareFunc(sampler.DepthCompareFunc));
  336. }
  337. else
  338. {
  339. GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.None);
  340. GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)All.Never);
  341. }
  342. }
  343. }
  344. }