/ src / Ryujinx.Graphics.Texture / Astc / IntegerEncoded.cs
IntegerEncoded.cs
  1  using System;
  2  using System.Numerics;
  3  
  4  namespace Ryujinx.Graphics.Texture.Astc
  5  {
  6      internal struct IntegerEncoded
  7      {
  8          internal const int StructSize = 8;
  9          private static readonly IntegerEncoded[] _encodings;
 10  
 11          public enum EIntegerEncoding : byte
 12          {
 13              JustBits,
 14              Quint,
 15              Trit,
 16          }
 17  
 18          readonly EIntegerEncoding _encoding;
 19          public byte NumberBits { get; private set; }
 20          public byte TritValue { get; private set; }
 21          public byte QuintValue { get; private set; }
 22          public int BitValue { get; private set; }
 23  
 24          static IntegerEncoded()
 25          {
 26              _encodings = new IntegerEncoded[0x100];
 27  
 28              for (int i = 0; i < _encodings.Length; i++)
 29              {
 30                  _encodings[i] = CreateEncodingCalc(i);
 31              }
 32          }
 33  
 34          public IntegerEncoded(EIntegerEncoding encoding, int numBits)
 35          {
 36              _encoding = encoding;
 37              NumberBits = (byte)numBits;
 38              BitValue = 0;
 39              TritValue = 0;
 40              QuintValue = 0;
 41          }
 42  
 43          public readonly bool MatchesEncoding(IntegerEncoded other)
 44          {
 45              return _encoding == other._encoding && NumberBits == other.NumberBits;
 46          }
 47  
 48          public readonly EIntegerEncoding GetEncoding()
 49          {
 50              return _encoding;
 51          }
 52  
 53          public readonly int GetBitLength(int numberVals)
 54          {
 55              int totalBits = NumberBits * numberVals;
 56              if (_encoding == EIntegerEncoding.Trit)
 57              {
 58                  totalBits += (numberVals * 8 + 4) / 5;
 59              }
 60              else if (_encoding == EIntegerEncoding.Quint)
 61              {
 62                  totalBits += (numberVals * 7 + 2) / 3;
 63              }
 64              return totalBits;
 65          }
 66  
 67          public static IntegerEncoded CreateEncoding(int maxVal)
 68          {
 69              return _encodings[maxVal];
 70          }
 71  
 72          private static IntegerEncoded CreateEncodingCalc(int maxVal)
 73          {
 74              while (maxVal > 0)
 75              {
 76                  int check = maxVal + 1;
 77  
 78                  // Is maxVal a power of two?
 79                  if ((check & (check - 1)) == 0)
 80                  {
 81                      return new IntegerEncoded(EIntegerEncoding.JustBits, BitOperations.PopCount((uint)maxVal));
 82                  }
 83  
 84                  // Is maxVal of the type 3*2^n - 1?
 85                  if ((check % 3 == 0) && ((check / 3) & ((check / 3) - 1)) == 0)
 86                  {
 87                      return new IntegerEncoded(EIntegerEncoding.Trit, BitOperations.PopCount((uint)(check / 3 - 1)));
 88                  }
 89  
 90                  // Is maxVal of the type 5*2^n - 1?
 91                  if ((check % 5 == 0) && ((check / 5) & ((check / 5) - 1)) == 0)
 92                  {
 93                      return new IntegerEncoded(EIntegerEncoding.Quint, BitOperations.PopCount((uint)(check / 5 - 1)));
 94                  }
 95  
 96                  // Apparently it can't be represented with a bounded integer sequence...
 97                  // just iterate.
 98                  maxVal--;
 99              }
100  
101              return new IntegerEncoded(EIntegerEncoding.JustBits, 0);
102          }
103  
104          public static void DecodeTritBlock(
105              ref BitStream128 bitStream,
106              ref IntegerSequence listIntegerEncoded,
107              int numberBitsPerValue)
108          {
109              // Implement the algorithm in section C.2.12
110              Span<int> m = stackalloc int[5];
111  
112              m[0] = bitStream.ReadBits(numberBitsPerValue);
113              int encoded = bitStream.ReadBits(2);
114              m[1] = bitStream.ReadBits(numberBitsPerValue);
115              encoded |= bitStream.ReadBits(2) << 2;
116              m[2] = bitStream.ReadBits(numberBitsPerValue);
117              encoded |= bitStream.ReadBits(1) << 4;
118              m[3] = bitStream.ReadBits(numberBitsPerValue);
119              encoded |= bitStream.ReadBits(2) << 5;
120              m[4] = bitStream.ReadBits(numberBitsPerValue);
121              encoded |= bitStream.ReadBits(1) << 7;
122  
123              ReadOnlySpan<byte> encodings = GetTritEncoding(encoded);
124  
125              IntegerEncoded intEncoded = new(EIntegerEncoding.Trit, numberBitsPerValue);
126  
127              for (int i = 0; i < 5; i++)
128              {
129                  intEncoded.BitValue = m[i];
130                  intEncoded.TritValue = encodings[i];
131  
132                  listIntegerEncoded.Add(ref intEncoded);
133              }
134          }
135  
136          public static void DecodeQuintBlock(
137              ref BitStream128 bitStream,
138              ref IntegerSequence listIntegerEncoded,
139              int numberBitsPerValue)
140          {
141              ReadOnlySpan<byte> interleavedBits = new byte[] { 3, 2, 2 };
142  
143              // Implement the algorithm in section C.2.12
144              Span<int> m = stackalloc int[3];
145              ulong encoded = 0;
146              int encodedBitsRead = 0;
147  
148              for (int i = 0; i < m.Length; i++)
149              {
150                  m[i] = bitStream.ReadBits(numberBitsPerValue);
151  
152                  uint encodedBits = (uint)bitStream.ReadBits(interleavedBits[i]);
153  
154                  encoded |= encodedBits << encodedBitsRead;
155                  encodedBitsRead += interleavedBits[i];
156              }
157  
158              ReadOnlySpan<byte> encodings = GetQuintEncoding((int)encoded);
159  
160              for (int i = 0; i < 3; i++)
161              {
162                  IntegerEncoded intEncoded = new(EIntegerEncoding.Quint, numberBitsPerValue)
163                  {
164                      BitValue = m[i],
165                      QuintValue = encodings[i],
166                  };
167  
168                  listIntegerEncoded.Add(ref intEncoded);
169              }
170          }
171  
172          public static void DecodeIntegerSequence(
173              ref IntegerSequence decodeIntegerSequence,
174              ref BitStream128 bitStream,
175              int maxRange,
176              int numberValues)
177          {
178              // Determine encoding parameters
179              IntegerEncoded intEncoded = CreateEncoding(maxRange);
180  
181              // Start decoding
182              int numberValuesDecoded = 0;
183              while (numberValuesDecoded < numberValues)
184              {
185                  switch (intEncoded.GetEncoding())
186                  {
187                      case EIntegerEncoding.Quint:
188                          {
189                              DecodeQuintBlock(ref bitStream, ref decodeIntegerSequence, intEncoded.NumberBits);
190                              numberValuesDecoded += 3;
191  
192                              break;
193                          }
194  
195                      case EIntegerEncoding.Trit:
196                          {
197                              DecodeTritBlock(ref bitStream, ref decodeIntegerSequence, intEncoded.NumberBits);
198                              numberValuesDecoded += 5;
199  
200                              break;
201                          }
202  
203                      case EIntegerEncoding.JustBits:
204                          {
205                              intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits);
206                              decodeIntegerSequence.Add(ref intEncoded);
207                              numberValuesDecoded++;
208  
209                              break;
210                          }
211                  }
212              }
213          }
214  
215          private static ReadOnlySpan<byte> GetTritEncoding(int index)
216          {
217              return TritEncodings.Slice(index * 5, 5);
218          }
219  
220          private static ReadOnlySpan<byte> GetQuintEncoding(int index)
221          {
222              return QuintEncodings.Slice(index * 3, 3);
223          }
224  
225          private static ReadOnlySpan<byte> TritEncodings => new byte[]
226          {
227              0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
228              0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0,
229              2, 1, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0,
230              1, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 2, 0, 0,
231              0, 2, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0, 0,
232              2, 0, 2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
233              2, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 1, 1, 0, 0,
234              1, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1, 1, 2, 0, 0,
235              0, 2, 1, 0, 0, 1, 2, 1, 0, 0, 2, 2, 1, 0, 0,
236              2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 1, 0, 0, 2, 2,
237              2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 1, 0,
238              1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 0, 2, 1, 0,
239              0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 2, 1, 0, 1, 0,
240              1, 0, 2, 1, 0, 0, 2, 0, 1, 0, 1, 2, 0, 1, 0,
241              2, 2, 0, 1, 0, 2, 0, 2, 1, 0, 0, 2, 2, 1, 0,
242              1, 2, 2, 1, 0, 2, 2, 2, 1, 0, 2, 0, 2, 1, 0,
243              0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 2, 0, 1, 1, 0,
244              0, 1, 2, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0,
245              2, 1, 1, 1, 0, 1, 1, 2, 1, 0, 0, 2, 1, 1, 0,
246              1, 2, 1, 1, 0, 2, 2, 1, 1, 0, 2, 1, 2, 1, 0,
247              0, 1, 0, 2, 2, 1, 1, 0, 2, 2, 2, 1, 0, 2, 2,
248              1, 0, 2, 2, 2, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0,
249              2, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 1, 0, 2, 0,
250              1, 1, 0, 2, 0, 2, 1, 0, 2, 0, 1, 0, 2, 2, 0,
251              0, 2, 0, 2, 0, 1, 2, 0, 2, 0, 2, 2, 0, 2, 0,
252              2, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 2, 2, 0,
253              2, 2, 2, 2, 0, 2, 0, 2, 2, 0, 0, 0, 1, 2, 0,
254              1, 0, 1, 2, 0, 2, 0, 1, 2, 0, 0, 1, 2, 2, 0,
255              0, 1, 1, 2, 0, 1, 1, 1, 2, 0, 2, 1, 1, 2, 0,
256              1, 1, 2, 2, 0, 0, 2, 1, 2, 0, 1, 2, 1, 2, 0,
257              2, 2, 1, 2, 0, 2, 1, 2, 2, 0, 0, 2, 0, 2, 2,
258              1, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2,
259              0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2,
260              0, 0, 2, 0, 2, 0, 1, 0, 0, 2, 1, 1, 0, 0, 2,
261              2, 1, 0, 0, 2, 1, 0, 2, 0, 2, 0, 2, 0, 0, 2,
262              1, 2, 0, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 0, 2,
263              0, 2, 2, 0, 2, 1, 2, 2, 0, 2, 2, 2, 2, 0, 2,
264              2, 0, 2, 0, 2, 0, 0, 1, 0, 2, 1, 0, 1, 0, 2,
265              2, 0, 1, 0, 2, 0, 1, 2, 0, 2, 0, 1, 1, 0, 2,
266              1, 1, 1, 0, 2, 2, 1, 1, 0, 2, 1, 1, 2, 0, 2,
267              0, 2, 1, 0, 2, 1, 2, 1, 0, 2, 2, 2, 1, 0, 2,
268              2, 1, 2, 0, 2, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2,
269              2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1,
270              1, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 2, 0, 1,
271              0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1,
272              1, 0, 2, 0, 1, 0, 2, 0, 0, 1, 1, 2, 0, 0, 1,
273              2, 2, 0, 0, 1, 2, 0, 2, 0, 1, 0, 2, 2, 0, 1,
274              1, 2, 2, 0, 1, 2, 2, 2, 0, 1, 2, 0, 2, 0, 1,
275              0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 2, 0, 1, 0, 1,
276              0, 1, 2, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1,
277              2, 1, 1, 0, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1,
278              1, 2, 1, 0, 1, 2, 2, 1, 0, 1, 2, 1, 2, 0, 1,
279              0, 0, 1, 2, 2, 1, 0, 1, 2, 2, 2, 0, 1, 2, 2,
280              0, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
281              2, 0, 0, 1, 1, 0, 0, 2, 1, 1, 0, 1, 0, 1, 1,
282              1, 1, 0, 1, 1, 2, 1, 0, 1, 1, 1, 0, 2, 1, 1,
283              0, 2, 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 1,
284              2, 0, 2, 1, 1, 0, 2, 2, 1, 1, 1, 2, 2, 1, 1,
285              2, 2, 2, 1, 1, 2, 0, 2, 1, 1, 0, 0, 1, 1, 1,
286              1, 0, 1, 1, 1, 2, 0, 1, 1, 1, 0, 1, 2, 1, 1,
287              0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
288              1, 1, 2, 1, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 1,
289              2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 0, 1, 1, 2, 2,
290              1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2,
291              0, 0, 0, 2, 1, 1, 0, 0, 2, 1, 2, 0, 0, 2, 1,
292              0, 0, 2, 2, 1, 0, 1, 0, 2, 1, 1, 1, 0, 2, 1,
293              2, 1, 0, 2, 1, 1, 0, 2, 2, 1, 0, 2, 0, 2, 1,
294              1, 2, 0, 2, 1, 2, 2, 0, 2, 1, 2, 0, 2, 2, 1,
295              0, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1,
296              2, 0, 2, 2, 1, 0, 0, 1, 2, 1, 1, 0, 1, 2, 1,
297              2, 0, 1, 2, 1, 0, 1, 2, 2, 1, 0, 1, 1, 2, 1,
298              1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1,
299              0, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1,
300              2, 1, 2, 2, 1, 0, 2, 1, 2, 2, 1, 2, 1, 2, 2,
301              2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 1, 2,
302              1, 0, 0, 1, 2, 2, 0, 0, 1, 2, 0, 0, 2, 1, 2,
303              0, 1, 0, 1, 2, 1, 1, 0, 1, 2, 2, 1, 0, 1, 2,
304              1, 0, 2, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 2,
305              2, 2, 0, 1, 2, 2, 0, 2, 1, 2, 0, 2, 2, 1, 2,
306              1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 0, 2, 1, 2,
307              0, 0, 1, 1, 2, 1, 0, 1, 1, 2, 2, 0, 1, 1, 2,
308              0, 1, 2, 1, 2, 0, 1, 1, 1, 2, 1, 1, 1, 1, 2,
309              2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 0, 2, 1, 1, 2,
310              1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2,
311              0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
312              2, 1, 2, 2, 2,
313          };
314  
315          private static ReadOnlySpan<byte> QuintEncodings => new byte[]
316          {
317              0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0,
318              0, 4, 0, 4, 4, 0, 4, 4, 4, 0, 1, 0, 1, 1, 0,
319              2, 1, 0, 3, 1, 0, 4, 1, 0, 1, 4, 0, 4, 4, 1,
320              4, 4, 4, 0, 2, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0,
321              4, 2, 0, 2, 4, 0, 4, 4, 2, 4, 4, 4, 0, 3, 0,
322              1, 3, 0, 2, 3, 0, 3, 3, 0, 4, 3, 0, 3, 4, 0,
323              4, 4, 3, 4, 4, 4, 0, 0, 1, 1, 0, 1, 2, 0, 1,
324              3, 0, 1, 4, 0, 1, 0, 4, 1, 4, 0, 4, 0, 4, 4,
325              0, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1,
326              1, 4, 1, 4, 1, 4, 1, 4, 4, 0, 2, 1, 1, 2, 1,
327              2, 2, 1, 3, 2, 1, 4, 2, 1, 2, 4, 1, 4, 2, 4,
328              2, 4, 4, 0, 3, 1, 1, 3, 1, 2, 3, 1, 3, 3, 1,
329              4, 3, 1, 3, 4, 1, 4, 3, 4, 3, 4, 4, 0, 0, 2,
330              1, 0, 2, 2, 0, 2, 3, 0, 2, 4, 0, 2, 0, 4, 2,
331              2, 0, 4, 3, 0, 4, 0, 1, 2, 1, 1, 2, 2, 1, 2,
332              3, 1, 2, 4, 1, 2, 1, 4, 2, 2, 1, 4, 3, 1, 4,
333              0, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 2, 4, 2, 2,
334              2, 4, 2, 2, 2, 4, 3, 2, 4, 0, 3, 2, 1, 3, 2,
335              2, 3, 2, 3, 3, 2, 4, 3, 2, 3, 4, 2, 2, 3, 4,
336              3, 3, 4, 0, 0, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3,
337              4, 0, 3, 0, 4, 3, 0, 0, 4, 1, 0, 4, 0, 1, 3,
338              1, 1, 3, 2, 1, 3, 3, 1, 3, 4, 1, 3, 1, 4, 3,
339              0, 1, 4, 1, 1, 4, 0, 2, 3, 1, 2, 3, 2, 2, 3,
340              3, 2, 3, 4, 2, 3, 2, 4, 3, 0, 2, 4, 1, 2, 4,
341              0, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3,
342              3, 4, 3, 0, 3, 4, 1, 3, 4,
343          };
344      }
345  }