OGLTexture.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Graphics.Gal.Texture;
  3. using System;
  4. namespace Ryujinx.Graphics.Gal.OpenGL
  5. {
  6. public class OGLTexture : IGalTexture
  7. {
  8. private class TCE
  9. {
  10. public int Handle;
  11. public GalTexture Texture;
  12. public TCE(int Handle, GalTexture Texture)
  13. {
  14. this.Handle = Handle;
  15. this.Texture = Texture;
  16. }
  17. }
  18. private OGLCachedResource<TCE> TextureCache;
  19. public OGLTexture()
  20. {
  21. TextureCache = new OGLCachedResource<TCE>(DeleteTexture);
  22. }
  23. public void LockCache()
  24. {
  25. TextureCache.Lock();
  26. }
  27. public void UnlockCache()
  28. {
  29. TextureCache.Unlock();
  30. }
  31. private static void DeleteTexture(TCE CachedTexture)
  32. {
  33. GL.DeleteTexture(CachedTexture.Handle);
  34. }
  35. public void Create(long Key, byte[] Data, GalTexture Texture)
  36. {
  37. int Handle = GL.GenTexture();
  38. TextureCache.AddOrUpdate(Key, new TCE(Handle, Texture), (uint)Data.Length);
  39. GL.BindTexture(TextureTarget.Texture2D, Handle);
  40. const int Level = 0; //TODO: Support mipmap textures.
  41. const int Border = 0;
  42. if (IsCompressedTextureFormat(Texture.Format))
  43. {
  44. InternalFormat InternalFmt = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
  45. GL.CompressedTexImage2D(
  46. TextureTarget.Texture2D,
  47. Level,
  48. InternalFmt,
  49. Texture.Width,
  50. Texture.Height,
  51. Border,
  52. Data.Length,
  53. Data);
  54. }
  55. else
  56. {
  57. if (Texture.Format >= GalTextureFormat.Astc2D4x4)
  58. {
  59. int TextureBlockWidth = GetAstcBlockWidth(Texture.Format);
  60. int TextureBlockHeight = GetAstcBlockHeight(Texture.Format);
  61. Data = ASTCDecoder.DecodeToRGBA8888(
  62. Data,
  63. TextureBlockWidth,
  64. TextureBlockHeight, 1,
  65. Texture.Width,
  66. Texture.Height, 1);
  67. Texture.Format = GalTextureFormat.A8B8G8R8;
  68. }
  69. const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
  70. (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format);
  71. GL.TexImage2D(
  72. TextureTarget.Texture2D,
  73. Level,
  74. InternalFmt,
  75. Texture.Width,
  76. Texture.Height,
  77. Border,
  78. Format,
  79. Type,
  80. Data);
  81. }
  82. int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Texture.XSource);
  83. int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Texture.YSource);
  84. int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Texture.ZSource);
  85. int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Texture.WSource);
  86. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
  87. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
  88. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
  89. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
  90. }
  91. private static int GetAstcBlockWidth(GalTextureFormat Format)
  92. {
  93. switch (Format)
  94. {
  95. case GalTextureFormat.Astc2D4x4: return 4;
  96. case GalTextureFormat.Astc2D5x5: return 5;
  97. case GalTextureFormat.Astc2D6x6: return 6;
  98. case GalTextureFormat.Astc2D8x8: return 8;
  99. case GalTextureFormat.Astc2D10x10: return 10;
  100. case GalTextureFormat.Astc2D12x12: return 12;
  101. case GalTextureFormat.Astc2D5x4: return 5;
  102. case GalTextureFormat.Astc2D6x5: return 6;
  103. case GalTextureFormat.Astc2D8x6: return 8;
  104. case GalTextureFormat.Astc2D10x8: return 10;
  105. case GalTextureFormat.Astc2D12x10: return 12;
  106. case GalTextureFormat.Astc2D8x5: return 8;
  107. case GalTextureFormat.Astc2D10x5: return 10;
  108. case GalTextureFormat.Astc2D10x6: return 10;
  109. }
  110. throw new ArgumentException(nameof(Format));
  111. }
  112. private static int GetAstcBlockHeight(GalTextureFormat Format)
  113. {
  114. switch (Format)
  115. {
  116. case GalTextureFormat.Astc2D4x4: return 4;
  117. case GalTextureFormat.Astc2D5x5: return 5;
  118. case GalTextureFormat.Astc2D6x6: return 6;
  119. case GalTextureFormat.Astc2D8x8: return 8;
  120. case GalTextureFormat.Astc2D10x10: return 10;
  121. case GalTextureFormat.Astc2D12x12: return 12;
  122. case GalTextureFormat.Astc2D5x4: return 4;
  123. case GalTextureFormat.Astc2D6x5: return 5;
  124. case GalTextureFormat.Astc2D8x6: return 6;
  125. case GalTextureFormat.Astc2D10x8: return 8;
  126. case GalTextureFormat.Astc2D12x10: return 10;
  127. case GalTextureFormat.Astc2D8x5: return 5;
  128. case GalTextureFormat.Astc2D10x5: return 5;
  129. case GalTextureFormat.Astc2D10x6: return 6;
  130. }
  131. throw new ArgumentException(nameof(Format));
  132. }
  133. public bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture)
  134. {
  135. if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
  136. {
  137. if (TextureCache.TryGetValue(Key, out TCE CachedTexture))
  138. {
  139. Texture = CachedTexture.Texture;
  140. return true;
  141. }
  142. }
  143. Texture = default(GalTexture);
  144. return false;
  145. }
  146. public void Bind(long Key, int Index)
  147. {
  148. if (TextureCache.TryGetValue(Key, out TCE CachedTexture))
  149. {
  150. GL.ActiveTexture(TextureUnit.Texture0 + Index);
  151. GL.BindTexture(TextureTarget.Texture2D, CachedTexture.Handle);
  152. }
  153. }
  154. public void SetSampler(GalTextureSampler Sampler)
  155. {
  156. int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
  157. int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
  158. int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
  159. int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
  160. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS);
  161. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT);
  162. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
  163. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
  164. float[] Color = new float[]
  165. {
  166. Sampler.BorderColor.Red,
  167. Sampler.BorderColor.Green,
  168. Sampler.BorderColor.Blue,
  169. Sampler.BorderColor.Alpha
  170. };
  171. GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
  172. }
  173. private static bool IsCompressedTextureFormat(GalTextureFormat Format)
  174. {
  175. switch (Format)
  176. {
  177. case GalTextureFormat.BC7U:
  178. case GalTextureFormat.BC1:
  179. case GalTextureFormat.BC2:
  180. case GalTextureFormat.BC3:
  181. case GalTextureFormat.BC4:
  182. case GalTextureFormat.BC5:
  183. return true;
  184. }
  185. return false;
  186. }
  187. }
  188. }