Add specific function to collect stats for BPTC so that we have one that preserves accurate running time measurements.

This commit is contained in:
Pavel Krajcevski 2012-10-08 18:34:42 -04:00
parent 4c359f42a7
commit 1bd1a79065

View File

@ -1404,7 +1404,8 @@ namespace BC7C
// Function prototypes // Function prototypes
static void ExtractBlock(const uint8* inPtr, int width, uint32* colorBlock); static void ExtractBlock(const uint8* inPtr, int width, uint32* colorBlock);
static void CompressBC7Block(const uint32 *block, uint8 *outBuf, BlockStatManager *statManager); static void CompressBC7Block(const uint32 *block, uint8 *outBuf);
static void CompressBC7Block(const uint32 *block, uint8 *outBuf, BlockStatManager &statManager);
static int gQualityLevel = 50; static int gQualityLevel = 50;
void SetQualityLevel(int q) { void SetQualityLevel(int q) {
@ -1490,7 +1491,7 @@ namespace BC7C
for(int i = 0; i < width; i += 4) for(int i = 0; i < width; i += 4)
{ {
// ExtractBlock(inBuf + i * 4, width, block); // ExtractBlock(inBuf + i * 4, width, block);
CompressBC7Block((const uint32 *)inBuf, outBuf, NULL); CompressBC7Block((const uint32 *)inBuf, outBuf);
BC7CompressionMode::NumUses[gBestMode]++; BC7CompressionMode::NumUses[gBestMode]++;
#ifndef NDEBUG #ifndef NDEBUG
@ -1531,7 +1532,7 @@ namespace BC7C
for(int i = 0; i < width; i += 4) for(int i = 0; i < width; i += 4)
{ {
// ExtractBlock(inBuf + i * 4, width, block); // ExtractBlock(inBuf + i * 4, width, block);
CompressBC7Block((const uint32 *)inBuf, outBuf, &statManager); CompressBC7Block((const uint32 *)inBuf, outBuf, statManager);
BC7CompressionMode::NumUses[gBestMode]++; BC7CompressionMode::NumUses[gBestMode]++;
#ifndef NDEBUG #ifndef NDEBUG
@ -1688,7 +1689,207 @@ namespace BC7C
assert(!(clusters[0].GetPointBitString() & clusters[2].GetPointBitString())); assert(!(clusters[0].GetPointBitString() & clusters[2].GetPointBitString()));
} }
static double EstimateTwoClusterError(RGBACluster &c, double (&estimates)[2]) { static double EstimateTwoClusterError(RGBACluster &c) {
RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max);
v = Max - Min;
if(v * v == 0) {
return 0.0;
}
const float *w = BC7C::GetErrorMetric();
double error = 0.0001;
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
double eigOne = c.GetPrincipalEigenvalue();
double eigTwo = c.GetSecondEigenvalue();
if(eigOne != 0.0) {
error += eigTwo / eigOne;
}
else {
error += 1.0;
}
#else
error += c.QuantizedError(Min, Max, 4, 0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
#endif
return error;
}
static double EstimateThreeClusterError(RGBACluster &c) {
RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max);
v = Max - Min;
if(v * v == 0) {
return 0.0;
}
const float *w = BC7C::GetErrorMetric();
double error = 0.0001;
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION
double eigOne = c.GetPrincipalEigenvalue();
double eigTwo = c.GetSecondEigenvalue();
// printf("EigOne: %08.3f\tEigTwo: %08.3f\n", eigOne, eigTwo);
if(eigOne != 0.0) {
error += eigTwo / eigOne;
}
else {
error += 1.0;
}
#else
error += c.QuantizedError(Min, Max, 4, 0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
#endif
return error;
}
static void CompressBC7Block(const uint32 *block, uint8 *outBuf) {
// All a single color?
if(AllOneColor(block)) {
BitStream bStrm(outBuf, 128, 0);
CompressOptimalColorBC7(*block, bStrm);
return;
}
RGBACluster blockCluster;
bool opaque = true;
bool transparent = true;
for(int i = 0; i < kMaxNumDataPoints; i++) {
RGBAVector p = RGBAVector(i, block[i]);
blockCluster.AddPoint(p);
if(fabs(p.a - 255.0f) > 1e-10)
opaque = false;
if(p.a > 0.0f)
transparent = false;
}
// The whole block is transparent?
if(transparent) {
BitStream bStrm(outBuf, 128, 0);
WriteTransparentBlock(bStrm);
return;
}
// First we must figure out which shape to use. To do this, simply
// see which shape has the smallest sum of minimum bounding spheres.
double bestError[2] = { DBL_MAX, DBL_MAX };
int bestShapeIdx[2] = { -1, -1 };
RGBACluster bestClusters[2][3];
for(int i = 0; i < kNumShapes2; i++)
{
RGBACluster clusters[2];
PopulateTwoClustersForShape(blockCluster, i, clusters);
double err = 0.0;
for(int ci = 0; ci < 2; ci++) {
err += EstimateTwoClusterError(clusters[ci]);
}
// If it's small, we'll take it!
if(err < 1e-9) {
CompressTwoClusters(i, clusters, outBuf, opaque);
return;
}
if(err < bestError[0]) {
bestError[0] = err;
bestShapeIdx[0] = i;
bestClusters[0][0] = clusters[0];
bestClusters[0][1] = clusters[1];
}
}
// There are not 3 subset blocks that support alpha, so only check these
// if the entire block is opaque.
if(opaque) {
for(int i = 0; i < kNumShapes3; i++) {
RGBACluster clusters[3];
PopulateThreeClustersForShape(blockCluster, i, clusters);
double err = 0.0;
for(int ci = 0; ci < 3; ci++) {
err += EstimateThreeClusterError(clusters[ci]);
}
// If it's small, we'll take it!
if(err < 1e-9) {
CompressThreeClusters(i, clusters, outBuf, opaque);
return;
}
if(err < bestError[1]) {
bestError[1] = err;
bestShapeIdx[1] = i;
bestClusters[1][0] = clusters[0];
bestClusters[1][1] = clusters[1];
bestClusters[1][2] = clusters[2];
}
}
}
uint8 tempBuf1[16], tempBuf2[16];
BitStream tempStream1 (tempBuf1, 128, 0);
BC7CompressionMode compressor(6, opaque);
double best = compressor.Compress(tempStream1, 0, &blockCluster);
if(best == 0.0f) {
memcpy(outBuf, tempBuf1, 16);
return;
}
// Check modes 4 and 5 if the block isn't opaque...
if(!opaque) {
for(int mode = 4; mode <= 5; mode++) {
BitStream tempStream2(tempBuf2, 128, 0);
BC7CompressionMode compressorTry(mode, opaque);
double error = compressorTry.Compress(tempStream2, 0, &blockCluster);
if(error < best) {
best = error;
if(best == 0.0f) {
memcpy(outBuf, tempBuf2, 16);
return;
}
else {
memcpy(tempBuf1, tempBuf2, 16);
}
}
}
}
double error = CompressTwoClusters(bestShapeIdx[0], bestClusters[0], tempBuf2, opaque);
if(error < best) {
best = error;
if(error == 0.0f) {
memcpy(outBuf, tempBuf2, 16);
return;
}
else {
memcpy(tempBuf1, tempBuf2, 16);
}
}
if(opaque) {
if(CompressThreeClusters(bestShapeIdx[1], bestClusters[1], tempBuf2, opaque) < best) {
memcpy(outBuf, tempBuf2, 16);
return;
}
}
memcpy(outBuf, tempBuf1, 16);
}
static double EstimateTwoClusterErrorStats(RGBACluster &c, double (&estimates)[2]) {
RGBAVector Min, Max, v; RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max); c.GetBoundingBox(Min, Max);
v = Max - Min; v = Max - Min;
@ -1727,7 +1928,7 @@ namespace BC7C
return error; return error;
} }
static double EstimateThreeClusterError(RGBACluster &c, double (&estimates)[2]) { static double EstimateThreeClusterErrorStats(RGBACluster &c, double (&estimates)[2]) {
RGBAVector Min, Max, v; RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max); c.GetBoundingBox(Min, Max);
v = Max - Min; v = Max - Min;
@ -1775,46 +1976,41 @@ namespace BC7C
} }
} }
// Compress a single block. // Compress a single block but collect statistics as well...
static void CompressBC7Block(const uint32 *block, uint8 *outBuf, BlockStatManager *statManager) { static void CompressBC7Block(const uint32 *block, uint8 *outBuf, BlockStatManager &statManager) {
class RAIIStatSaver { class RAIIStatSaver {
private: private:
uint32 m_BlockIdx; uint32 m_BlockIdx;
BlockStatManager *m_BSM; BlockStatManager &m_BSM;
public: public:
RAIIStatSaver(uint32 blockIdx, BlockStatManager *m) : m_BlockIdx(blockIdx), m_BSM(m) { } RAIIStatSaver(uint32 blockIdx, BlockStatManager &m) : m_BlockIdx(blockIdx), m_BSM(m) { }
~RAIIStatSaver() { ~RAIIStatSaver() {
if(!m_BSM)
return;
BlockStat s (kBlockStatString[eBlockStat_Mode], gBestMode); BlockStat s (kBlockStatString[eBlockStat_Mode], gBestMode);
m_BSM->AddStat(m_BlockIdx, s); m_BSM.AddStat(m_BlockIdx, s);
for(int i = 0; i < BC7CompressionMode::kNumModes; i++) { for(int i = 0; i < BC7CompressionMode::kNumModes; i++) {
s = BlockStat(kBlockStatString[eBlockStat_ModeZeroEstimate + i], gModeEstimate[i]); s = BlockStat(kBlockStatString[eBlockStat_ModeZeroEstimate + i], gModeEstimate[i]);
m_BSM->AddStat(m_BlockIdx, s); m_BSM.AddStat(m_BlockIdx, s);
s = BlockStat(kBlockStatString[eBlockStat_ModeZeroError + i], gModeError[i]); s = BlockStat(kBlockStatString[eBlockStat_ModeZeroError + i], gModeError[i]);
m_BSM->AddStat(m_BlockIdx, s); m_BSM.AddStat(m_BlockIdx, s);
} }
} }
}; };
uint32 blockIdx = 0; uint32 blockIdx = 0;
if(statManager) { // reset global variables...
gBestMode = 0;
for(int i = 0; i < BC7CompressionMode::kNumModes; i++){
gModeError[i] = gModeEstimate[i] = -1.0;
}
// reset global variables... blockIdx = statManager.BeginBlock();
gBestMode = 0;
for(int i = 0; i < BC7CompressionMode::kNumModes; i++){
gModeError[i] = gModeEstimate[i] = -1.0;
}
blockIdx = statManager->BeginBlock(); for(int i = 0; i < kNumBlockStats; i++) {
statManager.AddStat(blockIdx, BlockStat(kBlockStatString[i], 0));
for(int i = 0; i < kNumBlockStats; i++) {
statManager->AddStat(blockIdx, BlockStat(kBlockStatString[i], 0));
}
} }
RAIIStatSaver __statsaver__(blockIdx, statManager); RAIIStatSaver __statsaver__(blockIdx, statManager);
@ -1825,10 +2021,8 @@ namespace BC7C
CompressOptimalColorBC7(*block, bStrm); CompressOptimalColorBC7(*block, bStrm);
gBestMode = 5; gBestMode = 5;
if(statManager) { BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 0);
BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 0); statManager.AddStat(blockIdx, s);
statManager->AddStat(blockIdx, s);
}
return; return;
} }
@ -1853,10 +2047,8 @@ namespace BC7C
WriteTransparentBlock(bStrm); WriteTransparentBlock(bStrm);
gBestMode = 6; gBestMode = 6;
if(statManager) { BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 1);
BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 1); statManager.AddStat(blockIdx, s);
statManager->AddStat(blockIdx, s);
}
return; return;
} }
@ -1876,20 +2068,18 @@ namespace BC7C
UpdateErrorEstimate(6, err); UpdateErrorEstimate(6, err);
#ifdef USE_PCA_FOR_SHAPE_ESTIMATION #ifdef USE_PCA_FOR_SHAPE_ESTIMATION
if(statManager) { double eigOne = blockCluster.GetPrincipalEigenvalue();
double eigOne = blockCluster.GetPrincipalEigenvalue(); double eigTwo = blockCluster.GetSecondEigenvalue();
double eigTwo = blockCluster.GetSecondEigenvalue(); double error;
double error; if(eigOne != 0.0) {
if(eigOne != 0.0) { error = eigTwo / eigOne;
error = eigTwo / eigOne;
}
else {
error = 1.0;
}
BlockStat s (kBlockStatString[eBlockStat_SingleShapeEstimate], error);
statManager->AddStat(blockIdx, s);
} }
else {
error = 1.0;
}
BlockStat s (kBlockStatString[eBlockStat_SingleShapeEstimate], error);
statManager.AddStat(blockIdx, s);
#endif #endif
} }
} }
@ -1910,7 +2100,7 @@ namespace BC7C
double errEstimate[2] = { -1.0, -1.0 }; double errEstimate[2] = { -1.0, -1.0 };
for(int ci = 0; ci < 2; ci++) { for(int ci = 0; ci < 2; ci++) {
double shapeEstimate[2] = { -1.0, -1.0 }; double shapeEstimate[2] = { -1.0, -1.0 };
err += EstimateTwoClusterError(clusters[ci], shapeEstimate); err += EstimateTwoClusterErrorStats(clusters[ci], shapeEstimate);
for(int ei = 0; ei < 2; ei++) { for(int ei = 0; ei < 2; ei++) {
if(shapeEstimate[ei] >= 0.0) { if(shapeEstimate[ei] >= 0.0) {
@ -1936,9 +2126,9 @@ namespace BC7C
UpdateErrorEstimate(3, errEstimate[1]); UpdateErrorEstimate(3, errEstimate[1]);
} }
if(statManager && err < bestError[0]) { if(err < bestError[0]) {
BlockStat s = BlockStat(kBlockStatString[eBlockStat_TwoShapeEstimate], err); BlockStat s = BlockStat(kBlockStatString[eBlockStat_TwoShapeEstimate], err);
statManager->AddStat(blockIdx, s); statManager.AddStat(blockIdx, s);
} }
// If it's small, we'll take it! // If it's small, we'll take it!
@ -1946,10 +2136,8 @@ namespace BC7C
CompressTwoClusters(i, clusters, outBuf, opaque); CompressTwoClusters(i, clusters, outBuf, opaque);
gBestMode = gModeChosen; gBestMode = gModeChosen;
if(statManager) { BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 2);
BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 2); statManager.AddStat(blockIdx, s);
statManager->AddStat(blockIdx, s);
}
return; return;
} }
@ -1973,7 +2161,7 @@ namespace BC7C
double errEstimate[2] = { -1.0, -1.0 }; double errEstimate[2] = { -1.0, -1.0 };
for(int ci = 0; ci < 3; ci++) { for(int ci = 0; ci < 3; ci++) {
double shapeEstimate[2] = { -1.0, -1.0 }; double shapeEstimate[2] = { -1.0, -1.0 };
err += EstimateThreeClusterError(clusters[ci], shapeEstimate); err += EstimateThreeClusterErrorStats(clusters[ci], shapeEstimate);
for(int ei = 0; ei < 2; ei++) { for(int ei = 0; ei < 2; ei++) {
if(shapeEstimate[ei] >= 0.0) { if(shapeEstimate[ei] >= 0.0) {
@ -1999,9 +2187,9 @@ namespace BC7C
UpdateErrorEstimate(2, errEstimate[1]); UpdateErrorEstimate(2, errEstimate[1]);
} }
if(statManager && err < bestError[1]) { if(err < bestError[1]) {
BlockStat s = BlockStat(kBlockStatString[eBlockStat_ThreeShapeEstimate], err); BlockStat s = BlockStat(kBlockStatString[eBlockStat_ThreeShapeEstimate], err);
statManager->AddStat(blockIdx, s); statManager.AddStat(blockIdx, s);
} }
// If it's small, we'll take it! // If it's small, we'll take it!
@ -2009,10 +2197,8 @@ namespace BC7C
CompressThreeClusters(i, clusters, outBuf, opaque); CompressThreeClusters(i, clusters, outBuf, opaque);
gBestMode = gModeChosen; gBestMode = gModeChosen;
if(statManager) { BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 2);
BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 2); statManager.AddStat(blockIdx, s);
statManager->AddStat(blockIdx, s);
}
return; return;
} }
@ -2027,10 +2213,8 @@ namespace BC7C
} }
} }
if(statManager) { BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 3);
BlockStat s = BlockStat(kBlockStatString[eBlockStat_Path], 3); statManager.AddStat(blockIdx, s);
statManager->AddStat(blockIdx, s);
}
uint8 tempBuf1[16], tempBuf2[16]; uint8 tempBuf1[16], tempBuf2[16];