SizeCalculator.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. using Ryujinx.Common;
  2. using System;
  3. using static Ryujinx.Graphics.Texture.BlockLinearConstants;
  4. namespace Ryujinx.Graphics.Texture
  5. {
  6. public static class SizeCalculator
  7. {
  8. private const int StrideAlignment = 32;
  9. public static SizeInfo GetBlockLinearTextureSize(
  10. int width,
  11. int height,
  12. int depth,
  13. int levels,
  14. int layers,
  15. int blockWidth,
  16. int blockHeight,
  17. int bytesPerPixel,
  18. int gobBlocksInY,
  19. int gobBlocksInZ,
  20. int gobBlocksInTileX)
  21. {
  22. bool is3D = depth > 1;
  23. int layerSize = 0;
  24. int[] allOffsets = new int[levels * layers * depth];
  25. int[] mipOffsets = new int[levels];
  26. int mipGobBlocksInY = gobBlocksInY;
  27. int mipGobBlocksInZ = gobBlocksInZ;
  28. int gobWidth = (GobStride / bytesPerPixel) * gobBlocksInTileX;
  29. int gobHeight = gobBlocksInY * GobHeight;
  30. for (int level = 0; level < levels; level++)
  31. {
  32. int w = Math.Max(1, width >> level);
  33. int h = Math.Max(1, height >> level);
  34. int d = Math.Max(1, depth >> level);
  35. w = BitUtils.DivRoundUp(w, blockWidth);
  36. h = BitUtils.DivRoundUp(h, blockHeight);
  37. while (h <= (mipGobBlocksInY >> 1) * GobHeight && mipGobBlocksInY != 1)
  38. {
  39. mipGobBlocksInY >>= 1;
  40. }
  41. while (d <= (mipGobBlocksInZ >> 1) && mipGobBlocksInZ != 1)
  42. {
  43. mipGobBlocksInZ >>= 1;
  44. }
  45. int widthInGobs = BitUtils.DivRoundUp(w * bytesPerPixel, GobStride);
  46. int alignment = gobBlocksInTileX;
  47. if (d < gobBlocksInZ || w <= gobWidth || h <= gobHeight)
  48. {
  49. alignment = 1;
  50. }
  51. widthInGobs = BitUtils.AlignUp(widthInGobs, alignment);
  52. int totalBlocksOfGobsInZ = BitUtils.DivRoundUp(d, mipGobBlocksInZ);
  53. int totalBlocksOfGobsInY = BitUtils.DivRoundUp(BitUtils.DivRoundUp(h, GobHeight), mipGobBlocksInY);
  54. int robSize = widthInGobs * mipGobBlocksInY * mipGobBlocksInZ * GobSize;
  55. if (is3D)
  56. {
  57. int gobSize = mipGobBlocksInY * GobSize;
  58. int sliceSize = totalBlocksOfGobsInY * widthInGobs * gobSize;
  59. int baseOffset = layerSize;
  60. int mask = gobBlocksInZ - 1;
  61. for (int z = 0; z < d; z++)
  62. {
  63. int zLow = z & mask;
  64. int zHigh = z & ~mask;
  65. allOffsets[z * levels + level] = baseOffset + zLow * gobSize + zHigh * sliceSize;
  66. }
  67. }
  68. mipOffsets[level] = layerSize;
  69. layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize;
  70. }
  71. layerSize = AlignLayerSize(
  72. layerSize,
  73. height,
  74. depth,
  75. blockHeight,
  76. gobBlocksInY,
  77. gobBlocksInZ,
  78. gobBlocksInTileX);
  79. if (!is3D)
  80. {
  81. for (int layer = 0; layer < layers; layer++)
  82. {
  83. int baseIndex = layer * levels;
  84. int baseOffset = layer * layerSize;
  85. for (int level = 0; level < levels; level++)
  86. {
  87. allOffsets[baseIndex + level] = baseOffset + mipOffsets[level];
  88. }
  89. }
  90. }
  91. int totalSize = layerSize * layers;
  92. return new SizeInfo(mipOffsets, allOffsets, levels, layerSize, totalSize);
  93. }
  94. public static SizeInfo GetLinearTextureSize(int stride, int height, int blockHeight)
  95. {
  96. // Non-2D or mipmapped linear textures are not supported by the Switch GPU,
  97. // so we only need to handle a single case (2D textures without mipmaps).
  98. int totalSize = stride * BitUtils.DivRoundUp(height, blockHeight);
  99. return new SizeInfo(new int[] { 0 }, new int[] { 0 }, 1, totalSize, totalSize);
  100. }
  101. private static int AlignLayerSize(
  102. int size,
  103. int height,
  104. int depth,
  105. int blockHeight,
  106. int gobBlocksInY,
  107. int gobBlocksInZ,
  108. int gobBlocksInTileX)
  109. {
  110. if (gobBlocksInTileX < 2)
  111. {
  112. height = BitUtils.DivRoundUp(height, blockHeight);
  113. while (height <= (gobBlocksInY >> 1) * GobHeight && gobBlocksInY != 1)
  114. {
  115. gobBlocksInY >>= 1;
  116. }
  117. while (depth <= (gobBlocksInZ >> 1) && gobBlocksInZ != 1)
  118. {
  119. gobBlocksInZ >>= 1;
  120. }
  121. int blockOfGobsSize = gobBlocksInY * gobBlocksInZ * GobSize;
  122. int sizeInBlockOfGobs = size / blockOfGobsSize;
  123. if (size != sizeInBlockOfGobs * blockOfGobsSize)
  124. {
  125. size = (sizeInBlockOfGobs + 1) * blockOfGobsSize;
  126. }
  127. }
  128. else
  129. {
  130. int alignment = (gobBlocksInTileX * GobSize) * gobBlocksInY * gobBlocksInZ;
  131. size = BitUtils.AlignUp(size, alignment);
  132. }
  133. return size;
  134. }
  135. public static Size GetBlockLinearAlignedSize(
  136. int width,
  137. int height,
  138. int depth,
  139. int blockWidth,
  140. int blockHeight,
  141. int bytesPerPixel,
  142. int gobBlocksInY,
  143. int gobBlocksInZ,
  144. int gobBlocksInTileX)
  145. {
  146. width = BitUtils.DivRoundUp(width, blockWidth);
  147. height = BitUtils.DivRoundUp(height, blockHeight);
  148. int gobWidth = (GobStride / bytesPerPixel) * gobBlocksInTileX;
  149. int gobHeight = gobBlocksInY * GobHeight;
  150. int alignment = gobWidth;
  151. if (depth < gobBlocksInZ || width <= gobWidth || height <= gobHeight)
  152. {
  153. alignment = GobStride / bytesPerPixel;
  154. }
  155. (gobBlocksInY, gobBlocksInZ) = GetMipGobBlockSizes(height, depth, blockHeight, gobBlocksInY, gobBlocksInZ);
  156. int blockOfGobsHeight = gobBlocksInY * GobHeight;
  157. int blockOfGobsDepth = gobBlocksInZ;
  158. width = BitUtils.AlignUp(width, alignment);
  159. height = BitUtils.AlignUp(height, blockOfGobsHeight);
  160. depth = BitUtils.AlignUp(depth, blockOfGobsDepth);
  161. return new Size(width, height, depth);
  162. }
  163. public static Size GetLinearAlignedSize(
  164. int width,
  165. int height,
  166. int blockWidth,
  167. int blockHeight,
  168. int bytesPerPixel)
  169. {
  170. width = BitUtils.DivRoundUp(width, blockWidth);
  171. height = BitUtils.DivRoundUp(height, blockHeight);
  172. int widthAlignment = StrideAlignment / bytesPerPixel;
  173. width = BitUtils.AlignUp(width, widthAlignment);
  174. return new Size(width, height, 1);
  175. }
  176. public static (int, int) GetMipGobBlockSizes(
  177. int height,
  178. int depth,
  179. int blockHeight,
  180. int gobBlocksInY,
  181. int gobBlocksInZ)
  182. {
  183. height = BitUtils.DivRoundUp(height, blockHeight);
  184. while (height <= (gobBlocksInY >> 1) * GobHeight && gobBlocksInY != 1)
  185. {
  186. gobBlocksInY >>= 1;
  187. }
  188. while (depth <= (gobBlocksInZ >> 1) && gobBlocksInZ != 1)
  189. {
  190. gobBlocksInZ >>= 1;
  191. }
  192. return (gobBlocksInY, gobBlocksInZ);
  193. }
  194. }
  195. }