BlockLinearLayout.cs 6.0 KB

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