Move the other BPTC settings into the settings struct

This commit is contained in:
Pavel Krajcevski 2014-03-22 19:52:58 -04:00
parent 9144db4de6
commit 220a736a36
4 changed files with 64 additions and 69 deletions

View File

@ -96,6 +96,19 @@ namespace BPTCC {
eBlockMode_Seven = 128
};
// This is the error metric that is applied to our error measurement algorithm
// in order to bias calculation towards results that are more in-line with
// how the Human Visual System works. Uniform error means that each color
// channel is treated equally. For a while, the widely accepted non-uniform
// metric has been to give red 30%, green 59% and blue 11% weight when
// computing the error between two pixels.
enum ErrorMetric {
eErrorMetric_Uniform, // Treats r, g, and b channels equally
eErrorMetric_Nonuniform, // { 0.3, 0.59, 0.11 }
kNumErrorMetrics
};
// A shape selection can influence the results of the compressor by choosing
// different modes to compress or not compress. The shape index is a value
// between zero and sixty-four that corresponds to one of the available
@ -137,7 +150,7 @@ namespace BPTCC {
ShapeSelectionFn m_ShapeSelectionFn;
// The user data passed to the shape selection function.
void *m_ShapeSelectionUserData;
const void *m_ShapeSelectionUserData;
// The block modes that the compressor will consider during compression.
// This variable is a bit mask of EBlockMode values and by default contains
@ -145,42 +158,28 @@ namespace BPTCC {
// and increase compression times.
uint32 m_BlockModes;
// See the description for ErrorMetric.
ErrorMetric m_ErrorMetric;
// The number of simulated annealing steps to perform per refinement
// iteration. In general, a larger number produces better results. The
// default is set to 50. This metric works on a logarithmic scale -- twice
// the value will double the compute time, but only decrease the error by
// two times a factor.
uint32 m_NumSimulatedAnnealingSteps;
CompressionSettings()
: m_ShapeSelectionFn(NULL)
, m_ShapeSelectionUserData(NULL)
, m_BlockModes(static_cast<EBlockMode>(0xFF))
, m_ErrorMetric(eErrorMetric_Uniform)
, m_NumSimulatedAnnealingSteps(50)
{ }
};
// This is the error metric that is applied to our error measurement algorithm
// in order to bias calculation towards results that are more in-line with
// how the Human Visual System works. Uniform error means that each color
// channel is treated equally. For a while, the widely accepted non-uniform
// metric has been to give red 30%, green 59% and blue 11% weight when
// computing the error between two pixels.
enum ErrorMetric {
eErrorMetric_Uniform, // Treats r, g, and b channels equally
eErrorMetric_Nonuniform, // { 0.3, 0.59, 0.11 }
kNumErrorMetrics
};
// Sets the error metric to be the one specified.
void SetErrorMetric(ErrorMetric e);
// Retreives a float4 pointer for the r, g, b, a weights for each color
// channel, in that order, based on the current error metric.
const float *GetErrorMetric();
// Returns the enumeration for the current error metric.
ErrorMetric GetErrorMetricEnum();
// Sets the number of steps that we use to perform simulated annealing. In
// general, a larger number produces better results. The default is set to 50.
// This metric works on a logarithmic scale -- twice the value will double the
// compute time, but only decrease the error by two times a factor.
void SetQualityLevel(int q);
int GetQualityLevel();
// channel, in that order.
const float *GetErrorMetric(ErrorMetric e);
// Compress the image given as RGBA data to BPTC format. Width and Height are
// the dimensions of the image in pixels.

View File

@ -105,9 +105,10 @@ class CompressionMode {
// This initializes the compression variables used in order to compress a list
// of clusters. We can increase the speed a tad by specifying whether or not
// the block is opaque or not.
explicit CompressionMode(int mode)
explicit CompressionMode(int mode, ErrorMetric metric)
: m_IsOpaque(mode < 4)
, m_Attributes(&(kModeAttributes[mode]))
, m_ErrorMetric(metric)
, m_RotateMode(0)
, m_IndexMode(0)
{ }
@ -184,6 +185,7 @@ class CompressionMode {
const double m_IsOpaque;
const Attributes *const m_Attributes;
ErrorMetric m_ErrorMetric;
int m_RotateMode;
int m_IndexMode;
@ -224,7 +226,7 @@ class CompressionMode {
// This returns the proper error metric even if we have rotation bits set
RGBAVector GetErrorMetric() const {
const float *w = BPTCC::GetErrorMetric();
const float *w = BPTCC::GetErrorMetric(m_ErrorMetric);
switch(GetRotationMode()) {
default:
case 0: return RGBAVector(w[0], w[1], w[2], w[3]);

View File

@ -419,7 +419,7 @@ double CompressionMode::CompressSingleColor(
dist[ci] = std::max(bestChannelDist, dist[ci]);
}
const float *errorWeights = BPTCC::GetErrorMetric();
const float *errorWeights = BPTCC::GetErrorMetric(this->m_ErrorMetric);
float error = 0.0;
for(uint32 i = 0; i < kNumColorChannels; i++) {
float e = static_cast<float>(dist[i]) * errorWeights[i];
@ -1461,16 +1461,12 @@ double CompressionMode::Compress(
return totalErr;
}
static ErrorMetric gErrorMetric = eErrorMetric_Uniform;
void SetErrorMetric(ErrorMetric e) { gErrorMetric = e; }
ALIGN_SSE const float kErrorMetrics[kNumErrorMetrics][kNumColorChannels] = {
{ 1.0f, 1.0f, 1.0f, 1.0f },
{ sqrtf(0.3f), sqrtf(0.56f), sqrtf(0.11f), 1.0f }
};
const float *GetErrorMetric() { return kErrorMetrics[GetErrorMetricEnum()]; }
ErrorMetric GetErrorMetricEnum() { return gErrorMetric; }
const float *GetErrorMetric(ErrorMetric e) { return kErrorMetrics[e]; }
class BlockLogger {
public:
@ -1503,15 +1499,6 @@ static void CompressBC7Block(
const CompressionSettings = CompressionSettings()
);
static int gQualityLevel = 50;
void SetQualityLevel(int q) {
gQualityLevel = std::max(0, q);
const int kMaxIters = CompressionMode::kMaxAnnealingIterations;
CompressionMode::MaxAnnealingIterations =
std::min(kMaxIters, GetQualityLevel());
}
int GetQualityLevel() { return gQualityLevel; }
// Returns true if the entire block is a single color.
static bool AllOneColor(const uint32 block[16]) {
const uint32 pixel = block[0];
@ -1732,7 +1719,7 @@ void CompressAtomic(FasTC::CompressionJobList &cjl) {
}
}
static double EstimateTwoClusterError(RGBACluster &c) {
static double EstimateTwoClusterError(ErrorMetric metric, RGBACluster &c) {
RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max);
v = Max - Min;
@ -1740,7 +1727,7 @@ static double EstimateTwoClusterError(RGBACluster &c) {
return 0.0;
}
const float *w = BPTCC::GetErrorMetric();
const float *w = BPTCC::GetErrorMetric(metric);
double error = 0.0001;
error += c.QuantizedError(Min, Max, 8,
@ -1748,7 +1735,7 @@ static double EstimateTwoClusterError(RGBACluster &c) {
return error;
}
static double EstimateThreeClusterError(RGBACluster &c) {
static double EstimateThreeClusterError(ErrorMetric metric, RGBACluster &c) {
RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max);
v = Max - Min;
@ -1756,8 +1743,7 @@ static double EstimateThreeClusterError(RGBACluster &c) {
return 0.0;
}
const float *w = BPTCC::GetErrorMetric();
const float *w = BPTCC::GetErrorMetric(metric);
double error = 0.0001;
error += c.QuantizedError(Min, Max, 4,
0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
@ -1778,9 +1764,10 @@ static uint32 kAlphaModes =
static_cast<uint32>(eBlockMode_Seven);
static ShapeSelection BoxSelection(
uint32, uint32, const uint32 pixels[16], const void *
uint32, uint32, const uint32 pixels[16], const void *userData
) {
ErrorMetric metric = *(reinterpret_cast<const ErrorMetric *>(userData));
ShapeSelection result;
bool opaque = true;
@ -1802,7 +1789,7 @@ static ShapeSelection BoxSelection(
double err = 0.0;
for(int ci = 0; ci < 2; ci++) {
cluster.SetPartition(ci);
err += EstimateTwoClusterError(cluster);
err += EstimateTwoClusterError(metric, cluster);
}
if(err < bestError[0]) {
@ -1826,7 +1813,7 @@ static ShapeSelection BoxSelection(
double err = 0.0;
for(int ci = 0; ci < 3; ci++) {
cluster.SetPartition(ci);
err += EstimateThreeClusterError(cluster);
err += EstimateThreeClusterError(metric, cluster);
}
if(err < bestError[1]) {
@ -1856,7 +1843,8 @@ static ShapeSelection BoxSelection(
}
static void CompressClusters(ShapeSelection selection, const uint32 pixels[16],
uint8 *outBuf, double *errors, int *modeChosen) {
ErrorMetric metric, uint8 *outBuf,
double *errors, int *modeChosen) {
RGBACluster cluster(pixels);
uint8 tmpBuf[16];
double bestError = std::numeric_limits<double>::max();
@ -1887,7 +1875,7 @@ static void CompressClusters(ShapeSelection selection, const uint32 pixels[16],
shape, CompressionMode::GetAttributesForMode(mode)->numSubsets);
BitStream tmpStream(tmpBuf, 128, 0);
double error = CompressionMode(mode).Compress(tmpStream, shape, cluster);
double error = CompressionMode(mode, metric).Compress(tmpStream, shape, cluster);
if(errors)
errors[mode] = error;
@ -1929,20 +1917,22 @@ static void CompressBC7Block(const uint32 x, const uint32 y,
}
ShapeSelectionFn selectionFn = BoxSelection;
const void *userData = &settings.m_ErrorMetric;
if(settings.m_ShapeSelectionFn != NULL) {
selectionFn = settings.m_ShapeSelectionFn;
userData = settings.m_ShapeSelectionUserData;
}
assert(selectionFn);
ShapeSelection selection =
selectionFn(x, y, block, settings.m_ShapeSelectionUserData);
selectionFn(x, y, block, userData);
selection.m_SelectedModes &= settings.m_BlockModes;
assert(selection.m_SelectedModes);
CompressClusters(selection, block, outBuf, NULL, NULL);
CompressClusters(selection, block, settings.m_ErrorMetric, outBuf, NULL, NULL);
}
static double EstimateTwoClusterErrorStats(
RGBACluster &c, double (&estimates)[2]
ErrorMetric metric, RGBACluster &c, double (&estimates)[2]
) {
RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max);
@ -1952,7 +1942,7 @@ static double EstimateTwoClusterErrorStats(
return 0.0;
}
const float *w = BPTCC::GetErrorMetric();
const float *w = BPTCC::GetErrorMetric(metric);
const double err1 = c.QuantizedError(
Min, Max, 8, 0xFFFCFCFC, RGBAVector(w[0], w[1], w[2], w[3])
@ -1980,7 +1970,7 @@ static double EstimateTwoClusterErrorStats(
}
static double EstimateThreeClusterErrorStats(
RGBACluster &c, double (&estimates)[2]
ErrorMetric metric, RGBACluster &c, double (&estimates)[2]
) {
RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max);
@ -1990,7 +1980,7 @@ static double EstimateThreeClusterErrorStats(
return 0.0;
}
const float *w = BPTCC::GetErrorMetric();
const float *w = BPTCC::GetErrorMetric(metric);
const double err0 = 0.0001 + c.QuantizedError(
Min, Max, 4, 0xFFF0F0F0, RGBAVector(w[0], w[1], w[2], w[3])
);
@ -2134,7 +2124,7 @@ static void CompressBC7Block(
if(v * v == 0) {
modeEstimate[6] = 0.0;
} else {
const float *w = GetErrorMetric();
const float *w = GetErrorMetric(settings.m_ErrorMetric);
const double err = 0.0001 + blockCluster.QuantizedError(
Min, Max, 4, 0xFEFEFEFE, RGBAVector(w[0], w[1], w[2], w[3])
);
@ -2157,7 +2147,8 @@ static void CompressBC7Block(
for(int ci = 0; ci < 2; ci++) {
blockCluster.SetPartition(ci);
double shapeEstimate[2] = { -1.0, -1.0 };
err += EstimateTwoClusterErrorStats(blockCluster, shapeEstimate);
err += EstimateTwoClusterErrorStats(settings.m_ErrorMetric,
blockCluster, shapeEstimate);
for(int ei = 0; ei < 2; ei++) {
if(shapeEstimate[ei] >= 0.0) {
@ -2209,7 +2200,8 @@ static void CompressBC7Block(
for(int ci = 0; ci < 3; ci++) {
blockCluster.SetPartition(ci);
double shapeEstimate[2] = { -1.0, -1.0 };
err += EstimateThreeClusterErrorStats(blockCluster, shapeEstimate);
err += EstimateThreeClusterErrorStats(settings.m_ErrorMetric,
blockCluster, shapeEstimate);
for(int ei = 0; ei < 2; ei++) {
if(shapeEstimate[ei] >= 0.0) {
@ -2255,7 +2247,8 @@ static void CompressBC7Block(
selection.m_SelectedModes &= settings.m_BlockModes;
assert(selection.m_SelectedModes);
CompressClusters(selection, block, outBuf, modeError, &bestMode);
ErrorMetric metric = settings.m_ErrorMetric;
CompressClusters(selection, block, metric, outBuf, modeError, &bestMode);
PrintStat(logStream, kBlockStatString[eBlockStat_Path], path);
}

View File

@ -76,13 +76,14 @@ static inline T sad(const T &a, const T &b) {
return (a > b)? a - b : b - a;
}
static BPTCC::CompressionSettings gBPTCSettings;
static void CompressBPTC(const CompressionJob &cj) {
BPTCC::Compress(cj);
BPTCC::Compress(cj, gBPTCSettings);
}
static void CompressBPTCWithStats(const CompressionJob &cj,
std::ostream *strm) {
BPTCC::CompressWithStats(cj, strm);
BPTCC::CompressWithStats(cj, strm, gBPTCSettings);
}
static void CompressPVRTC(const CompressionJob &cj) {
@ -135,7 +136,7 @@ static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) {
switch(s.format) {
case FasTC::eCompressionFormat_BPTC:
{
BPTCC::SetQualityLevel(s.iQuality);
gBPTCSettings.m_NumSimulatedAnnealingSteps = s.iQuality;
#ifdef HAS_SSE_41
if(s.bUseSIMD) {
return BPTCC::CompressImageBPTCSIMD;