ImageUtils.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. using ARMeilleure.Memory;
  2. using OpenTK.Graphics.OpenGL;
  3. using Ryujinx.Graphics.Gal;
  4. using Ryujinx.Graphics.Memory;
  5. using System;
  6. using System.Collections.Generic;
  7. namespace Ryujinx.Graphics.Texture
  8. {
  9. public static class ImageUtils
  10. {
  11. [Flags]
  12. private enum TargetBuffer
  13. {
  14. Color = 1 << 0,
  15. Depth = 1 << 1,
  16. Stencil = 1 << 2,
  17. DepthStencil = Depth | Stencil
  18. }
  19. private struct ImageDescriptor
  20. {
  21. public int BytesPerPixel { get; private set; }
  22. public int BlockWidth { get; private set; }
  23. public int BlockHeight { get; private set; }
  24. public int BlockDepth { get; private set; }
  25. public TargetBuffer Target { get; private set; }
  26. public ImageDescriptor(int bytesPerPixel, int blockWidth, int blockHeight, int blockDepth, TargetBuffer target)
  27. {
  28. BytesPerPixel = bytesPerPixel;
  29. BlockWidth = blockWidth;
  30. BlockHeight = blockHeight;
  31. BlockDepth = blockDepth;
  32. Target = target;
  33. }
  34. }
  35. private const GalImageFormat Snorm = GalImageFormat.Snorm;
  36. private const GalImageFormat Unorm = GalImageFormat.Unorm;
  37. private const GalImageFormat Sint = GalImageFormat.Sint;
  38. private const GalImageFormat Uint = GalImageFormat.Uint;
  39. private const GalImageFormat Float = GalImageFormat.Float;
  40. private const GalImageFormat Srgb = GalImageFormat.Srgb;
  41. private static readonly Dictionary<GalTextureFormat, GalImageFormat> TextureTable =
  42. new Dictionary<GalTextureFormat, GalImageFormat>()
  43. {
  44. { GalTextureFormat.Rgba32, GalImageFormat.Rgba32 | Sint | Uint | Float },
  45. { GalTextureFormat.Rgba16, GalImageFormat.Rgba16 | Snorm | Unorm | Sint | Uint | Float },
  46. { GalTextureFormat.Rg32, GalImageFormat.Rg32 | Sint | Uint | Float },
  47. { GalTextureFormat.Rgba8, GalImageFormat.Rgba8 | Snorm | Unorm | Sint | Uint | Srgb },
  48. { GalTextureFormat.Rgb10A2, GalImageFormat.Rgb10A2 | Snorm | Unorm | Sint | Uint },
  49. { GalTextureFormat.Rg8, GalImageFormat.Rg8 | Snorm | Unorm | Sint | Uint },
  50. { GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float },
  51. { GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
  52. { GalTextureFormat.Rg16, GalImageFormat.Rg16 | Snorm | Unorm | Sint | Float },
  53. { GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Float },
  54. { GalTextureFormat.Rgba4, GalImageFormat.Rgba4 | Unorm },
  55. { GalTextureFormat.Rgb5A1, GalImageFormat.Rgb5A1 | Unorm },
  56. { GalTextureFormat.Rgb565, GalImageFormat.Rgb565 | Unorm },
  57. { GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float },
  58. { GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint },
  59. { GalTextureFormat.D32F, GalImageFormat.D32 | Float },
  60. { GalTextureFormat.D32Fx24S8, GalImageFormat.D32S8 | Float },
  61. { GalTextureFormat.D16, GalImageFormat.D16 | Unorm },
  62. // Compressed formats
  63. { GalTextureFormat.BptcSfloat, GalImageFormat.BptcSfloat | Float },
  64. { GalTextureFormat.BptcUfloat, GalImageFormat.BptcUfloat | Float },
  65. { GalTextureFormat.BptcUnorm, GalImageFormat.BptcUnorm | Unorm | Srgb },
  66. { GalTextureFormat.BC1, GalImageFormat.BC1 | Unorm | Srgb },
  67. { GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm | Srgb },
  68. { GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm | Srgb },
  69. { GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
  70. { GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
  71. { GalTextureFormat.Astc2D4x4, GalImageFormat.Astc2D4x4 | Unorm | Srgb },
  72. { GalTextureFormat.Astc2D5x5, GalImageFormat.Astc2D5x5 | Unorm | Srgb },
  73. { GalTextureFormat.Astc2D6x6, GalImageFormat.Astc2D6x6 | Unorm | Srgb },
  74. { GalTextureFormat.Astc2D8x8, GalImageFormat.Astc2D8x8 | Unorm | Srgb },
  75. { GalTextureFormat.Astc2D10x10, GalImageFormat.Astc2D10x10 | Unorm | Srgb },
  76. { GalTextureFormat.Astc2D12x12, GalImageFormat.Astc2D12x12 | Unorm | Srgb },
  77. { GalTextureFormat.Astc2D5x4, GalImageFormat.Astc2D5x4 | Unorm | Srgb },
  78. { GalTextureFormat.Astc2D6x5, GalImageFormat.Astc2D6x5 | Unorm | Srgb },
  79. { GalTextureFormat.Astc2D8x6, GalImageFormat.Astc2D8x6 | Unorm | Srgb },
  80. { GalTextureFormat.Astc2D10x8, GalImageFormat.Astc2D10x8 | Unorm | Srgb },
  81. { GalTextureFormat.Astc2D12x10, GalImageFormat.Astc2D12x10 | Unorm | Srgb },
  82. { GalTextureFormat.Astc2D8x5, GalImageFormat.Astc2D8x5 | Unorm | Srgb },
  83. { GalTextureFormat.Astc2D10x5, GalImageFormat.Astc2D10x5 | Unorm | Srgb },
  84. { GalTextureFormat.Astc2D10x6, GalImageFormat.Astc2D10x6 | Unorm | Srgb }
  85. };
  86. private static readonly Dictionary<GalImageFormat, ImageDescriptor> ImageTable =
  87. new Dictionary<GalImageFormat, ImageDescriptor>()
  88. {
  89. { GalImageFormat.Rgba32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) },
  90. { GalImageFormat.Rgba16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
  91. { GalImageFormat.Rg32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
  92. { GalImageFormat.Rgbx8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  93. { GalImageFormat.Rgba8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  94. { GalImageFormat.Bgra8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  95. { GalImageFormat.Rgb10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  96. { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  97. { GalImageFormat.Rgba4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  98. { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  99. { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  100. { GalImageFormat.Bgr5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  101. { GalImageFormat.Rgb5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  102. { GalImageFormat.Rgb565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  103. { GalImageFormat.Bgr565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  104. { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  105. { GalImageFormat.Rg16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  106. { GalImageFormat.Rg8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  107. { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
  108. { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) },
  109. { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
  110. { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) },
  111. { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  112. { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  113. { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) },
  114. { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  115. { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
  116. { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, 1, TargetBuffer.Color) },
  117. { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, 1, TargetBuffer.Color) },
  118. { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, 1, TargetBuffer.Color) },
  119. { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, 1, TargetBuffer.Color) },
  120. { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, 1, TargetBuffer.Color) },
  121. { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, 1, TargetBuffer.Color) },
  122. { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, 1, TargetBuffer.Color) },
  123. { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, 1, TargetBuffer.Color) },
  124. { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, 1, TargetBuffer.Color) },
  125. { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, 1, TargetBuffer.Color) },
  126. { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, 1, TargetBuffer.Color) },
  127. { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, 1, TargetBuffer.Color) },
  128. { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, 1, TargetBuffer.Color) },
  129. { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Depth) },
  130. { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) },
  131. { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.DepthStencil) },
  132. { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) },
  133. { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.DepthStencil) }
  134. };
  135. public static GalImageFormat ConvertTexture(
  136. GalTextureFormat format,
  137. GalTextureType rType,
  138. GalTextureType gType,
  139. GalTextureType bType,
  140. GalTextureType aType,
  141. bool convSrgb)
  142. {
  143. if (!TextureTable.TryGetValue(format, out GalImageFormat imageFormat))
  144. {
  145. throw new NotImplementedException($"Format 0x{((int)format):x} not implemented!");
  146. }
  147. if (!HasDepth(imageFormat) && (rType != gType || rType != bType || rType != aType))
  148. {
  149. throw new NotImplementedException("Per component types are not implemented!");
  150. }
  151. GalImageFormat formatType = convSrgb ? Srgb : GetFormatType(rType);
  152. GalImageFormat combinedFormat = (imageFormat & GalImageFormat.FormatMask) | formatType;
  153. if (!imageFormat.HasFlag(formatType))
  154. {
  155. throw new NotImplementedException($"Format \"{combinedFormat}\" not implemented!");
  156. }
  157. return combinedFormat;
  158. }
  159. public static GalImageFormat ConvertSurface(GalSurfaceFormat format)
  160. {
  161. switch (format)
  162. {
  163. case GalSurfaceFormat.Rgba32Float: return GalImageFormat.Rgba32 | Float;
  164. case GalSurfaceFormat.Rgba32Uint: return GalImageFormat.Rgba32 | Uint;
  165. case GalSurfaceFormat.Rgba16Float: return GalImageFormat.Rgba16 | Float;
  166. case GalSurfaceFormat.Rgba16Uint: return GalImageFormat.Rgba16 | Uint;
  167. case GalSurfaceFormat.Rgba16Unorm: return GalImageFormat.Rgba16 | Unorm;
  168. case GalSurfaceFormat.Rg32Float: return GalImageFormat.Rg32 | Float;
  169. case GalSurfaceFormat.Rg32Sint: return GalImageFormat.Rg32 | Sint;
  170. case GalSurfaceFormat.Rg32Uint: return GalImageFormat.Rg32 | Uint;
  171. case GalSurfaceFormat.Bgra8Unorm: return GalImageFormat.Bgra8 | Unorm;
  172. case GalSurfaceFormat.Bgra8Srgb: return GalImageFormat.Bgra8 | Srgb;
  173. case GalSurfaceFormat.Rgb10A2Unorm: return GalImageFormat.Rgb10A2 | Unorm;
  174. case GalSurfaceFormat.Rgba8Unorm: return GalImageFormat.Rgba8 | Unorm;
  175. case GalSurfaceFormat.Rgba8Srgb: return GalImageFormat.Rgba8 | Srgb;
  176. case GalSurfaceFormat.Rgba8Snorm: return GalImageFormat.Rgba8 | Snorm;
  177. case GalSurfaceFormat.Rg16Snorm: return GalImageFormat.Rg16 | Snorm;
  178. case GalSurfaceFormat.Rg16Unorm: return GalImageFormat.Rg16 | Unorm;
  179. case GalSurfaceFormat.Rg16Sint: return GalImageFormat.Rg16 | Sint;
  180. case GalSurfaceFormat.Rg16Float: return GalImageFormat.Rg16 | Float;
  181. case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float;
  182. case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float;
  183. case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint;
  184. case GalSurfaceFormat.Rg8Unorm: return GalImageFormat.Rg8 | Unorm;
  185. case GalSurfaceFormat.Rg8Snorm: return GalImageFormat.Rg8 | Snorm;
  186. case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float;
  187. case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
  188. case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint;
  189. case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
  190. case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint;
  191. case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.Rgb565 | Unorm;
  192. case GalSurfaceFormat.Bgr5A1Unorm: return GalImageFormat.Bgr5A1 | Unorm;
  193. case GalSurfaceFormat.Rgbx8Unorm: return GalImageFormat.Rgbx8 | Unorm;
  194. }
  195. throw new NotImplementedException(format.ToString());
  196. }
  197. public static GalImageFormat ConvertZeta(GalZetaFormat format)
  198. {
  199. switch (format)
  200. {
  201. case GalZetaFormat.D32Float: return GalImageFormat.D32 | Float;
  202. case GalZetaFormat.S8D24Unorm: return GalImageFormat.D24S8 | Unorm;
  203. case GalZetaFormat.D16Unorm: return GalImageFormat.D16 | Unorm;
  204. case GalZetaFormat.D24X8Unorm: return GalImageFormat.D24 | Unorm;
  205. case GalZetaFormat.D24S8Unorm: return GalImageFormat.D24S8 | Unorm;
  206. case GalZetaFormat.D32S8X24Float: return GalImageFormat.D32S8 | Float;
  207. }
  208. throw new NotImplementedException(format.ToString());
  209. }
  210. public static byte[] ReadTexture(IMemory memory, GalImage image, long position)
  211. {
  212. IMemoryManager cpuMemory;
  213. if (memory is NvGpuVmm vmm)
  214. {
  215. cpuMemory = vmm.Memory;
  216. }
  217. else
  218. {
  219. cpuMemory = (IMemoryManager)memory;
  220. }
  221. ISwizzle swizzle = TextureHelper.GetSwizzle(image);
  222. ImageDescriptor desc = GetImageDescriptor(image.Format);
  223. (int width, int height, int depth) = GetImageSizeInBlocks(image);
  224. int bytesPerPixel = desc.BytesPerPixel;
  225. // Note: Each row of the texture needs to be aligned to 4 bytes.
  226. int pitch = (width * bytesPerPixel + 3) & ~3;
  227. int dataLayerSize = height * pitch * depth;
  228. byte[] data = new byte[dataLayerSize * image.LayerCount];
  229. int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
  230. int layerOffset = GetLayerOffset(image, targetMipLevel);
  231. for (int layer = 0; layer < image.LayerCount; layer++)
  232. {
  233. for (int z = 0; z < depth; z++)
  234. {
  235. for (int y = 0; y < height; y++)
  236. {
  237. int outOffs = (dataLayerSize * layer) + y * pitch + (z * width * height * bytesPerPixel);
  238. for (int x = 0; x < width; x++)
  239. {
  240. long offset = (uint)swizzle.GetSwizzleOffset(x, y, z);
  241. cpuMemory.ReadBytes(position + (layerOffset * layer) + offset, data, outOffs, bytesPerPixel);
  242. outOffs += bytesPerPixel;
  243. }
  244. }
  245. }
  246. }
  247. return data;
  248. }
  249. public static void WriteTexture(NvGpuVmm vmm, GalImage image, long position, byte[] data)
  250. {
  251. ISwizzle swizzle = TextureHelper.GetSwizzle(image);
  252. ImageDescriptor desc = GetImageDescriptor(image.Format);
  253. (int width, int height, int depth) = GetImageSizeInBlocks(image);
  254. int bytesPerPixel = desc.BytesPerPixel;
  255. int inOffs = 0;
  256. for (int z = 0; z < depth; z++)
  257. for (int y = 0; y < height; y++)
  258. for (int x = 0; x < width; x++)
  259. {
  260. long offset = (uint)swizzle.GetSwizzleOffset(x, y, z);
  261. vmm.Memory.WriteBytes(position + offset, data, inOffs, bytesPerPixel);
  262. inOffs += bytesPerPixel;
  263. }
  264. }
  265. // TODO: Support non 2D
  266. public static bool CopyTexture(
  267. NvGpuVmm vmm,
  268. GalImage srcImage,
  269. GalImage dstImage,
  270. long srcAddress,
  271. long dstAddress,
  272. int srcX,
  273. int srcY,
  274. int dstX,
  275. int dstY,
  276. int width,
  277. int height)
  278. {
  279. ISwizzle srcSwizzle = TextureHelper.GetSwizzle(srcImage);
  280. ISwizzle dstSwizzle = TextureHelper.GetSwizzle(dstImage);
  281. ImageDescriptor desc = GetImageDescriptor(srcImage.Format);
  282. if (GetImageDescriptor(dstImage.Format).BytesPerPixel != desc.BytesPerPixel)
  283. {
  284. return false;
  285. }
  286. int bytesPerPixel = desc.BytesPerPixel;
  287. for (int y = 0; y < height; y++)
  288. for (int x = 0; x < width; x++)
  289. {
  290. long srcOffset = (uint)srcSwizzle.GetSwizzleOffset(srcX + x, srcY + y, 0);
  291. long dstOffset = (uint)dstSwizzle.GetSwizzleOffset(dstX + x, dstY + y, 0);
  292. byte[] texel = vmm.ReadBytes(srcAddress + srcOffset, bytesPerPixel);
  293. vmm.WriteBytes(dstAddress + dstOffset, texel);
  294. }
  295. return true;
  296. }
  297. public static int GetSize(GalImage image)
  298. {
  299. ImageDescriptor desc = GetImageDescriptor(image.Format);
  300. int componentCount = GetCoordsCountTextureTarget(image.TextureTarget);
  301. if (IsArray(image.TextureTarget))
  302. componentCount--;
  303. int width = DivRoundUp(image.Width, desc.BlockWidth);
  304. int height = DivRoundUp(image.Height, desc.BlockHeight);
  305. int depth = DivRoundUp(image.Depth, desc.BlockDepth);
  306. switch (componentCount)
  307. {
  308. case 1:
  309. return desc.BytesPerPixel * width * image.LayerCount;
  310. case 2:
  311. return desc.BytesPerPixel * width * height * image.LayerCount;
  312. case 3:
  313. return desc.BytesPerPixel * width * height * depth * image.LayerCount;
  314. default:
  315. throw new InvalidOperationException($"Invalid component count: {componentCount}");
  316. }
  317. }
  318. public static int GetGpuSize(GalImage image, bool forcePitch = false)
  319. {
  320. return TextureHelper.GetSwizzle(image).GetImageSize(image.MaxMipmapLevel) * image.LayerCount;
  321. }
  322. public static int GetLayerOffset(GalImage image, int mipLevel)
  323. {
  324. if (mipLevel <= 0)
  325. {
  326. mipLevel = 1;
  327. }
  328. return TextureHelper.GetSwizzle(image).GetMipOffset(mipLevel);
  329. }
  330. public static int GetPitch(GalImageFormat format, int width)
  331. {
  332. ImageDescriptor desc = GetImageDescriptor(format);
  333. int pitch = desc.BytesPerPixel * DivRoundUp(width, desc.BlockWidth);
  334. pitch = (pitch + 0x1f) & ~0x1f;
  335. return pitch;
  336. }
  337. public static int GetBlockWidth(GalImageFormat format)
  338. {
  339. return GetImageDescriptor(format).BlockWidth;
  340. }
  341. public static int GetBlockHeight(GalImageFormat format)
  342. {
  343. return GetImageDescriptor(format).BlockHeight;
  344. }
  345. public static int GetBlockDepth(GalImageFormat format)
  346. {
  347. return GetImageDescriptor(format).BlockDepth;
  348. }
  349. public static int GetAlignedWidth(GalImage image)
  350. {
  351. ImageDescriptor desc = GetImageDescriptor(image.Format);
  352. int alignMask;
  353. if (image.Layout == GalMemoryLayout.BlockLinear)
  354. {
  355. alignMask = image.TileWidth * (64 / desc.BytesPerPixel) - 1;
  356. }
  357. else
  358. {
  359. alignMask = (32 / desc.BytesPerPixel) - 1;
  360. }
  361. return (image.Width + alignMask) & ~alignMask;
  362. }
  363. public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage image)
  364. {
  365. ImageDescriptor desc = GetImageDescriptor(image.Format);
  366. return (DivRoundUp(image.Width, desc.BlockWidth),
  367. DivRoundUp(image.Height, desc.BlockHeight),
  368. DivRoundUp(image.Depth, desc.BlockDepth));
  369. }
  370. public static int GetBytesPerPixel(GalImageFormat format)
  371. {
  372. return GetImageDescriptor(format).BytesPerPixel;
  373. }
  374. private static int DivRoundUp(int lhs, int rhs)
  375. {
  376. return (lhs + (rhs - 1)) / rhs;
  377. }
  378. public static bool HasColor(GalImageFormat format)
  379. {
  380. return (GetImageDescriptor(format).Target & TargetBuffer.Color) != 0;
  381. }
  382. public static bool HasDepth(GalImageFormat format)
  383. {
  384. return (GetImageDescriptor(format).Target & TargetBuffer.Depth) != 0;
  385. }
  386. public static bool HasStencil(GalImageFormat format)
  387. {
  388. return (GetImageDescriptor(format).Target & TargetBuffer.Stencil) != 0;
  389. }
  390. public static bool IsCompressed(GalImageFormat format)
  391. {
  392. ImageDescriptor desc = GetImageDescriptor(format);
  393. return (desc.BlockWidth | desc.BlockHeight) != 1;
  394. }
  395. private static ImageDescriptor GetImageDescriptor(GalImageFormat format)
  396. {
  397. GalImageFormat pixelFormat = format & GalImageFormat.FormatMask;
  398. if (ImageTable.TryGetValue(pixelFormat, out ImageDescriptor descriptor))
  399. {
  400. return descriptor;
  401. }
  402. throw new NotImplementedException($"Format \"{pixelFormat}\" not implemented!");
  403. }
  404. private static GalImageFormat GetFormatType(GalTextureType type)
  405. {
  406. switch (type)
  407. {
  408. case GalTextureType.Snorm: return Snorm;
  409. case GalTextureType.Unorm: return Unorm;
  410. case GalTextureType.Sint: return Sint;
  411. case GalTextureType.Uint: return Uint;
  412. case GalTextureType.Float: return Float;
  413. default: throw new NotImplementedException(((int)type).ToString());
  414. }
  415. }
  416. public static TextureTarget GetTextureTarget(GalTextureTarget galTextureTarget)
  417. {
  418. switch (galTextureTarget)
  419. {
  420. case GalTextureTarget.OneD:
  421. return TextureTarget.Texture1D;
  422. case GalTextureTarget.TwoD:
  423. case GalTextureTarget.TwoDNoMipMap:
  424. return TextureTarget.Texture2D;
  425. case GalTextureTarget.ThreeD:
  426. return TextureTarget.Texture3D;
  427. case GalTextureTarget.OneDArray:
  428. return TextureTarget.Texture1DArray;
  429. case GalTextureTarget.OneDBuffer:
  430. return TextureTarget.TextureBuffer;
  431. case GalTextureTarget.TwoDArray:
  432. return TextureTarget.Texture2DArray;
  433. case GalTextureTarget.CubeMap:
  434. return TextureTarget.TextureCubeMap;
  435. case GalTextureTarget.CubeArray:
  436. return TextureTarget.TextureCubeMapArray;
  437. default:
  438. throw new NotSupportedException($"Texture target {galTextureTarget} currently not supported!");
  439. }
  440. }
  441. public static bool IsArray(GalTextureTarget textureTarget)
  442. {
  443. switch (textureTarget)
  444. {
  445. case GalTextureTarget.OneDArray:
  446. case GalTextureTarget.TwoDArray:
  447. case GalTextureTarget.CubeArray:
  448. return true;
  449. default:
  450. return false;
  451. }
  452. }
  453. public static int GetCoordsCountTextureTarget(GalTextureTarget textureTarget)
  454. {
  455. switch (textureTarget)
  456. {
  457. case GalTextureTarget.OneD:
  458. return 1;
  459. case GalTextureTarget.OneDArray:
  460. case GalTextureTarget.OneDBuffer:
  461. case GalTextureTarget.TwoD:
  462. case GalTextureTarget.TwoDNoMipMap:
  463. return 2;
  464. case GalTextureTarget.ThreeD:
  465. case GalTextureTarget.TwoDArray:
  466. case GalTextureTarget.CubeMap:
  467. return 3;
  468. case GalTextureTarget.CubeArray:
  469. return 4;
  470. default:
  471. throw new NotImplementedException($"TextureTarget.{textureTarget} not implemented yet.");
  472. }
  473. }
  474. }
  475. }