BlockLinearSwizzle.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using Ryujinx.Common;
  2. using System;
  3. namespace Ryujinx.Graphics.Texture
  4. {
  5. class BlockLinearSwizzle : ISwizzle
  6. {
  7. private const int GobWidth = 64;
  8. private const int GobHeight = 8;
  9. private const int GobSize = GobWidth * GobHeight;
  10. private int _texWidth;
  11. private int _texHeight;
  12. private int _texDepth;
  13. private int _texGobBlockHeight;
  14. private int _texGobBlockDepth;
  15. private int _texBpp;
  16. private int _bhMask;
  17. private int _bdMask;
  18. private int _bhShift;
  19. private int _bdShift;
  20. private int _bppShift;
  21. private int _xShift;
  22. private int _robSize;
  23. private int _sliceSize;
  24. private int _baseOffset;
  25. public BlockLinearSwizzle(
  26. int width,
  27. int height,
  28. int depth,
  29. int gobBlockHeight,
  30. int gobBlockDepth,
  31. int bpp)
  32. {
  33. _texWidth = width;
  34. _texHeight = height;
  35. _texDepth = depth;
  36. _texGobBlockHeight = gobBlockHeight;
  37. _texGobBlockDepth = gobBlockDepth;
  38. _texBpp = bpp;
  39. _bppShift = BitUtils.CountTrailingZeros32(bpp);
  40. SetMipLevel(0);
  41. }
  42. public void SetMipLevel(int level)
  43. {
  44. _baseOffset = GetMipOffset(level);
  45. int width = Math.Max(1, _texWidth >> level);
  46. int height = Math.Max(1, _texHeight >> level);
  47. int depth = Math.Max(1, _texDepth >> level);
  48. GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth);
  49. _bhMask = gbSizes.Height - 1;
  50. _bdMask = gbSizes.Depth - 1;
  51. _bhShift = BitUtils.CountTrailingZeros32(gbSizes.Height);
  52. _bdShift = BitUtils.CountTrailingZeros32(gbSizes.Depth);
  53. _xShift = BitUtils.CountTrailingZeros32(GobSize * gbSizes.Height * gbSizes.Depth);
  54. RobAndSliceSizes gsSizes = GetRobAndSliceSizes(width, height, gbSizes);
  55. _robSize = gsSizes.RobSize;
  56. _sliceSize = gsSizes.SliceSize;
  57. }
  58. public int GetImageSize(int mipsCount)
  59. {
  60. int size = GetMipOffset(mipsCount);
  61. size = (size + 0x1fff) & ~0x1fff;
  62. return size;
  63. }
  64. public int GetMipOffset(int level)
  65. {
  66. int totalSize = 0;
  67. for (int index = 0; index < level; index++)
  68. {
  69. int width = Math.Max(1, _texWidth >> index);
  70. int height = Math.Max(1, _texHeight >> index);
  71. int depth = Math.Max(1, _texDepth >> index);
  72. GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth);
  73. RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gbSizes);
  74. totalSize += BitUtils.DivRoundUp(depth, gbSizes.Depth) * rsSizes.SliceSize;
  75. }
  76. return totalSize;
  77. }
  78. private struct GobBlockSizes
  79. {
  80. public int Height;
  81. public int Depth;
  82. public GobBlockSizes(int gobBlockHeight, int gobBlockDepth)
  83. {
  84. Height = gobBlockHeight;
  85. Depth = gobBlockDepth;
  86. }
  87. }
  88. private GobBlockSizes AdjustGobBlockSizes(int height, int depth)
  89. {
  90. int gobBlockHeight = _texGobBlockHeight;
  91. int gobBlockDepth = _texGobBlockDepth;
  92. int pow2Height = BitUtils.Pow2RoundUp(height);
  93. int pow2Depth = BitUtils.Pow2RoundUp(depth);
  94. while (gobBlockHeight * GobHeight > pow2Height && gobBlockHeight > 1)
  95. {
  96. gobBlockHeight >>= 1;
  97. }
  98. while (gobBlockDepth > pow2Depth && gobBlockDepth > 1)
  99. {
  100. gobBlockDepth >>= 1;
  101. }
  102. return new GobBlockSizes(gobBlockHeight, gobBlockDepth);
  103. }
  104. private struct RobAndSliceSizes
  105. {
  106. public int RobSize;
  107. public int SliceSize;
  108. public RobAndSliceSizes(int robSize, int sliceSize)
  109. {
  110. RobSize = robSize;
  111. SliceSize = sliceSize;
  112. }
  113. }
  114. private RobAndSliceSizes GetRobAndSliceSizes(int width, int height, GobBlockSizes gbSizes)
  115. {
  116. int widthInGobs = BitUtils.DivRoundUp(width * _texBpp, GobWidth);
  117. int robSize = GobSize * gbSizes.Height * gbSizes.Depth * widthInGobs;
  118. int sliceSize = BitUtils.DivRoundUp(height, gbSizes.Height * GobHeight) * robSize;
  119. return new RobAndSliceSizes(robSize, sliceSize);
  120. }
  121. public int GetSwizzleOffset(int x, int y, int z)
  122. {
  123. x <<= _bppShift;
  124. int yh = y / GobHeight;
  125. int position = (z >> _bdShift) * _sliceSize + (yh >> _bhShift) * _robSize;
  126. position += (x / GobWidth) << _xShift;
  127. position += (yh & _bhMask) * GobSize;
  128. position += ((z & _bdMask) * GobSize) << _bhShift;
  129. position += ((x & 0x3f) >> 5) << 8;
  130. position += ((y & 0x07) >> 1) << 6;
  131. position += ((x & 0x1f) >> 4) << 5;
  132. position += ((y & 0x01) >> 0) << 4;
  133. position += ((x & 0x0f) >> 0) << 0;
  134. return _baseOffset + position;
  135. }
  136. }
  137. }