Ryujinx/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs
Alex Barney d1ab9fb42c ASTC optimizations (#845)
* 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
2020-01-09 02:13:00 +01:00

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
};
}
}