BC7Decoder.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using Ryujinx.Graphics.Texture.Utils;
  2. using System.Diagnostics;
  3. using System;
  4. using System.Numerics;
  5. using System.Runtime.InteropServices;
  6. namespace Ryujinx.Graphics.Texture
  7. {
  8. static class BC7Decoder
  9. {
  10. public static void Decode(Span<byte> output, ReadOnlySpan<byte> data, int width, int height)
  11. {
  12. ReadOnlySpan<Block> blocks = MemoryMarshal.Cast<byte, Block>(data);
  13. Span<uint> output32 = MemoryMarshal.Cast<byte, uint>(output);
  14. int wInBlocks = (width + 3) / 4;
  15. int hInBlocks = (height + 3) / 4;
  16. for (int y = 0; y < hInBlocks; y++)
  17. {
  18. int y2 = y * 4;
  19. int bh = Math.Min(4, height - y2);
  20. for (int x = 0; x < wInBlocks; x++)
  21. {
  22. int x2 = x * 4;
  23. int bw = Math.Min(4, width - x2);
  24. DecodeBlock(blocks[y * wInBlocks + x], output32.Slice(y2 * width + x2), bw, bh, width);
  25. }
  26. }
  27. }
  28. private static void DecodeBlock(Block block, Span<uint> output, int w, int h, int width)
  29. {
  30. int mode = BitOperations.TrailingZeroCount((byte)block.Low | 0x100);
  31. if (mode == 8)
  32. {
  33. // Mode is invalid, the spec mandates that hardware fills the block with
  34. // a transparent black color.
  35. for (int ty = 0; ty < h; ty++)
  36. {
  37. int baseOffs = ty * width;
  38. for (int tx = 0; tx < w; tx++)
  39. {
  40. int offs = baseOffs + tx;
  41. output[offs] = 0;
  42. }
  43. }
  44. return;
  45. }
  46. BC7ModeInfo modeInfo = BC67Tables.BC7ModeInfos[mode];
  47. int offset = mode + 1;
  48. int partition = (int)block.Decode(ref offset, modeInfo.PartitionBitCount);
  49. int rotation = (int)block.Decode(ref offset, modeInfo.RotationBitCount);
  50. int indexMode = (int)block.Decode(ref offset, modeInfo.IndexModeBitCount);
  51. Debug.Assert(partition < 64);
  52. Debug.Assert(rotation < 4);
  53. Debug.Assert(indexMode < 2);
  54. int endPointCount = modeInfo.SubsetCount * 2;
  55. Span<RgbaColor32> endPoints = stackalloc RgbaColor32[endPointCount];
  56. Span<byte> pValues = stackalloc byte[modeInfo.PBits];
  57. endPoints.Fill(new RgbaColor32(0, 0, 0, 255));
  58. for (int i = 0; i < endPointCount; i++)
  59. {
  60. endPoints[i].R = (int)block.Decode(ref offset, modeInfo.ColorDepth);
  61. }
  62. for (int i = 0; i < endPointCount; i++)
  63. {
  64. endPoints[i].G = (int)block.Decode(ref offset, modeInfo.ColorDepth);
  65. }
  66. for (int i = 0; i < endPointCount; i++)
  67. {
  68. endPoints[i].B = (int)block.Decode(ref offset, modeInfo.ColorDepth);
  69. }
  70. if (modeInfo.AlphaDepth != 0)
  71. {
  72. for (int i = 0; i < endPointCount; i++)
  73. {
  74. endPoints[i].A = (int)block.Decode(ref offset, modeInfo.AlphaDepth);
  75. }
  76. }
  77. for (int i = 0; i < modeInfo.PBits; i++)
  78. {
  79. pValues[i] = (byte)block.Decode(ref offset, 1);
  80. }
  81. for (int i = 0; i < endPointCount; i++)
  82. {
  83. int pBit = -1;
  84. if (modeInfo.PBits != 0)
  85. {
  86. int pIndex = (i * modeInfo.PBits) / endPointCount;
  87. pBit = pValues[pIndex];
  88. }
  89. Unquantize(ref endPoints[i], modeInfo.ColorDepth, modeInfo.AlphaDepth, pBit);
  90. }
  91. byte[] partitionTable = BC67Tables.PartitionTable[modeInfo.SubsetCount - 1][partition];
  92. byte[] fixUpTable = BC67Tables.FixUpIndices[modeInfo.SubsetCount - 1][partition];
  93. Span<byte> colorIndices = stackalloc byte[16];
  94. for (int i = 0; i < 16; i++)
  95. {
  96. byte subset = partitionTable[i];
  97. int bitCount = i == fixUpTable[subset] ? modeInfo.ColorIndexBitCount - 1 : modeInfo.ColorIndexBitCount;
  98. colorIndices[i] = (byte)block.Decode(ref offset, bitCount);
  99. Debug.Assert(colorIndices[i] < 16);
  100. }
  101. Span<byte> alphaIndices = stackalloc byte[16];
  102. if (modeInfo.AlphaIndexBitCount != 0)
  103. {
  104. for (int i = 0; i < 16; i++)
  105. {
  106. int bitCount = i != 0 ? modeInfo.AlphaIndexBitCount : modeInfo.AlphaIndexBitCount - 1;
  107. alphaIndices[i] = (byte)block.Decode(ref offset, bitCount);
  108. Debug.Assert(alphaIndices[i] < 16);
  109. }
  110. }
  111. for (int ty = 0; ty < h; ty++)
  112. {
  113. int baseOffs = ty * width;
  114. for (int tx = 0; tx < w; tx++)
  115. {
  116. int i = ty * 4 + tx;
  117. RgbaColor32 color;
  118. byte subset = partitionTable[i];
  119. RgbaColor32 color1 = endPoints[subset * 2];
  120. RgbaColor32 color2 = endPoints[subset * 2 + 1];
  121. if (modeInfo.AlphaIndexBitCount != 0)
  122. {
  123. if (indexMode == 0)
  124. {
  125. color = BC67Utils.Interpolate(color1, color2, colorIndices[i], alphaIndices[i], modeInfo.ColorIndexBitCount, modeInfo.AlphaIndexBitCount);
  126. }
  127. else
  128. {
  129. color = BC67Utils.Interpolate(color1, color2, alphaIndices[i], colorIndices[i], modeInfo.AlphaIndexBitCount, modeInfo.ColorIndexBitCount);
  130. }
  131. }
  132. else
  133. {
  134. color = BC67Utils.Interpolate(color1, color2, colorIndices[i], colorIndices[i], modeInfo.ColorIndexBitCount, modeInfo.ColorIndexBitCount);
  135. }
  136. if (rotation != 0)
  137. {
  138. int a = color.A;
  139. switch (rotation)
  140. {
  141. case 1: color.A = color.R; color.R = a; break;
  142. case 2: color.A = color.G; color.G = a; break;
  143. case 3: color.A = color.B; color.B = a; break;
  144. }
  145. }
  146. RgbaColor8 color8 = color.GetColor8();
  147. output[baseOffs + tx] = color8.ToUInt32();
  148. }
  149. }
  150. }
  151. private static void Unquantize(ref RgbaColor32 color, int colorDepth, int alphaDepth, int pBit)
  152. {
  153. color.R = UnquantizeComponent(color.R, colorDepth, pBit);
  154. color.G = UnquantizeComponent(color.G, colorDepth, pBit);
  155. color.B = UnquantizeComponent(color.B, colorDepth, pBit);
  156. color.A = alphaDepth != 0 ? UnquantizeComponent(color.A, alphaDepth, pBit) : 255;
  157. }
  158. private static int UnquantizeComponent(int component, int bits, int pBit)
  159. {
  160. int shift = 8 - bits;
  161. int value = component << shift;
  162. if (pBit >= 0)
  163. {
  164. Debug.Assert(pBit <= 1);
  165. value |= value >> (bits + 1);
  166. value |= pBit << (shift - 1);
  167. }
  168. else
  169. {
  170. value |= value >> bits;
  171. }
  172. return value;
  173. }
  174. }
  175. }