BlockLinearLayout.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using Ryujinx.Common;
  2. using System.Runtime.CompilerServices;
  3. using static Ryujinx.Graphics.Texture.BlockLinearConstants;
  4. namespace Ryujinx.Graphics.Texture
  5. {
  6. class BlockLinearLayout
  7. {
  8. private struct RobAndSliceSizes
  9. {
  10. public int RobSize;
  11. public int SliceSize;
  12. public RobAndSliceSizes(int robSize, int sliceSize)
  13. {
  14. RobSize = robSize;
  15. SliceSize = sliceSize;
  16. }
  17. }
  18. private int _texBpp;
  19. private int _bhMask;
  20. private int _bdMask;
  21. private int _bhShift;
  22. private int _bdShift;
  23. private int _bppShift;
  24. private int _xShift;
  25. private int _robSize;
  26. private int _sliceSize;
  27. // Variables for built in iteration.
  28. private int _yPart;
  29. private int _yzPart;
  30. private int _zPart;
  31. public BlockLinearLayout(
  32. int width,
  33. int height,
  34. int depth,
  35. int gobBlocksInY,
  36. int gobBlocksInZ,
  37. int bpp)
  38. {
  39. _texBpp = bpp;
  40. _bppShift = BitUtils.CountTrailingZeros32(bpp);
  41. _bhMask = gobBlocksInY - 1;
  42. _bdMask = gobBlocksInZ - 1;
  43. _bhShift = BitUtils.CountTrailingZeros32(gobBlocksInY);
  44. _bdShift = BitUtils.CountTrailingZeros32(gobBlocksInZ);
  45. _xShift = BitUtils.CountTrailingZeros32(GobSize * gobBlocksInY * gobBlocksInZ);
  46. RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gobBlocksInY, gobBlocksInZ);
  47. _robSize = rsSizes.RobSize;
  48. _sliceSize = rsSizes.SliceSize;
  49. }
  50. private RobAndSliceSizes GetRobAndSliceSizes(int width, int height, int gobBlocksInY, int gobBlocksInZ)
  51. {
  52. int widthInGobs = BitUtils.DivRoundUp(width * _texBpp, GobStride);
  53. int robSize = GobSize * gobBlocksInY * gobBlocksInZ * widthInGobs;
  54. int sliceSize = BitUtils.DivRoundUp(height, gobBlocksInY * GobHeight) * robSize;
  55. return new RobAndSliceSizes(robSize, sliceSize);
  56. }
  57. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  58. public int GetOffset(int x, int y, int z)
  59. {
  60. return GetOffsetWithLineOffset(x << _bppShift, y, z);
  61. }
  62. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  63. public int GetOffsetWithLineOffset(int x, int y, int z)
  64. {
  65. int yh = y / GobHeight;
  66. int offset = (z >> _bdShift) * _sliceSize + (yh >> _bhShift) * _robSize;
  67. offset += (x / GobStride) << _xShift;
  68. offset += (yh & _bhMask) * GobSize;
  69. offset += ((z & _bdMask) * GobSize) << _bhShift;
  70. offset += ((x & 0x3f) >> 5) << 8;
  71. offset += ((y & 0x07) >> 1) << 6;
  72. offset += ((x & 0x1f) >> 4) << 5;
  73. offset += ((y & 0x01) >> 0) << 4;
  74. offset += ((x & 0x0f) >> 0) << 0;
  75. return offset;
  76. }
  77. public (int offset, int size) GetRectangleRange(int x, int y, int width, int height)
  78. {
  79. // Justification:
  80. // The 2D offset is a combination of separate x and y parts.
  81. // Both components increase with input and never overlap bits.
  82. // Therefore for each component, the minimum input value is the lowest that component can go.
  83. // Minimum total value is minimum X component + minimum Y component. Similar goes for maximum.
  84. int start = GetOffset(x, y, 0);
  85. int end = GetOffset(x + width - 1, y + height - 1, 0) + _texBpp; // Cover the last pixel.
  86. return (start, end - start);
  87. }
  88. public bool LayoutMatches(BlockLinearLayout other)
  89. {
  90. return _robSize == other._robSize &&
  91. _sliceSize == other._sliceSize &&
  92. _texBpp == other._texBpp &&
  93. _bhMask == other._bhMask &&
  94. _bdMask == other._bdMask;
  95. }
  96. // Functions for built in iteration.
  97. // Components of the offset can be updated separately, and combined to save some time.
  98. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  99. public void SetY(int y)
  100. {
  101. int yh = y / GobHeight;
  102. int offset = (yh >> _bhShift) * _robSize;
  103. offset += (yh & _bhMask) * GobSize;
  104. offset += ((y & 0x07) >> 1) << 6;
  105. offset += ((y & 0x01) >> 0) << 4;
  106. _yPart = offset;
  107. _yzPart = offset + _zPart;
  108. }
  109. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  110. public void SetZ(int z)
  111. {
  112. int offset = (z >> _bdShift) * _sliceSize;
  113. offset += ((z & _bdMask) * GobSize) << _bhShift;
  114. _zPart = offset;
  115. _yzPart = offset + _yPart;
  116. }
  117. /// <summary>
  118. /// Optimized conversion for line offset in bytes to an absolute offset. Input x must be divisible by 16.
  119. /// </summary>
  120. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  121. public int GetOffsetWithLineOffset16(int x)
  122. {
  123. int offset = (x / GobStride) << _xShift;
  124. offset += ((x & 0x3f) >> 5) << 8;
  125. offset += ((x & 0x1f) >> 4) << 5;
  126. return offset + _yzPart;
  127. }
  128. /// <summary>
  129. /// Optimized conversion for line offset in bytes to an absolute offset. Input x must be divisible by 64.
  130. /// </summary>
  131. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  132. public int GetOffsetWithLineOffset64(int x)
  133. {
  134. int offset = (x / GobStride) << _xShift;
  135. return offset + _yzPart;
  136. }
  137. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  138. public int GetOffset(int x)
  139. {
  140. x <<= _bppShift;
  141. int offset = (x / GobStride) << _xShift;
  142. offset += ((x & 0x3f) >> 5) << 8;
  143. offset += ((x & 0x1f) >> 4) << 5;
  144. offset += (x & 0x0f);
  145. return offset + _yzPart;
  146. }
  147. }
  148. }