ImageUtils.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. using Ryujinx.Graphics.Gal;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.Graphics.Texture
  5. {
  6. static class ImageUtils
  7. {
  8. struct ImageDescriptor
  9. {
  10. public TextureReaderDelegate Reader;
  11. public bool HasColor;
  12. public bool HasDepth;
  13. public bool HasStencil;
  14. public bool Compressed;
  15. public ImageDescriptor(
  16. TextureReaderDelegate Reader,
  17. bool HasColor,
  18. bool HasDepth,
  19. bool HasStencil,
  20. bool Compressed)
  21. {
  22. this.Reader = Reader;
  23. this.HasColor = HasColor;
  24. this.HasDepth = HasDepth;
  25. this.HasStencil = HasStencil;
  26. this.Compressed = Compressed;
  27. }
  28. }
  29. private const GalImageFormat Snorm = GalImageFormat.Snorm;
  30. private const GalImageFormat Unorm = GalImageFormat.Unorm;
  31. private const GalImageFormat Sint = GalImageFormat.Sint;
  32. private const GalImageFormat Uint = GalImageFormat.Uint;
  33. private const GalImageFormat Sfloat = GalImageFormat.Sfloat;
  34. private static readonly Dictionary<GalTextureFormat, GalImageFormat> s_TextureTable =
  35. new Dictionary<GalTextureFormat, GalImageFormat>()
  36. {
  37. { GalTextureFormat.R32G32B32A32, GalImageFormat.R32G32B32A32 | Sint | Uint | Sfloat },
  38. { GalTextureFormat.R16G16B16A16, GalImageFormat.R16G16B16A16 | Snorm | Unorm | Sint | Uint | Sfloat },
  39. { GalTextureFormat.R32G32, GalImageFormat.R32G32 | Sint | Uint | Sfloat },
  40. { GalTextureFormat.A8B8G8R8, GalImageFormat.A8B8G8R8 | Snorm | Unorm | Sint | Uint },
  41. { GalTextureFormat.A2B10G10R10, GalImageFormat.A2B10G10R10 | Snorm | Unorm | Sint | Uint },
  42. { GalTextureFormat.G8R8, GalImageFormat.G8R8 | Snorm | Unorm | Sint | Uint },
  43. { GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Sfloat },
  44. { GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
  45. { GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat },
  46. { GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm },
  47. { GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm },
  48. { GalTextureFormat.B5G6R5, GalImageFormat.B5G6R5 | Unorm },
  49. { GalTextureFormat.BF10GF11RF11, GalImageFormat.B10G11R11 | Sfloat },
  50. { GalTextureFormat.Z24S8, GalImageFormat.D24_S8 | Unorm },
  51. { GalTextureFormat.ZF32, GalImageFormat.D32 | Sfloat },
  52. { GalTextureFormat.ZF32_X24S8, GalImageFormat.D32_S8 | Unorm },
  53. //Compressed formats
  54. { GalTextureFormat.BC6H_SF16, GalImageFormat.BC6H_SF16 | Unorm },
  55. { GalTextureFormat.BC6H_UF16, GalImageFormat.BC6H_UF16 | Unorm },
  56. { GalTextureFormat.BC7U, GalImageFormat.BC7 | Unorm },
  57. { GalTextureFormat.BC1, GalImageFormat.BC1_RGBA | Unorm },
  58. { GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm },
  59. { GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm },
  60. { GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
  61. { GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
  62. { GalTextureFormat.Astc2D4x4, GalImageFormat.ASTC_4x4 | Unorm },
  63. { GalTextureFormat.Astc2D5x5, GalImageFormat.ASTC_5x5 | Unorm },
  64. { GalTextureFormat.Astc2D6x6, GalImageFormat.ASTC_6x6 | Unorm },
  65. { GalTextureFormat.Astc2D8x8, GalImageFormat.ASTC_8x8 | Unorm },
  66. { GalTextureFormat.Astc2D10x10, GalImageFormat.ASTC_10x10 | Unorm },
  67. { GalTextureFormat.Astc2D12x12, GalImageFormat.ASTC_12x12 | Unorm },
  68. { GalTextureFormat.Astc2D5x4, GalImageFormat.ASTC_5x4 | Unorm },
  69. { GalTextureFormat.Astc2D6x5, GalImageFormat.ASTC_6x5 | Unorm },
  70. { GalTextureFormat.Astc2D8x6, GalImageFormat.ASTC_8x6 | Unorm },
  71. { GalTextureFormat.Astc2D10x8, GalImageFormat.ASTC_10x8 | Unorm },
  72. { GalTextureFormat.Astc2D12x10, GalImageFormat.ASTC_12x10 | Unorm },
  73. { GalTextureFormat.Astc2D8x5, GalImageFormat.ASTC_8x5 | Unorm },
  74. { GalTextureFormat.Astc2D10x5, GalImageFormat.ASTC_10x5 | Unorm },
  75. { GalTextureFormat.Astc2D10x6, GalImageFormat.ASTC_10x6 | Unorm }
  76. };
  77. private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
  78. new Dictionary<GalImageFormat, ImageDescriptor>()
  79. {
  80. { GalImageFormat.R32G32B32A32, new ImageDescriptor(TextureReader.Read16Bpp, true, false, false, false) },
  81. { GalImageFormat.R16G16B16A16, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
  82. { GalImageFormat.R32G32, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
  83. { GalImageFormat.A8B8G8R8, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
  84. { GalImageFormat.A2B10G10R10, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
  85. { GalImageFormat.R32, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
  86. { GalImageFormat.A4B4G4R4, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
  87. { GalImageFormat.BC6H_SF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  88. { GalImageFormat.BC6H_UF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  89. { GalImageFormat.A1R5G5B5, new ImageDescriptor(TextureReader.Read5551, true, false, false, false) },
  90. { GalImageFormat.B5G6R5, new ImageDescriptor(TextureReader.Read565, true, false, false, false) },
  91. { GalImageFormat.BC7, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  92. { GalImageFormat.R16G16, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
  93. { GalImageFormat.R8G8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
  94. { GalImageFormat.G8R8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
  95. { GalImageFormat.R16, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
  96. { GalImageFormat.R8, new ImageDescriptor(TextureReader.Read1Bpp, true, false, false, false) },
  97. { GalImageFormat.B10G11R11, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
  98. { GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
  99. { GalImageFormat.BC1_RGBA, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
  100. { GalImageFormat.BC2, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  101. { GalImageFormat.BC3, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  102. { GalImageFormat.BC4, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
  103. { GalImageFormat.BC5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  104. { GalImageFormat.ASTC_4x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
  105. { GalImageFormat.ASTC_5x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x5, true, false, false, true) },
  106. { GalImageFormat.ASTC_6x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x6, true, false, false, true) },
  107. { GalImageFormat.ASTC_8x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x8, true, false, false, true) },
  108. { GalImageFormat.ASTC_10x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x10, true, false, false, true) },
  109. { GalImageFormat.ASTC_12x12, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x12, true, false, false, true) },
  110. { GalImageFormat.ASTC_5x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x4, true, false, false, true) },
  111. { GalImageFormat.ASTC_6x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x5, true, false, false, true) },
  112. { GalImageFormat.ASTC_8x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x6, true, false, false, true) },
  113. { GalImageFormat.ASTC_10x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x8, true, false, false, true) },
  114. { GalImageFormat.ASTC_12x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x10, true, false, false, true) },
  115. { GalImageFormat.ASTC_8x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x5, true, false, false, true) },
  116. { GalImageFormat.ASTC_10x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x5, true, false, false, true) },
  117. { GalImageFormat.ASTC_10x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x6, true, false, false, true) },
  118. { GalImageFormat.D24_S8, new ImageDescriptor(TextureReader.Read4Bpp, false, true, true, false) },
  119. { GalImageFormat.D32, new ImageDescriptor(TextureReader.Read4Bpp, false, true, false, false) },
  120. { GalImageFormat.D16, new ImageDescriptor(TextureReader.Read2Bpp, false, true, false, false) },
  121. { GalImageFormat.D32_S8, new ImageDescriptor(TextureReader.Read8Bpp, false, true, true, false) },
  122. };
  123. public static GalImageFormat ConvertTexture(
  124. GalTextureFormat Format,
  125. GalTextureType RType,
  126. GalTextureType GType,
  127. GalTextureType BType,
  128. GalTextureType AType)
  129. {
  130. if (RType != GType || RType != BType || RType != AType)
  131. {
  132. throw new NotImplementedException("Per component types are not implemented");
  133. }
  134. if (!s_TextureTable.TryGetValue(Format, out GalImageFormat ImageFormat))
  135. {
  136. throw new NotImplementedException("Texture with format " + ((int)Format).ToString("x2") + " not implemented");
  137. }
  138. GalTextureType Type = RType;
  139. GalImageFormat FormatType = GetFormatType(RType);
  140. if (ImageFormat.HasFlag(FormatType))
  141. {
  142. return (ImageFormat & GalImageFormat.FormatMask) | FormatType;
  143. }
  144. else
  145. {
  146. throw new NotImplementedException("Texture with format " + Format +
  147. " and component type " + Type + " is not implemented");
  148. }
  149. }
  150. public static GalImageFormat ConvertSurface(GalSurfaceFormat Format)
  151. {
  152. switch (Format)
  153. {
  154. case GalSurfaceFormat.RGBA32Float: return GalImageFormat.R32G32B32A32 | Sfloat;
  155. case GalSurfaceFormat.RGBA16Float: return GalImageFormat.R16G16B16A16 | Sfloat;
  156. case GalSurfaceFormat.RG32Float: return GalImageFormat.R32G32 | Sfloat;
  157. case GalSurfaceFormat.RG32Sint: return GalImageFormat.R32G32 | Sint;
  158. case GalSurfaceFormat.RG32Uint: return GalImageFormat.R32G32 | Uint;
  159. case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.R8G8B8A8 | Unorm; //Is this right?
  160. case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.A8B8G8R8_SRGB; //This one might be wrong
  161. case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.A2B10G10R10 | Unorm;
  162. case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.A8B8G8R8 | Unorm;
  163. case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.A8B8G8R8_SRGB;
  164. case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.A8B8G8R8 | Snorm;
  165. case GalSurfaceFormat.RG16Snorm: return GalImageFormat.R16G16 | Snorm;
  166. case GalSurfaceFormat.RG16Float: return GalImageFormat.R16G16 | Sfloat;
  167. case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.B10G11R11 | Sfloat;
  168. case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Sfloat;
  169. case GalSurfaceFormat.RG8Unorm: return GalImageFormat.R8G8 | Unorm;
  170. case GalSurfaceFormat.RG8Snorm: return GalImageFormat.R8 | Snorm;
  171. case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Sfloat;
  172. case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
  173. }
  174. throw new NotImplementedException(Format.ToString());
  175. }
  176. public static GalImageFormat ConvertZeta(GalZetaFormat Format)
  177. {
  178. switch (Format)
  179. {
  180. case GalZetaFormat.Z32Float: return GalImageFormat.D32 | Sfloat;
  181. case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_S8 | Unorm;
  182. case GalZetaFormat.Z16Unorm: return GalImageFormat.D16 | Unorm;
  183. //This one might not be Uint, change when a texture uses this format
  184. case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Uint;
  185. }
  186. throw new NotImplementedException(Format.ToString());
  187. }
  188. public static TextureReaderDelegate GetReader(GalImageFormat Format)
  189. {
  190. return GetImageDescriptor(Format).Reader;
  191. }
  192. public static int GetSize(GalImage Image)
  193. {
  194. switch (Image.Format & GalImageFormat.FormatMask)
  195. {
  196. case GalImageFormat.R32G32B32A32:
  197. return Image.Width * Image.Height * 16;
  198. case GalImageFormat.R16G16B16A16:
  199. case GalImageFormat.D32_S8:
  200. case GalImageFormat.R32G32:
  201. return Image.Width * Image.Height * 8;
  202. case GalImageFormat.A8B8G8R8:
  203. case GalImageFormat.A8B8G8R8_SRGB:
  204. case GalImageFormat.A2B10G10R10:
  205. case GalImageFormat.R16G16:
  206. case GalImageFormat.R32:
  207. case GalImageFormat.D32:
  208. case GalImageFormat.B10G11R11:
  209. case GalImageFormat.D24_S8:
  210. return Image.Width * Image.Height * 4;
  211. case GalImageFormat.B4G4R4A4:
  212. case GalImageFormat.A1R5G5B5:
  213. case GalImageFormat.B5G6R5:
  214. case GalImageFormat.R8G8:
  215. case GalImageFormat.G8R8:
  216. case GalImageFormat.R16:
  217. case GalImageFormat.D16:
  218. return Image.Width * Image.Height * 2;
  219. case GalImageFormat.R8:
  220. return Image.Width * Image.Height;
  221. case GalImageFormat.BC1_RGBA:
  222. case GalImageFormat.BC4:
  223. {
  224. return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 8);
  225. }
  226. case GalImageFormat.BC6H_SF16:
  227. case GalImageFormat.BC6H_UF16:
  228. case GalImageFormat.BC7:
  229. case GalImageFormat.BC2:
  230. case GalImageFormat.BC3:
  231. case GalImageFormat.BC5:
  232. case GalImageFormat.ASTC_4x4:
  233. return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 16);
  234. case GalImageFormat.ASTC_5x5:
  235. return CompressedTextureSize(Image.Width, Image.Height, 5, 5, 16);
  236. case GalImageFormat.ASTC_6x6:
  237. return CompressedTextureSize(Image.Width, Image.Height, 6, 6, 16);
  238. case GalImageFormat.ASTC_8x8:
  239. return CompressedTextureSize(Image.Width, Image.Height, 8, 8, 16);
  240. case GalImageFormat.ASTC_10x10:
  241. return CompressedTextureSize(Image.Width, Image.Height, 10, 10, 16);
  242. case GalImageFormat.ASTC_12x12:
  243. return CompressedTextureSize(Image.Width, Image.Height, 12, 12, 16);
  244. case GalImageFormat.ASTC_5x4:
  245. return CompressedTextureSize(Image.Width, Image.Height, 5, 4, 16);
  246. case GalImageFormat.ASTC_6x5:
  247. return CompressedTextureSize(Image.Width, Image.Height, 6, 5, 16);
  248. case GalImageFormat.ASTC_8x6:
  249. return CompressedTextureSize(Image.Width, Image.Height, 8, 6, 16);
  250. case GalImageFormat.ASTC_10x8:
  251. return CompressedTextureSize(Image.Width, Image.Height, 10, 8, 16);
  252. case GalImageFormat.ASTC_12x10:
  253. return CompressedTextureSize(Image.Width, Image.Height, 12, 10, 16);
  254. case GalImageFormat.ASTC_8x5:
  255. return CompressedTextureSize(Image.Width, Image.Height, 8, 5, 16);
  256. case GalImageFormat.ASTC_10x5:
  257. return CompressedTextureSize(Image.Width, Image.Height, 10, 5, 16);
  258. case GalImageFormat.ASTC_10x6:
  259. return CompressedTextureSize(Image.Width, Image.Height, 10, 6, 16);
  260. }
  261. throw new NotImplementedException((Image.Format & GalImageFormat.FormatMask).ToString());
  262. }
  263. public static bool HasColor(GalImageFormat Format)
  264. {
  265. return GetImageDescriptor(Format).HasColor;
  266. }
  267. public static bool HasDepth(GalImageFormat Format)
  268. {
  269. return GetImageDescriptor(Format).HasDepth;
  270. }
  271. public static bool HasStencil(GalImageFormat Format)
  272. {
  273. return GetImageDescriptor(Format).HasStencil;
  274. }
  275. public static bool IsCompressed(GalImageFormat Format)
  276. {
  277. return GetImageDescriptor(Format).Compressed;
  278. }
  279. private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
  280. {
  281. GalImageFormat TypeLess = (Format & GalImageFormat.FormatMask);
  282. if (s_ImageTable.TryGetValue(TypeLess, out ImageDescriptor Descriptor))
  283. {
  284. return Descriptor;
  285. }
  286. throw new NotImplementedException("Image with format " + TypeLess.ToString() + " not implemented");
  287. }
  288. private static GalImageFormat GetFormatType(GalTextureType Type)
  289. {
  290. switch (Type)
  291. {
  292. case GalTextureType.Snorm: return Snorm;
  293. case GalTextureType.Unorm: return Unorm;
  294. case GalTextureType.Sint: return Sint;
  295. case GalTextureType.Uint: return Uint;
  296. case GalTextureType.Float: return Sfloat;
  297. default: throw new NotImplementedException(((int)Type).ToString());
  298. }
  299. }
  300. private static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb)
  301. {
  302. int W = (TextureWidth + (BlockWidth - 1)) / BlockWidth;
  303. int H = (TextureHeight + (BlockHeight - 1)) / BlockHeight;
  304. return W * H * Bpb;
  305. }
  306. }
  307. }