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:
Pavel Krajcevski 2014-03-07 19:32:15 -05:00
parent 94db169582
commit 5a68febdda

View file

@ -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..
}