mirror of
				https://github.com/Ryujinx/Ryujinx.git
				synced 2025-10-25 21:13:55 -07:00 
			
		
		
		
	* ASTC optimizations * Move code to Ryujinx.Common * Support 3D textures * Address feedback * Remove ASTC logging * Use stackalloc instead of a Buffer20 struct * Code style and cleanup * Respond to feedback * Rearrange public/private property ordering
		
			
				
	
	
		
			346 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Numerics;
 | |
| 
 | |
| namespace Ryujinx.Graphics.Texture.Astc
 | |
| {
 | |
|     internal struct IntegerEncoded
 | |
|     {
 | |
|         internal const int StructSize = 8;
 | |
|         private static readonly IntegerEncoded[] Encodings;
 | |
| 
 | |
|         public enum EIntegerEncoding : byte
 | |
|         {
 | |
|             JustBits,
 | |
|             Quint,
 | |
|             Trit
 | |
|         }
 | |
| 
 | |
|         EIntegerEncoding _encoding;
 | |
|         public byte NumberBits { get; private set; }
 | |
|         public byte TritValue { get; private set; }
 | |
|         public byte QuintValue { get; private set; }
 | |
|         public int BitValue { get; private set; }
 | |
| 
 | |
|         static IntegerEncoded()
 | |
|         {
 | |
|             Encodings = new IntegerEncoded[0x100];
 | |
| 
 | |
|             for (int i = 0; i < Encodings.Length; i++)
 | |
|             {
 | |
|                 Encodings[i] = CreateEncodingCalc(i);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public IntegerEncoded(EIntegerEncoding encoding, int numBits)
 | |
|         {
 | |
|             _encoding = encoding;
 | |
|             NumberBits = (byte)numBits;
 | |
|             BitValue = 0;
 | |
|             TritValue = 0;
 | |
|             QuintValue = 0;
 | |
|         }
 | |
| 
 | |
|         public bool MatchesEncoding(IntegerEncoded other)
 | |
|         {
 | |
|             return _encoding == other._encoding && NumberBits == other.NumberBits;
 | |
|         }
 | |
| 
 | |
|         public EIntegerEncoding GetEncoding()
 | |
|         {
 | |
|             return _encoding;
 | |
|         }
 | |
| 
 | |
|         public int GetBitLength(int numberVals)
 | |
|         {
 | |
|             int totalBits = NumberBits * numberVals;
 | |
|             if (_encoding == EIntegerEncoding.Trit)
 | |
|             {
 | |
|                 totalBits += (numberVals * 8 + 4) / 5;
 | |
|             }
 | |
|             else if (_encoding == EIntegerEncoding.Quint)
 | |
|             {
 | |
|                 totalBits += (numberVals * 7 + 2) / 3;
 | |
|             }
 | |
|             return totalBits;
 | |
|         }
 | |
| 
 | |
|         public static IntegerEncoded CreateEncoding(int maxVal)
 | |
|         {
 | |
|             return Encodings[maxVal];
 | |
|         }
 | |
| 
 | |
|         private static IntegerEncoded CreateEncodingCalc(int maxVal)
 | |
|         {
 | |
|             while (maxVal > 0)
 | |
|             {
 | |
|                 int check = maxVal + 1;
 | |
| 
 | |
|                 // Is maxVal a power of two?
 | |
|                 if ((check & (check - 1)) == 0)
 | |
|                 {
 | |
|                     return new IntegerEncoded(EIntegerEncoding.JustBits, BitOperations.PopCount((uint)maxVal));
 | |
|                 }
 | |
| 
 | |
|                 // Is maxVal of the type 3*2^n - 1?
 | |
|                 if ((check % 3 == 0) && ((check / 3) & ((check / 3) - 1)) == 0)
 | |
|                 {
 | |
|                     return new IntegerEncoded(EIntegerEncoding.Trit, BitOperations.PopCount((uint)(check / 3 - 1)));
 | |
|                 }
 | |
| 
 | |
|                 // Is maxVal of the type 5*2^n - 1?
 | |
|                 if ((check % 5 == 0) && ((check / 5) & ((check / 5) - 1)) == 0)
 | |
|                 {
 | |
|                     return new IntegerEncoded(EIntegerEncoding.Quint, BitOperations.PopCount((uint)(check / 5 - 1)));
 | |
|                 }
 | |
| 
 | |
|                 // Apparently it can't be represented with a bounded integer sequence...
 | |
|                 // just iterate.
 | |
|                 maxVal--;
 | |
|             }
 | |
| 
 | |
|             return new IntegerEncoded(EIntegerEncoding.JustBits, 0);
 | |
|         }
 | |
| 
 | |
|         public static void DecodeTritBlock(
 | |
|             ref BitStream128 bitStream,
 | |
|             ref IntegerSequence listIntegerEncoded,
 | |
|             int numberBitsPerValue)
 | |
|         {
 | |
|             // Implement the algorithm in section C.2.12
 | |
|             Span<int> m = stackalloc int[5];
 | |
| 
 | |
|             m[0] = bitStream.ReadBits(numberBitsPerValue);
 | |
|             int encoded = bitStream.ReadBits(2);
 | |
|             m[1] = bitStream.ReadBits(numberBitsPerValue);
 | |
|             encoded |= bitStream.ReadBits(2) << 2;
 | |
|             m[2] = bitStream.ReadBits(numberBitsPerValue);
 | |
|             encoded |= bitStream.ReadBits(1) << 4;
 | |
|             m[3] = bitStream.ReadBits(numberBitsPerValue);
 | |
|             encoded |= bitStream.ReadBits(2) << 5;
 | |
|             m[4] = bitStream.ReadBits(numberBitsPerValue);
 | |
|             encoded |= bitStream.ReadBits(1) << 7;
 | |
| 
 | |
|             ReadOnlySpan<byte> encodings = GetTritEncoding(encoded);
 | |
| 
 | |
|             IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue);
 | |
| 
 | |
|             for (int i = 0; i < 5; i++)
 | |
|             {
 | |
|                 intEncoded.BitValue = m[i];
 | |
|                 intEncoded.TritValue = encodings[i];
 | |
| 
 | |
|                 listIntegerEncoded.Add(ref intEncoded);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static void DecodeQuintBlock(
 | |
|             ref BitStream128 bitStream,
 | |
|             ref IntegerSequence listIntegerEncoded,
 | |
|             int numberBitsPerValue)
 | |
|         {
 | |
|             ReadOnlySpan<byte> interleavedBits = new byte[] { 3, 2, 2 };
 | |
| 
 | |
|             // Implement the algorithm in section C.2.12
 | |
|             Span<int> m = stackalloc int[3];
 | |
|             ulong encoded = 0;
 | |
|             int encodedBitsRead = 0;
 | |
| 
 | |
|             for (int i = 0; i < m.Length; i++)
 | |
|             {
 | |
|                 m[i] = bitStream.ReadBits(numberBitsPerValue);
 | |
| 
 | |
|                 uint encodedBits = (uint)bitStream.ReadBits(interleavedBits[i]);
 | |
| 
 | |
|                 encoded |= encodedBits << encodedBitsRead;
 | |
|                 encodedBitsRead += interleavedBits[i];
 | |
|             }
 | |
| 
 | |
|             ReadOnlySpan<byte> encodings = GetQuintEncoding((int)encoded);
 | |
| 
 | |
|             for (int i = 0; i < 3; i++)
 | |
|             {
 | |
|                 IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Quint, numberBitsPerValue)
 | |
|                 {
 | |
|                     BitValue = m[i],
 | |
|                     QuintValue = encodings[i]
 | |
|                 };
 | |
| 
 | |
|                 listIntegerEncoded.Add(ref intEncoded);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static void DecodeIntegerSequence(
 | |
|             ref IntegerSequence decodeIntegerSequence,
 | |
|             ref BitStream128 bitStream,
 | |
|             int maxRange,
 | |
|             int numberValues)
 | |
|         {
 | |
|             // Determine encoding parameters
 | |
|             IntegerEncoded intEncoded = CreateEncoding(maxRange);
 | |
| 
 | |
|             // Start decoding
 | |
|             int numberValuesDecoded = 0;
 | |
|             while (numberValuesDecoded < numberValues)
 | |
|             {
 | |
|                 switch (intEncoded.GetEncoding())
 | |
|                 {
 | |
|                     case EIntegerEncoding.Quint:
 | |
|                     {
 | |
|                         DecodeQuintBlock(ref bitStream, ref decodeIntegerSequence, intEncoded.NumberBits);
 | |
|                         numberValuesDecoded += 3;
 | |
| 
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     case EIntegerEncoding.Trit:
 | |
|                     {
 | |
|                         DecodeTritBlock(ref bitStream, ref decodeIntegerSequence, intEncoded.NumberBits);
 | |
|                         numberValuesDecoded += 5;
 | |
| 
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     case EIntegerEncoding.JustBits:
 | |
|                     {
 | |
|                         intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits);
 | |
|                         decodeIntegerSequence.Add(ref intEncoded);
 | |
|                         numberValuesDecoded++;
 | |
| 
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static ReadOnlySpan<byte> GetTritEncoding(int index)
 | |
|         {
 | |
|             return TritEncodings.Slice(index * 5, 5);
 | |
|         }
 | |
| 
 | |
|         private static ReadOnlySpan<byte> GetQuintEncoding(int index)
 | |
|         {
 | |
|             return QuintEncodings.Slice(index * 3, 3);
 | |
|         }
 | |
| 
 | |
|         private static ReadOnlySpan<byte> TritEncodings => new byte[]
 | |
|         {
 | |
|             0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
 | |
|             0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0,
 | |
|             2, 1, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0,
 | |
|             1, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 2, 0, 0,
 | |
|             0, 2, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0, 0,
 | |
|             2, 0, 2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
 | |
|             2, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 1, 1, 0, 0,
 | |
|             1, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1, 1, 2, 0, 0,
 | |
|             0, 2, 1, 0, 0, 1, 2, 1, 0, 0, 2, 2, 1, 0, 0,
 | |
|             2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 1, 0, 0, 2, 2,
 | |
|             2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 1, 0,
 | |
|             1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 0, 2, 1, 0,
 | |
|             0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 2, 1, 0, 1, 0,
 | |
|             1, 0, 2, 1, 0, 0, 2, 0, 1, 0, 1, 2, 0, 1, 0,
 | |
|             2, 2, 0, 1, 0, 2, 0, 2, 1, 0, 0, 2, 2, 1, 0,
 | |
|             1, 2, 2, 1, 0, 2, 2, 2, 1, 0, 2, 0, 2, 1, 0,
 | |
|             0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 2, 0, 1, 1, 0,
 | |
|             0, 1, 2, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0,
 | |
|             2, 1, 1, 1, 0, 1, 1, 2, 1, 0, 0, 2, 1, 1, 0,
 | |
|             1, 2, 1, 1, 0, 2, 2, 1, 1, 0, 2, 1, 2, 1, 0,
 | |
|             0, 1, 0, 2, 2, 1, 1, 0, 2, 2, 2, 1, 0, 2, 2,
 | |
|             1, 0, 2, 2, 2, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0,
 | |
|             2, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 1, 0, 2, 0,
 | |
|             1, 1, 0, 2, 0, 2, 1, 0, 2, 0, 1, 0, 2, 2, 0,
 | |
|             0, 2, 0, 2, 0, 1, 2, 0, 2, 0, 2, 2, 0, 2, 0,
 | |
|             2, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 2, 2, 0,
 | |
|             2, 2, 2, 2, 0, 2, 0, 2, 2, 0, 0, 0, 1, 2, 0,
 | |
|             1, 0, 1, 2, 0, 2, 0, 1, 2, 0, 0, 1, 2, 2, 0,
 | |
|             0, 1, 1, 2, 0, 1, 1, 1, 2, 0, 2, 1, 1, 2, 0,
 | |
|             1, 1, 2, 2, 0, 0, 2, 1, 2, 0, 1, 2, 1, 2, 0,
 | |
|             2, 2, 1, 2, 0, 2, 1, 2, 2, 0, 0, 2, 0, 2, 2,
 | |
|             1, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2,
 | |
|             0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2,
 | |
|             0, 0, 2, 0, 2, 0, 1, 0, 0, 2, 1, 1, 0, 0, 2,
 | |
|             2, 1, 0, 0, 2, 1, 0, 2, 0, 2, 0, 2, 0, 0, 2,
 | |
|             1, 2, 0, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 0, 2,
 | |
|             0, 2, 2, 0, 2, 1, 2, 2, 0, 2, 2, 2, 2, 0, 2,
 | |
|             2, 0, 2, 0, 2, 0, 0, 1, 0, 2, 1, 0, 1, 0, 2,
 | |
|             2, 0, 1, 0, 2, 0, 1, 2, 0, 2, 0, 1, 1, 0, 2,
 | |
|             1, 1, 1, 0, 2, 2, 1, 1, 0, 2, 1, 1, 2, 0, 2,
 | |
|             0, 2, 1, 0, 2, 1, 2, 1, 0, 2, 2, 2, 1, 0, 2,
 | |
|             2, 1, 2, 0, 2, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2,
 | |
|             2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1,
 | |
|             1, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 2, 0, 1,
 | |
|             0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1,
 | |
|             1, 0, 2, 0, 1, 0, 2, 0, 0, 1, 1, 2, 0, 0, 1,
 | |
|             2, 2, 0, 0, 1, 2, 0, 2, 0, 1, 0, 2, 2, 0, 1,
 | |
|             1, 2, 2, 0, 1, 2, 2, 2, 0, 1, 2, 0, 2, 0, 1,
 | |
|             0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 2, 0, 1, 0, 1,
 | |
|             0, 1, 2, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1,
 | |
|             2, 1, 1, 0, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1,
 | |
|             1, 2, 1, 0, 1, 2, 2, 1, 0, 1, 2, 1, 2, 0, 1,
 | |
|             0, 0, 1, 2, 2, 1, 0, 1, 2, 2, 2, 0, 1, 2, 2,
 | |
|             0, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
 | |
|             2, 0, 0, 1, 1, 0, 0, 2, 1, 1, 0, 1, 0, 1, 1,
 | |
|             1, 1, 0, 1, 1, 2, 1, 0, 1, 1, 1, 0, 2, 1, 1,
 | |
|             0, 2, 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 1,
 | |
|             2, 0, 2, 1, 1, 0, 2, 2, 1, 1, 1, 2, 2, 1, 1,
 | |
|             2, 2, 2, 1, 1, 2, 0, 2, 1, 1, 0, 0, 1, 1, 1,
 | |
|             1, 0, 1, 1, 1, 2, 0, 1, 1, 1, 0, 1, 2, 1, 1,
 | |
|             0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
 | |
|             1, 1, 2, 1, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 1,
 | |
|             2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 0, 1, 1, 2, 2,
 | |
|             1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2,
 | |
|             0, 0, 0, 2, 1, 1, 0, 0, 2, 1, 2, 0, 0, 2, 1,
 | |
|             0, 0, 2, 2, 1, 0, 1, 0, 2, 1, 1, 1, 0, 2, 1,
 | |
|             2, 1, 0, 2, 1, 1, 0, 2, 2, 1, 0, 2, 0, 2, 1,
 | |
|             1, 2, 0, 2, 1, 2, 2, 0, 2, 1, 2, 0, 2, 2, 1,
 | |
|             0, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1,
 | |
|             2, 0, 2, 2, 1, 0, 0, 1, 2, 1, 1, 0, 1, 2, 1,
 | |
|             2, 0, 1, 2, 1, 0, 1, 2, 2, 1, 0, 1, 1, 2, 1,
 | |
|             1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1,
 | |
|             0, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1,
 | |
|             2, 1, 2, 2, 1, 0, 2, 1, 2, 2, 1, 2, 1, 2, 2,
 | |
|             2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 1, 2,
 | |
|             1, 0, 0, 1, 2, 2, 0, 0, 1, 2, 0, 0, 2, 1, 2,
 | |
|             0, 1, 0, 1, 2, 1, 1, 0, 1, 2, 2, 1, 0, 1, 2,
 | |
|             1, 0, 2, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 2,
 | |
|             2, 2, 0, 1, 2, 2, 0, 2, 1, 2, 0, 2, 2, 1, 2,
 | |
|             1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 0, 2, 1, 2,
 | |
|             0, 0, 1, 1, 2, 1, 0, 1, 1, 2, 2, 0, 1, 1, 2,
 | |
|             0, 1, 2, 1, 2, 0, 1, 1, 1, 2, 1, 1, 1, 1, 2,
 | |
|             2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 0, 2, 1, 1, 2,
 | |
|             1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2,
 | |
|             0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
 | |
|             2, 1, 2, 2, 2
 | |
|         };
 | |
| 
 | |
|         private static ReadOnlySpan<byte> QuintEncodings => new byte[]
 | |
|         {
 | |
|             0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0,
 | |
|             0, 4, 0, 4, 4, 0, 4, 4, 4, 0, 1, 0, 1, 1, 0,
 | |
|             2, 1, 0, 3, 1, 0, 4, 1, 0, 1, 4, 0, 4, 4, 1,
 | |
|             4, 4, 4, 0, 2, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0,
 | |
|             4, 2, 0, 2, 4, 0, 4, 4, 2, 4, 4, 4, 0, 3, 0,
 | |
|             1, 3, 0, 2, 3, 0, 3, 3, 0, 4, 3, 0, 3, 4, 0,
 | |
|             4, 4, 3, 4, 4, 4, 0, 0, 1, 1, 0, 1, 2, 0, 1,
 | |
|             3, 0, 1, 4, 0, 1, 0, 4, 1, 4, 0, 4, 0, 4, 4,
 | |
|             0, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1,
 | |
|             1, 4, 1, 4, 1, 4, 1, 4, 4, 0, 2, 1, 1, 2, 1,
 | |
|             2, 2, 1, 3, 2, 1, 4, 2, 1, 2, 4, 1, 4, 2, 4,
 | |
|             2, 4, 4, 0, 3, 1, 1, 3, 1, 2, 3, 1, 3, 3, 1,
 | |
|             4, 3, 1, 3, 4, 1, 4, 3, 4, 3, 4, 4, 0, 0, 2,
 | |
|             1, 0, 2, 2, 0, 2, 3, 0, 2, 4, 0, 2, 0, 4, 2,
 | |
|             2, 0, 4, 3, 0, 4, 0, 1, 2, 1, 1, 2, 2, 1, 2,
 | |
|             3, 1, 2, 4, 1, 2, 1, 4, 2, 2, 1, 4, 3, 1, 4,
 | |
|             0, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 2, 4, 2, 2,
 | |
|             2, 4, 2, 2, 2, 4, 3, 2, 4, 0, 3, 2, 1, 3, 2,
 | |
|             2, 3, 2, 3, 3, 2, 4, 3, 2, 3, 4, 2, 2, 3, 4,
 | |
|             3, 3, 4, 0, 0, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3,
 | |
|             4, 0, 3, 0, 4, 3, 0, 0, 4, 1, 0, 4, 0, 1, 3,
 | |
|             1, 1, 3, 2, 1, 3, 3, 1, 3, 4, 1, 3, 1, 4, 3,
 | |
|             0, 1, 4, 1, 1, 4, 0, 2, 3, 1, 2, 3, 2, 2, 3,
 | |
|             3, 2, 3, 4, 2, 3, 2, 4, 3, 0, 2, 4, 1, 2, 4,
 | |
|             0, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3,
 | |
|             3, 4, 3, 0, 3, 4, 1, 3, 4
 | |
|         };
 | |
|     }
 | |
| }
 |