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 }