OGLTexture.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. default:
  157. throw new NotImplementedException($"Unsupported texture target type: {Target}");
  158. }
  159. }
  160. else
  161. {
  162. //TODO: Use KHR_texture_compression_astc_hdr when available
  163. if (IsAstc(Image.Format))
  164. {
  165. int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
  166. int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
  167. int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format);
  168. Data = ASTCDecoder.DecodeToRGBA8888(
  169. Data,
  170. TextureBlockWidth,
  171. TextureBlockHeight,
  172. TextureBlockDepth,
  173. Image.Width,
  174. Image.Height,
  175. Image.Depth);
  176. Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask);
  177. }
  178. (PixelInternalFormat InternalFmt,
  179. PixelFormat Format,
  180. PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
  181. switch (Target)
  182. {
  183. case TextureTarget.Texture1D:
  184. GL.TexImage1D(
  185. Target,
  186. Level,
  187. InternalFmt,
  188. Image.Width,
  189. Border,
  190. Format,
  191. Type,
  192. Data);
  193. break;
  194. case TextureTarget.Texture2D:
  195. GL.TexImage2D(
  196. Target,
  197. Level,
  198. InternalFmt,
  199. Image.Width,
  200. Image.Height,
  201. Border,
  202. Format,
  203. Type,
  204. Data);
  205. break;
  206. case TextureTarget.Texture3D:
  207. GL.TexImage3D(
  208. Target,
  209. Level,
  210. InternalFmt,
  211. Image.Width,
  212. Image.Height,
  213. Image.Depth,
  214. Border,
  215. Format,
  216. Type,
  217. Data);
  218. break;
  219. case TextureTarget.Texture2DArray:
  220. GL.TexImage3D(
  221. Target,
  222. Level,
  223. InternalFmt,
  224. Image.Width,
  225. Image.Height,
  226. Image.LayerCount,
  227. Border,
  228. Format,
  229. Type,
  230. Data);
  231. break;
  232. case TextureTarget.TextureCubeMap:
  233. Span<byte> Array = new Span<byte>(Data);
  234. int FaceSize = ImageUtils.GetSize(Image) / 6;
  235. for (int Face = 0; Face < 6; Face++)
  236. {
  237. GL.TexImage2D(
  238. TextureTarget.TextureCubeMapPositiveX + Face,
  239. Level,
  240. InternalFmt,
  241. Image.Width,
  242. Image.Height,
  243. Border,
  244. Format,
  245. Type,
  246. Array.Slice(Face * FaceSize, FaceSize).ToArray());
  247. }
  248. break;
  249. default:
  250. throw new NotImplementedException($"Unsupported texture target type: {Target}");
  251. }
  252. }
  253. }
  254. private static bool IsAstc(GalImageFormat Format)
  255. {
  256. Format &= GalImageFormat.FormatMask;
  257. return Format > GalImageFormat.Astc2DStart && Format < GalImageFormat.Astc2DEnd;
  258. }
  259. public bool TryGetImage(long Key, out GalImage Image)
  260. {
  261. if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
  262. {
  263. Image = CachedImage.Image;
  264. return true;
  265. }
  266. Image = default(GalImage);
  267. return false;
  268. }
  269. public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
  270. {
  271. if (TextureCache.TryGetValue(Key, out CachedImage))
  272. {
  273. return true;
  274. }
  275. CachedImage = null;
  276. return false;
  277. }
  278. public void Bind(long Key, int Index, GalImage Image)
  279. {
  280. if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
  281. {
  282. GL.ActiveTexture(TextureUnit.Texture0 + Index);
  283. TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
  284. GL.BindTexture(Target, CachedImage.Handle);
  285. int[] SwizzleRgba = new int[]
  286. {
  287. (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource),
  288. (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource),
  289. (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource),
  290. (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
  291. };
  292. GL.TexParameter(Target, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
  293. }
  294. }
  295. public void SetSampler(GalImage Image, GalTextureSampler Sampler)
  296. {
  297. int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
  298. int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
  299. int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP);
  300. int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
  301. int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
  302. TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
  303. GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS);
  304. GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT);
  305. GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR);
  306. GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter);
  307. GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter);
  308. float[] Color = new float[]
  309. {
  310. Sampler.BorderColor.Red,
  311. Sampler.BorderColor.Green,
  312. Sampler.BorderColor.Blue,
  313. Sampler.BorderColor.Alpha
  314. };
  315. GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color);
  316. if (Sampler.DepthCompare)
  317. {
  318. GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
  319. GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc));
  320. }
  321. else
  322. {
  323. GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None);
  324. GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never);
  325. }
  326. }
  327. }
  328. }