mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-15 22:54:00 +00:00
astc: Make IntegerEncodedValue a trivial structure
This commit is contained in:
parent
70a31eda62
commit
e183820956
1 changed files with 181 additions and 216 deletions
|
@ -160,124 +160,34 @@ private:
|
|||
|
||||
enum class IntegerEncoding { JustBits, Qus32, Trit };
|
||||
|
||||
class IntegerEncodedValue {
|
||||
private:
|
||||
IntegerEncoding m_Encoding{};
|
||||
u32 m_NumBits = 0;
|
||||
u32 m_BitValue = 0;
|
||||
union {
|
||||
u32 m_Qus32Value = 0;
|
||||
u32 m_TritValue;
|
||||
};
|
||||
struct IntegerEncodedValue {
|
||||
constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
|
||||
: encoding{encoding_}, num_bits{num_bits_} {}
|
||||
|
||||
public:
|
||||
constexpr IntegerEncodedValue() = default;
|
||||
constexpr IntegerEncodedValue(IntegerEncoding encoding, u32 numBits)
|
||||
: m_Encoding(encoding), m_NumBits(numBits) {}
|
||||
|
||||
IntegerEncoding GetEncoding() const {
|
||||
return m_Encoding;
|
||||
}
|
||||
u32 BaseBitLength() const {
|
||||
return m_NumBits;
|
||||
}
|
||||
|
||||
u32 GetBitValue() const {
|
||||
return m_BitValue;
|
||||
}
|
||||
void SetBitValue(u32 val) {
|
||||
m_BitValue = val;
|
||||
}
|
||||
|
||||
u32 GetTritValue() const {
|
||||
return m_TritValue;
|
||||
}
|
||||
void SetTritValue(u32 val) {
|
||||
m_TritValue = val;
|
||||
}
|
||||
|
||||
u32 GetQus32Value() const {
|
||||
return m_Qus32Value;
|
||||
}
|
||||
void SetQus32Value(u32 val) {
|
||||
m_Qus32Value = val;
|
||||
}
|
||||
|
||||
bool MatchesEncoding(const IntegerEncodedValue& other) const {
|
||||
return m_Encoding == other.m_Encoding && m_NumBits == other.m_NumBits;
|
||||
constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
|
||||
return encoding == other.encoding && num_bits == other.num_bits;
|
||||
}
|
||||
|
||||
// Returns the number of bits required to encode nVals values.
|
||||
u32 GetBitLength(u32 nVals) const {
|
||||
u32 totalBits = m_NumBits * nVals;
|
||||
if (m_Encoding == IntegerEncoding::Trit) {
|
||||
u32 totalBits = num_bits * nVals;
|
||||
if (encoding == IntegerEncoding::Trit) {
|
||||
totalBits += (nVals * 8 + 4) / 5;
|
||||
} else if (m_Encoding == IntegerEncoding::Qus32) {
|
||||
} else if (encoding == IntegerEncoding::Qus32) {
|
||||
totalBits += (nVals * 7 + 2) / 3;
|
||||
}
|
||||
return totalBits;
|
||||
}
|
||||
|
||||
// Returns a new instance of this struct that corresponds to the
|
||||
// can take no more than maxval values
|
||||
static IntegerEncodedValue CreateEncoding(u32 maxVal) {
|
||||
while (maxVal > 0) {
|
||||
u32 check = maxVal + 1;
|
||||
IntegerEncoding encoding;
|
||||
u32 num_bits;
|
||||
u32 bit_value = 0;
|
||||
union {
|
||||
u32 qus32_value = 0;
|
||||
u32 trit_value;
|
||||
};
|
||||
};
|
||||
|
||||
// Is maxVal a power of two?
|
||||
if (!(check & (check - 1))) {
|
||||
return IntegerEncodedValue(IntegerEncoding::JustBits, Popcnt(maxVal));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 3*2^n - 1?
|
||||
if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
|
||||
return IntegerEncodedValue(IntegerEncoding::Trit, Popcnt(check / 3 - 1));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 5*2^n - 1?
|
||||
if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
|
||||
return IntegerEncodedValue(IntegerEncoding::Qus32, Popcnt(check / 5 - 1));
|
||||
}
|
||||
|
||||
// Apparently it can't be represented with a bounded s32eger sequence...
|
||||
// just iterate.
|
||||
maxVal--;
|
||||
}
|
||||
return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
|
||||
}
|
||||
|
||||
// Fills result with the values that are encoded in the given
|
||||
// bitstream. We must know beforehand what the maximum possible
|
||||
// value is, and how many values we're decoding.
|
||||
static void DecodeIntegerSequence(std::vector<IntegerEncodedValue>& result,
|
||||
InputBitStream& bits, u32 maxRange, u32 nValues) {
|
||||
// Determine encoding parameters
|
||||
IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(maxRange);
|
||||
|
||||
// Start decoding
|
||||
u32 nValsDecoded = 0;
|
||||
while (nValsDecoded < nValues) {
|
||||
switch (val.GetEncoding()) {
|
||||
case IntegerEncoding::Qus32:
|
||||
DecodeQus32Block(bits, result, val.BaseBitLength());
|
||||
nValsDecoded += 3;
|
||||
break;
|
||||
|
||||
case IntegerEncoding::Trit:
|
||||
DecodeTritBlock(bits, result, val.BaseBitLength());
|
||||
nValsDecoded += 5;
|
||||
break;
|
||||
|
||||
case IntegerEncoding::JustBits:
|
||||
val.SetBitValue(bits.ReadBits(val.BaseBitLength()));
|
||||
result.push_back(val);
|
||||
nValsDecoded++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void DecodeTritBlock(InputBitStream& bits, std::vector<IntegerEncodedValue>& result,
|
||||
u32 nBitsPerValue) {
|
||||
// Implement the algorithm in section C.2.12
|
||||
|
@ -330,11 +240,10 @@ private:
|
|||
t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 5; i++) {
|
||||
IntegerEncodedValue val(IntegerEncoding::Trit, nBitsPerValue);
|
||||
val.SetBitValue(m[i]);
|
||||
val.SetTritValue(t[i]);
|
||||
result.push_back(val);
|
||||
for (std::size_t i = 0; i < 5; ++i) {
|
||||
IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Trit, nBitsPerValue);
|
||||
val.bit_value = m[i];
|
||||
val.trit_value = t[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,14 +287,71 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 3; i++) {
|
||||
IntegerEncodedValue val(IntegerEncoding::Qus32, nBitsPerValue);
|
||||
val.m_BitValue = m[i];
|
||||
val.m_Qus32Value = q[i];
|
||||
for (std::size_t i = 0; i < 3; ++i) {
|
||||
IntegerEncodedValue& val = result.emplace_back(IntegerEncoding::Qus32, nBitsPerValue);
|
||||
val.bit_value = m[i];
|
||||
val.qus32_value = q[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a new instance of this struct that corresponds to the
|
||||
// can take no more than maxval values
|
||||
static IntegerEncodedValue CreateEncoding(u32 maxVal) {
|
||||
while (maxVal > 0) {
|
||||
u32 check = maxVal + 1;
|
||||
|
||||
// Is maxVal a power of two?
|
||||
if (!(check & (check - 1))) {
|
||||
return IntegerEncodedValue(IntegerEncoding::JustBits, Popcnt(maxVal));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 3*2^n - 1?
|
||||
if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
|
||||
return IntegerEncodedValue(IntegerEncoding::Trit, Popcnt(check / 3 - 1));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 5*2^n - 1?
|
||||
if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
|
||||
return IntegerEncodedValue(IntegerEncoding::Qus32, Popcnt(check / 5 - 1));
|
||||
}
|
||||
|
||||
// Apparently it can't be represented with a bounded s32eger sequence...
|
||||
// just iterate.
|
||||
maxVal--;
|
||||
}
|
||||
return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
|
||||
}
|
||||
|
||||
// Fills result with the values that are encoded in the given
|
||||
// bitstream. We must know beforehand what the maximum possible
|
||||
// value is, and how many values we're decoding.
|
||||
static void DecodeIntegerSequence(std::vector<IntegerEncodedValue>& result, InputBitStream& bits,
|
||||
u32 maxRange, u32 nValues) {
|
||||
// Determine encoding parameters
|
||||
IntegerEncodedValue val = CreateEncoding(maxRange);
|
||||
|
||||
// Start decoding
|
||||
u32 nValsDecoded = 0;
|
||||
while (nValsDecoded < nValues) {
|
||||
switch (val.encoding) {
|
||||
case IntegerEncoding::Qus32:
|
||||
DecodeQus32Block(bits, result, val.num_bits);
|
||||
nValsDecoded += 3;
|
||||
break;
|
||||
|
||||
case IntegerEncoding::Trit:
|
||||
DecodeTritBlock(bits, result, val.num_bits);
|
||||
nValsDecoded += 5;
|
||||
break;
|
||||
|
||||
case IntegerEncoding::JustBits:
|
||||
val.bit_value = bits.ReadBits(val.num_bits);
|
||||
result.push_back(val);
|
||||
nValsDecoded++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace ASTCC {
|
||||
|
||||
|
@ -405,7 +371,7 @@ struct TexelWeightParams {
|
|||
nIdxs *= 2;
|
||||
}
|
||||
|
||||
return IntegerEncodedValue::CreateEncoding(m_MaxWeight).GetBitLength(nIdxs);
|
||||
return CreateEncoding(m_MaxWeight).GetBitLength(nIdxs);
|
||||
}
|
||||
|
||||
u32 GetNumWeightValues() const {
|
||||
|
@ -814,12 +780,12 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
// figure out the max value for each of them...
|
||||
u32 range = 256;
|
||||
while (--range > 0) {
|
||||
IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(range);
|
||||
IntegerEncodedValue val = CreateEncoding(range);
|
||||
u32 bitLength = val.GetBitLength(nValues);
|
||||
if (bitLength <= nBitsForColorData) {
|
||||
// Find the smallest possible range that matches the given encoding
|
||||
while (--range > 0) {
|
||||
IntegerEncodedValue newval = IntegerEncodedValue::CreateEncoding(range);
|
||||
IntegerEncodedValue newval = CreateEncoding(range);
|
||||
if (!newval.MatchesEncoding(val)) {
|
||||
break;
|
||||
}
|
||||
|
@ -834,7 +800,7 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
// We now have enough to decode our s32eger sequence.
|
||||
std::vector<IntegerEncodedValue> decodedColorValues;
|
||||
InputBitStream colorStream(data);
|
||||
IntegerEncodedValue::DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
|
||||
DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
|
||||
|
||||
// Once we have the decoded values, we need to dequantize them to the 0-255 range
|
||||
// This procedure is outlined in ASTC spec C.2.13
|
||||
|
@ -846,8 +812,8 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
}
|
||||
|
||||
const IntegerEncodedValue& val = *itr;
|
||||
u32 bitlen = val.BaseBitLength();
|
||||
u32 bitval = val.GetBitValue();
|
||||
u32 bitlen = val.num_bits;
|
||||
u32 bitval = val.bit_value;
|
||||
|
||||
assert(bitlen >= 1);
|
||||
|
||||
|
@ -855,7 +821,7 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
// A is just the lsb replicated 9 times.
|
||||
A = Replicate(bitval & 1, 1, 9);
|
||||
|
||||
switch (val.GetEncoding()) {
|
||||
switch (val.encoding) {
|
||||
// Replicate bits
|
||||
case IntegerEncoding::JustBits:
|
||||
out[outIdx++] = Replicate(bitval, bitlen, 8);
|
||||
|
@ -864,7 +830,7 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
// Use algorithm in C.2.13
|
||||
case IntegerEncoding::Trit: {
|
||||
|
||||
D = val.GetTritValue();
|
||||
D = val.trit_value;
|
||||
|
||||
switch (bitlen) {
|
||||
case 1: {
|
||||
|
@ -915,7 +881,7 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
|
||||
case IntegerEncoding::Qus32: {
|
||||
|
||||
D = val.GetQus32Value();
|
||||
D = val.qus32_value;
|
||||
|
||||
switch (bitlen) {
|
||||
case 1: {
|
||||
|
@ -956,9 +922,9 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
} // switch(bitlen)
|
||||
} // case IntegerEncoding::Qus32
|
||||
break;
|
||||
} // switch(val.GetEncoding())
|
||||
} // switch(val.encoding)
|
||||
|
||||
if (val.GetEncoding() != IntegerEncoding::JustBits) {
|
||||
if (val.encoding != IntegerEncoding::JustBits) {
|
||||
u32 T = D * C + B;
|
||||
T ^= A;
|
||||
T = (A & 0x80) | (T >> 2);
|
||||
|
@ -973,20 +939,20 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP
|
|||
}
|
||||
|
||||
static u32 UnquantizeTexelWeight(const IntegerEncodedValue& val) {
|
||||
u32 bitval = val.GetBitValue();
|
||||
u32 bitlen = val.BaseBitLength();
|
||||
u32 bitval = val.bit_value;
|
||||
u32 bitlen = val.num_bits;
|
||||
|
||||
u32 A = Replicate(bitval & 1, 1, 7);
|
||||
u32 B = 0, C = 0, D = 0;
|
||||
|
||||
u32 result = 0;
|
||||
switch (val.GetEncoding()) {
|
||||
switch (val.encoding) {
|
||||
case IntegerEncoding::JustBits:
|
||||
result = Replicate(bitval, bitlen, 6);
|
||||
break;
|
||||
|
||||
case IntegerEncoding::Trit: {
|
||||
D = val.GetTritValue();
|
||||
D = val.trit_value;
|
||||
assert(D < 3);
|
||||
|
||||
switch (bitlen) {
|
||||
|
@ -1018,7 +984,7 @@ static u32 UnquantizeTexelWeight(const IntegerEncodedValue& val) {
|
|||
} break;
|
||||
|
||||
case IntegerEncoding::Qus32: {
|
||||
D = val.GetQus32Value();
|
||||
D = val.qus32_value;
|
||||
assert(D < 5);
|
||||
|
||||
switch (bitlen) {
|
||||
|
@ -1044,7 +1010,7 @@ static u32 UnquantizeTexelWeight(const IntegerEncodedValue& val) {
|
|||
} break;
|
||||
}
|
||||
|
||||
if (val.GetEncoding() != IntegerEncoding::JustBits && bitlen > 0) {
|
||||
if (val.encoding != IntegerEncoding::JustBits && bitlen > 0) {
|
||||
// Decode the value...
|
||||
result = D * C + B;
|
||||
result ^= A;
|
||||
|
@ -1562,8 +1528,7 @@ static void DecompressBlock(const u8 inBuf[16], const u32 blockWidth, const u32
|
|||
std::vector<IntegerEncodedValue> texelWeightValues;
|
||||
InputBitStream weightStream(texelWeightData);
|
||||
|
||||
IntegerEncodedValue::DecodeIntegerSequence(texelWeightValues, weightStream,
|
||||
weightParams.m_MaxWeight,
|
||||
DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight,
|
||||
weightParams.GetNumWeightValues());
|
||||
|
||||
// Blocks can be at most 12x12, so we can have as many as 144 weights
|
||||
|
|
Loading…
Reference in a new issue