mirror of
https://github.com/yuzu-emu/FasTC
synced 2024-11-22 10:03:48 +00:00
More work on ASTC decode.
Fixed the notion that the CEM data was right after the first six bits after the partition mode. It's actually right before the texel weight data. Still not sure whether or not the texel weights are read in the opposite order from the color data... Also, added some preliminary integer sequence decoding. This will need to be tested before we actually figure out if we did it correctly or not...
This commit is contained in:
parent
94db169582
commit
5a68febdda
1 changed files with 269 additions and 30 deletions
|
@ -52,18 +52,49 @@
|
|||
|
||||
#include "ASTCCompressor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include "TexCompTypes.h"
|
||||
|
||||
#include "Bits.h"
|
||||
using FasTC::Bits;
|
||||
|
||||
#include "BitStream.h"
|
||||
using FasTC::BitStreamReadOnly;
|
||||
|
||||
namespace ASTCC {
|
||||
|
||||
struct TexelWeightParams {
|
||||
// According to table C.2.7
|
||||
void GetBitEncoding(uint8 &nQuints, uint8 &nTrits, uint8 &nBits,
|
||||
const uint32 maxWeight) {
|
||||
nQuints = nTrits = nBits = 0;
|
||||
switch(maxWeight) {
|
||||
case 1: nBits = 1; return;
|
||||
case 2: nTrits = 1; return;
|
||||
case 3: nBits = 2; return;
|
||||
case 4: nQuints = 1; return;
|
||||
case 5: nTrits = 1; nBits = 1; return;
|
||||
case 7: nBits = 3; return;
|
||||
case 9: nQuints = 1; nBits = 1; return;
|
||||
case 11: nTrits = 1; nBits = 2; return;
|
||||
case 15: nBits = 4; return;
|
||||
case 19: nQuints = 1; nBits = 2; return;
|
||||
case 23: nTrits = 1; nBits = 3; return;
|
||||
case 31: nBits = 5; return;
|
||||
|
||||
default:
|
||||
assert(!"Invalid maximum weight");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class TexelWeightParams {
|
||||
public:
|
||||
uint32 m_Width;
|
||||
uint32 m_Height;
|
||||
bool m_bDualPlane;
|
||||
|
@ -75,29 +106,26 @@ namespace ASTCC {
|
|||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
// According to table C.2.7
|
||||
void GetBitEncoding(uint8 &nQuints, uint8 &nTrits, uint8 &nBits) {
|
||||
nQuints = 0;
|
||||
nTrits = 0;
|
||||
nBits = 0;
|
||||
switch(m_MaxWeight) {
|
||||
case 1: nBits = 1; return;
|
||||
case 2: nTrits = 1; return;
|
||||
case 3: nBits = 2; return;
|
||||
case 4: nQuints = 1; return;
|
||||
case 5: nTrits = 1; nBits = 1; return;
|
||||
case 7: nBits = 3; return;
|
||||
case 9: nQuints = 1; nBits = 1; return;
|
||||
case 11: nTrits = 1; nBits = 2; return;
|
||||
case 15: nBits = 4; return;
|
||||
case 19: nQuints = 1; nBits = 2; return;
|
||||
case 23: nTrits = 1; nBits = 3; return;
|
||||
case 31: nBits = 5; return;
|
||||
|
||||
default:
|
||||
assert(!"Invalid maximum weight");
|
||||
return;
|
||||
uint32 GetPackedBitSize() {
|
||||
// How many indices do we have?
|
||||
uint32 nIdxs = m_Height * m_Width;
|
||||
if(m_bDualPlane) {
|
||||
nIdxs *= 2;
|
||||
}
|
||||
|
||||
// How are they encoded?
|
||||
uint8 nQuints, nTrits, nBits;
|
||||
GetBitEncoding(nQuints, nTrits, nBits, m_MaxWeight);
|
||||
|
||||
// nQuints and nTrits are mutually exclusive values of one.
|
||||
assert(nQuints != 1 || nTrits == 0);
|
||||
assert(nTrits != 1 || nQuints == 0);
|
||||
|
||||
// each index has at least as many bits per index as described.
|
||||
uint32 totalBits = nBits * nIdxs;
|
||||
totalBits += (nIdxs * 8 * nTrits + 4) / 5;
|
||||
totalBits += (nIdxs * 7 * nQuints + 2) / 3;
|
||||
return totalBits;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -298,6 +326,143 @@ namespace ASTCC {
|
|||
}
|
||||
}
|
||||
|
||||
void DecodeTritBlock(BitStreamReadOnly &bits,
|
||||
std::vector<uint32> &result,
|
||||
uint32 nBitsPerValue) {
|
||||
// Implement the algorithm in section C.2.12
|
||||
uint32 m[5];
|
||||
uint32 t[5];
|
||||
uint32 T;
|
||||
|
||||
// Read the trit encoded block according to
|
||||
// table C.2.14
|
||||
m[0] = bits.ReadBits(nBitsPerValue);
|
||||
T = bits.ReadBits(2);
|
||||
m[1] = bits.ReadBits(nBitsPerValue);
|
||||
T |= bits.ReadBits(2) << 2;
|
||||
m[2] = bits.ReadBits(nBitsPerValue);
|
||||
T |= bits.ReadBit() << 4;
|
||||
m[3] = bits.ReadBits(nBitsPerValue);
|
||||
T |= bits.ReadBits(2) << 5;
|
||||
m[4] = bits.ReadBits(nBitsPerValue);
|
||||
T |= bits.ReadBit() << 7;
|
||||
|
||||
uint32 C = 0;
|
||||
|
||||
Bits<uint32> Tb(T);
|
||||
if(Tb(2, 4) == 7) {
|
||||
C = (Tb(5, 7) << 2) | Tb(0, 1);
|
||||
t[4] = t[3] = 2;
|
||||
} else {
|
||||
C = Tb(0, 4);
|
||||
if(Tb(5, 6) == 3) {
|
||||
t[4] = 2;
|
||||
t[3] = Tb[7];
|
||||
} else {
|
||||
t[4] = Tb[7];
|
||||
t[3] = Tb(5, 6);
|
||||
}
|
||||
}
|
||||
|
||||
Bits<uint32> Cb(C);
|
||||
if(Cb(0, 1) == 3) {
|
||||
t[2] = 2;
|
||||
t[1] = Cb[4];
|
||||
t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]);
|
||||
} else if(Cb(2, 3) == 3) {
|
||||
t[2] = 2;
|
||||
t[1] = 2;
|
||||
t[0] = Cb(0, 1);
|
||||
} else {
|
||||
t[2] = Cb[4];
|
||||
t[1] = Cb(2, 3);
|
||||
t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]);
|
||||
}
|
||||
|
||||
for(uint32 i = 0; i < 5; i++) {
|
||||
assert(t[i] < 3);
|
||||
uint32 val = (t[i] << nBitsPerValue) + m[i];
|
||||
result.push_back(val);
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeQuintBlock(BitStreamReadOnly &bits,
|
||||
std::vector<uint32> &result,
|
||||
uint32 nBitsPerValue) {
|
||||
// Implement the algorithm in section C.2.12
|
||||
uint32 m[3];
|
||||
uint32 q[3];
|
||||
uint32 Q;
|
||||
|
||||
// Read the trit encoded block according to
|
||||
// table C.2.15
|
||||
m[0] = bits.ReadBits(nBitsPerValue);
|
||||
Q = bits.ReadBits(3);
|
||||
m[1] = bits.ReadBits(nBitsPerValue);
|
||||
Q |= bits.ReadBits(2) << 3;
|
||||
m[2] = bits.ReadBits(nBitsPerValue);
|
||||
Q |= bits.ReadBits(2) << 5;
|
||||
|
||||
Bits<uint32> Qb(Q);
|
||||
if(Qb(1, 2) == 3 && Qb(5, 6) == 0) {
|
||||
q[0] = q[1] = 4;
|
||||
q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]);
|
||||
} else {
|
||||
uint32 C = 0;
|
||||
if(Qb(1, 2) == 3) {
|
||||
q[2] = 4;
|
||||
C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0];
|
||||
} else {
|
||||
q[2] = Qb(5, 6);
|
||||
C = Qb(0, 4);
|
||||
}
|
||||
|
||||
Bits<uint32> Cb(C);
|
||||
if(Cb(0, 2) == 5) {
|
||||
q[1] = 4;
|
||||
q[0] = Cb(3, 4);
|
||||
} else {
|
||||
q[1] = Cb(3, 4);
|
||||
q[0] = Cb(0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32 i = 0; i < 3; i++) {
|
||||
assert(q[i] < 5);
|
||||
uint32 val = (q[i] << nBitsPerValue) + m[i];
|
||||
result.push_back(val);
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeIntegerSequence(BitStreamReadOnly &bits,
|
||||
std::vector<uint32> &result,
|
||||
uint32 maxRange,
|
||||
uint32 nValues) {
|
||||
// Clean our result vector
|
||||
result.clear();
|
||||
result.reserve(nValues);
|
||||
|
||||
// Determine encoding parameters
|
||||
uint8 nQuints, nTrits, nBits;
|
||||
GetBitEncoding(nQuints, nTrits, nBits, maxRange);
|
||||
|
||||
// Start decoding
|
||||
uint32 nValsDecoded = 0;
|
||||
while(nValsDecoded < nValues) {
|
||||
if(nQuints) {
|
||||
DecodeQuintBlock(bits, result, nBits);
|
||||
nValsDecoded += 3;
|
||||
} else if(nTrits) {
|
||||
DecodeTritBlock(bits, result, nBits);
|
||||
nValsDecoded += 5;
|
||||
} else {
|
||||
// Decode bit by bit
|
||||
result.push_back(bits.ReadBits(nBits));
|
||||
nValsDecoded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecompressBlock(const uint8 inBuf[16],
|
||||
const uint32 blockWidth, const uint32 blockHeight,
|
||||
uint8 *outBuf) {
|
||||
|
@ -335,29 +500,103 @@ namespace ASTCC {
|
|||
|
||||
// Based on the number of partitions, read the color endpoint mode for
|
||||
// each partition.
|
||||
|
||||
// Determine partitions, partition index, and color endpoint modes
|
||||
int32 planeIdx = -1;
|
||||
uint32 partitionIndex = nPartitions;
|
||||
uint32 colorEndpointMode[4] = {0, 0, 0, 0};
|
||||
|
||||
// Define color data.
|
||||
uint8 colorEndpointData[16];
|
||||
memset(colorEndpointData, 0, sizeof(colorEndpointData));
|
||||
FasTC::BitStream colorEndpointStream (colorEndpointData, 16*8, 0);
|
||||
|
||||
// Read extra config data...
|
||||
uint32 baseCEM = 0;
|
||||
if(nPartitions == 1) {
|
||||
colorEndpointMode[0] = strm.ReadBits(4);
|
||||
} else {
|
||||
uint32 restOfPartitionIndex = strm.ReadBits(10);
|
||||
partitionIndex |= restOfPartitionIndex << 2;
|
||||
baseCEM = strm.ReadBits(6);
|
||||
}
|
||||
uint32 baseMode = (baseCEM & 3);
|
||||
|
||||
uint32 CEM = strm.ReadBits(2) - 1;
|
||||
// Remaining bits are color endpoint data...
|
||||
uint32 nWeightBits = weightParams.GetPackedBitSize();
|
||||
int32 remainingBits = 128 - nWeightBits - strm.GetBitsRead();
|
||||
|
||||
// Consider extra bits prior to texel data...
|
||||
uint32 extraCEMbits = 0;
|
||||
if(baseMode) {
|
||||
switch(nPartitions) {
|
||||
case 2: extraCEMbits += 2; break;
|
||||
case 3: extraCEMbits += 5; break;
|
||||
case 4: extraCEMbits += 8; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
}
|
||||
remainingBits -= extraCEMbits;
|
||||
|
||||
// Do we have a dual plane situation?
|
||||
uint32 planeSelectorBits = 0;
|
||||
if(weightParams.m_bDualPlane) {
|
||||
planeSelectorBits = 2;
|
||||
}
|
||||
remainingBits -= planeSelectorBits;
|
||||
|
||||
// Read color data...
|
||||
while(remainingBits > 0) {
|
||||
uint32 nb = std::min(remainingBits, 8);
|
||||
uint32 b = strm.ReadBits(nb);
|
||||
colorEndpointStream.WriteBits(b, nb);
|
||||
remainingBits -= 8;
|
||||
}
|
||||
|
||||
// Read the plane selection bits
|
||||
planeIdx = strm.ReadBits(planeSelectorBits);
|
||||
|
||||
// Read the rest of the CEM
|
||||
if(baseMode) {
|
||||
uint32 extraCEM = strm.ReadBits(extraCEMbits);
|
||||
uint32 CEM = (extraCEM << 6) | baseCEM;
|
||||
CEM >>= 2;
|
||||
|
||||
bool C[4] = { 0 };
|
||||
for(uint32 i = 0; i < nPartitions; i++) {
|
||||
colorEndpointMode[i] = CEM + strm.ReadBit();
|
||||
C[i] = CEM & 1;
|
||||
CEM >>= 1;
|
||||
}
|
||||
|
||||
uint8 M[4] = { 0 };
|
||||
for(uint32 i = 0; i < nPartitions; i++) {
|
||||
M[i] = CEM & 3;
|
||||
CEM >>= 2;
|
||||
assert(M[i] <= 3);
|
||||
}
|
||||
|
||||
for(uint32 i = 0; i < nPartitions; i++) {
|
||||
colorEndpointMode[i] = baseMode;
|
||||
if(!(C[i])) colorEndpointMode[i] -= 1;
|
||||
colorEndpointMode[i] <<= 2;
|
||||
if(i == 0 && nPartitions == 3) {
|
||||
colorEndpointMode[i] += strm.ReadBit();
|
||||
} else {
|
||||
colorEndpointMode[i] += strm.ReadBits(2);
|
||||
}
|
||||
colorEndpointMode[i] |= M[i];
|
||||
}
|
||||
} else if(nPartitions > 1) {
|
||||
uint32 CEM = baseCEM >> 2;
|
||||
for(uint32 i = 0; i < nPartitions; i++) {
|
||||
colorEndpointMode[i] = CEM;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Make sure everything up till here is sane.
|
||||
for(uint32 i = 0; i < nPartitions; i++) {
|
||||
assert(colorEndpointMode[i] < 16);
|
||||
}
|
||||
assert(strm.GetBitsRead() + weightParams.GetPackedBitSize() == 128);
|
||||
#endif
|
||||
|
||||
// Read the texel weight data..
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue