ImageUtils.cs 22 KB

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