OGLTexture.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 OGLCachedResource<ImageHandler> TextureCache;
  9. public OGLTexture()
  10. {
  11. TextureCache = new OGLCachedResource<ImageHandler>(DeleteTexture);
  12. }
  13. public void LockCache()
  14. {
  15. TextureCache.Lock();
  16. }
  17. public void UnlockCache()
  18. {
  19. TextureCache.Unlock();
  20. }
  21. private static void DeleteTexture(ImageHandler CachedImage)
  22. {
  23. GL.DeleteTexture(CachedImage.Handle);
  24. }
  25. public void Create(long Key, byte[] Data, GalImage Image)
  26. {
  27. int Handle = GL.GenTexture();
  28. TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
  29. GL.BindTexture(TextureTarget.Texture2D, Handle);
  30. const int Level = 0; //TODO: Support mipmap textures.
  31. const int Border = 0;
  32. GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
  33. bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
  34. if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
  35. {
  36. InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
  37. GL.CompressedTexImage2D(
  38. TextureTarget.Texture2D,
  39. Level,
  40. InternalFmt,
  41. Image.Width,
  42. Image.Height,
  43. Border,
  44. Data.Length,
  45. Data);
  46. }
  47. else
  48. {
  49. //TODO: Use KHR_texture_compression_astc_hdr when available
  50. if (IsASTC)
  51. {
  52. int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
  53. int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
  54. Data = ASTCDecoder.DecodeToRGBA8888(
  55. Data,
  56. TextureBlockWidth,
  57. TextureBlockHeight, 1,
  58. Image.Width,
  59. Image.Height, 1);
  60. Image.Format = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
  61. }
  62. else if (TypeLess == GalImageFormat.G8R8)
  63. {
  64. Data = ImageConverter.G8R8ToR8G8(
  65. Data,
  66. Image.Width,
  67. Image.Height,
  68. 1);
  69. Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
  70. }
  71. (PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
  72. GL.TexImage2D(
  73. TextureTarget.Texture2D,
  74. Level,
  75. InternalFormat,
  76. Image.Width,
  77. Image.Height,
  78. Border,
  79. Format,
  80. Type,
  81. Data);
  82. }
  83. int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource);
  84. int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource);
  85. int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
  86. int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
  87. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
  88. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
  89. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
  90. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
  91. }
  92. public void CreateFb(long Key, long Size, GalImage Image)
  93. {
  94. if (!TryGetImage(Key, out ImageHandler CachedImage))
  95. {
  96. CachedImage = new ImageHandler();
  97. TextureCache.AddOrUpdate(Key, CachedImage, Size);
  98. }
  99. CachedImage.EnsureSetup(Image);
  100. }
  101. public bool TryGetImage(long Key, out ImageHandler CachedImage)
  102. {
  103. if (TextureCache.TryGetValue(Key, out CachedImage))
  104. {
  105. return true;
  106. }
  107. CachedImage = null;
  108. return false;
  109. }
  110. private static int GetAstcBlockWidth(GalImageFormat Format)
  111. {
  112. switch (Format)
  113. {
  114. case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
  115. case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
  116. case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
  117. case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
  118. case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
  119. case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
  120. case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5;
  121. case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6;
  122. case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8;
  123. case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10;
  124. case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12;
  125. case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8;
  126. case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10;
  127. case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10;
  128. }
  129. throw new ArgumentException(nameof(Format));
  130. }
  131. private static int GetAstcBlockHeight(GalImageFormat Format)
  132. {
  133. switch (Format)
  134. {
  135. case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
  136. case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
  137. case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
  138. case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
  139. case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
  140. case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
  141. case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4;
  142. case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5;
  143. case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6;
  144. case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8;
  145. case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10;
  146. case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5;
  147. case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5;
  148. case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6;
  149. }
  150. throw new ArgumentException(nameof(Format));
  151. }
  152. public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image)
  153. {
  154. if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
  155. {
  156. if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
  157. {
  158. Image = CachedImage.Image;
  159. return true;
  160. }
  161. }
  162. Image = default(GalImage);
  163. return false;
  164. }
  165. public void Bind(long Key, int Index)
  166. {
  167. if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
  168. {
  169. GL.ActiveTexture(TextureUnit.Texture0 + Index);
  170. GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
  171. }
  172. }
  173. public void SetSampler(GalTextureSampler Sampler)
  174. {
  175. int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
  176. int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
  177. int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
  178. int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
  179. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS);
  180. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT);
  181. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
  182. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
  183. float[] Color = new float[]
  184. {
  185. Sampler.BorderColor.Red,
  186. Sampler.BorderColor.Green,
  187. Sampler.BorderColor.Blue,
  188. Sampler.BorderColor.Alpha
  189. };
  190. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
  191. }
  192. }
  193. }