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 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 // 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 // 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 // between zero and sixty-four that corresponds to one of the available
@ -137,7 +150,7 @@ namespace BPTCC {
ShapeSelectionFn m_ShapeSelectionFn; ShapeSelectionFn m_ShapeSelectionFn;
// The user data passed to the shape selection function. // 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. // The block modes that the compressor will consider during compression.
// This variable is a bit mask of EBlockMode values and by default contains // This variable is a bit mask of EBlockMode values and by default contains
@ -145,42 +158,28 @@ namespace BPTCC {
// and increase compression times. // and increase compression times.
uint32 m_BlockModes; 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() CompressionSettings()
: m_ShapeSelectionFn(NULL) : m_ShapeSelectionFn(NULL)
, m_ShapeSelectionUserData(NULL) , m_ShapeSelectionUserData(NULL)
, m_BlockModes(static_cast<EBlockMode>(0xFF)) , 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 // Retreives a float4 pointer for the r, g, b, a weights for each color
// channel, in that order, based on the current error metric. // channel, in that order.
const float *GetErrorMetric(); const float *GetErrorMetric(ErrorMetric e);
// 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();
// Compress the image given as RGBA data to BPTC format. Width and Height are // Compress the image given as RGBA data to BPTC format. Width and Height are
// the dimensions of the image in pixels. // 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 // 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 // of clusters. We can increase the speed a tad by specifying whether or not
// the block is opaque or not. // the block is opaque or not.
explicit CompressionMode(int mode) explicit CompressionMode(int mode, ErrorMetric metric)
: m_IsOpaque(mode < 4) : m_IsOpaque(mode < 4)
, m_Attributes(&(kModeAttributes[mode])) , m_Attributes(&(kModeAttributes[mode]))
, m_ErrorMetric(metric)
, m_RotateMode(0) , m_RotateMode(0)
, m_IndexMode(0) , m_IndexMode(0)
{ } { }
@ -184,6 +185,7 @@ class CompressionMode {
const double m_IsOpaque; const double m_IsOpaque;
const Attributes *const m_Attributes; const Attributes *const m_Attributes;
ErrorMetric m_ErrorMetric;
int m_RotateMode; int m_RotateMode;
int m_IndexMode; int m_IndexMode;
@ -224,7 +226,7 @@ class CompressionMode {
// This returns the proper error metric even if we have rotation bits set // This returns the proper error metric even if we have rotation bits set
RGBAVector GetErrorMetric() const { RGBAVector GetErrorMetric() const {
const float *w = BPTCC::GetErrorMetric(); const float *w = BPTCC::GetErrorMetric(m_ErrorMetric);
switch(GetRotationMode()) { switch(GetRotationMode()) {
default: default:
case 0: return RGBAVector(w[0], w[1], w[2], w[3]); 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]); dist[ci] = std::max(bestChannelDist, dist[ci]);
} }
const float *errorWeights = BPTCC::GetErrorMetric(); const float *errorWeights = BPTCC::GetErrorMetric(this->m_ErrorMetric);
float error = 0.0; float error = 0.0;
for(uint32 i = 0; i < kNumColorChannels; i++) { for(uint32 i = 0; i < kNumColorChannels; i++) {
float e = static_cast<float>(dist[i]) * errorWeights[i]; float e = static_cast<float>(dist[i]) * errorWeights[i];
@ -1461,16 +1461,12 @@ double CompressionMode::Compress(
return totalErr; return totalErr;
} }
static ErrorMetric gErrorMetric = eErrorMetric_Uniform;
void SetErrorMetric(ErrorMetric e) { gErrorMetric = e; }
ALIGN_SSE const float kErrorMetrics[kNumErrorMetrics][kNumColorChannels] = { ALIGN_SSE const float kErrorMetrics[kNumErrorMetrics][kNumColorChannels] = {
{ 1.0f, 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f },
{ sqrtf(0.3f), sqrtf(0.56f), sqrtf(0.11f), 1.0f } { sqrtf(0.3f), sqrtf(0.56f), sqrtf(0.11f), 1.0f }
}; };
const float *GetErrorMetric() { return kErrorMetrics[GetErrorMetricEnum()]; } const float *GetErrorMetric(ErrorMetric e) { return kErrorMetrics[e]; }
ErrorMetric GetErrorMetricEnum() { return gErrorMetric; }
class BlockLogger { class BlockLogger {
public: public:
@ -1503,15 +1499,6 @@ static void CompressBC7Block(
const CompressionSettings = CompressionSettings() 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. // Returns true if the entire block is a single color.
static bool AllOneColor(const uint32 block[16]) { static bool AllOneColor(const uint32 block[16]) {
const uint32 pixel = block[0]; 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; RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max); c.GetBoundingBox(Min, Max);
v = Max - Min; v = Max - Min;
@ -1740,7 +1727,7 @@ static double EstimateTwoClusterError(RGBACluster &c) {
return 0.0; return 0.0;
} }
const float *w = BPTCC::GetErrorMetric(); const float *w = BPTCC::GetErrorMetric(metric);
double error = 0.0001; double error = 0.0001;
error += c.QuantizedError(Min, Max, 8, error += c.QuantizedError(Min, Max, 8,
@ -1748,7 +1735,7 @@ static double EstimateTwoClusterError(RGBACluster &c) {
return error; return error;
} }
static double EstimateThreeClusterError(RGBACluster &c) { static double EstimateThreeClusterError(ErrorMetric metric, RGBACluster &c) {
RGBAVector Min, Max, v; RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max); c.GetBoundingBox(Min, Max);
v = Max - Min; v = Max - Min;
@ -1756,8 +1743,7 @@ static double EstimateThreeClusterError(RGBACluster &c) {
return 0.0; return 0.0;
} }
const float *w = BPTCC::GetErrorMetric(); const float *w = BPTCC::GetErrorMetric(metric);
double error = 0.0001; double error = 0.0001;
error += c.QuantizedError(Min, Max, 4, error += c.QuantizedError(Min, Max, 4,
0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3])); 0xFFFFFFFF, RGBAVector(w[0], w[1], w[2], w[3]));
@ -1778,9 +1764,10 @@ static uint32 kAlphaModes =
static_cast<uint32>(eBlockMode_Seven); static_cast<uint32>(eBlockMode_Seven);
static ShapeSelection BoxSelection( 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; ShapeSelection result;
bool opaque = true; bool opaque = true;
@ -1802,7 +1789,7 @@ static ShapeSelection BoxSelection(
double err = 0.0; double err = 0.0;
for(int ci = 0; ci < 2; ci++) { for(int ci = 0; ci < 2; ci++) {
cluster.SetPartition(ci); cluster.SetPartition(ci);
err += EstimateTwoClusterError(cluster); err += EstimateTwoClusterError(metric, cluster);
} }
if(err < bestError[0]) { if(err < bestError[0]) {
@ -1826,7 +1813,7 @@ static ShapeSelection BoxSelection(
double err = 0.0; double err = 0.0;
for(int ci = 0; ci < 3; ci++) { for(int ci = 0; ci < 3; ci++) {
cluster.SetPartition(ci); cluster.SetPartition(ci);
err += EstimateThreeClusterError(cluster); err += EstimateThreeClusterError(metric, cluster);
} }
if(err < bestError[1]) { if(err < bestError[1]) {
@ -1856,7 +1843,8 @@ static ShapeSelection BoxSelection(
} }
static void CompressClusters(ShapeSelection selection, const uint32 pixels[16], 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); RGBACluster cluster(pixels);
uint8 tmpBuf[16]; uint8 tmpBuf[16];
double bestError = std::numeric_limits<double>::max(); 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); shape, CompressionMode::GetAttributesForMode(mode)->numSubsets);
BitStream tmpStream(tmpBuf, 128, 0); BitStream tmpStream(tmpBuf, 128, 0);
double error = CompressionMode(mode).Compress(tmpStream, shape, cluster); double error = CompressionMode(mode, metric).Compress(tmpStream, shape, cluster);
if(errors) if(errors)
errors[mode] = error; errors[mode] = error;
@ -1929,20 +1917,22 @@ static void CompressBC7Block(const uint32 x, const uint32 y,
} }
ShapeSelectionFn selectionFn = BoxSelection; ShapeSelectionFn selectionFn = BoxSelection;
const void *userData = &settings.m_ErrorMetric;
if(settings.m_ShapeSelectionFn != NULL) { if(settings.m_ShapeSelectionFn != NULL) {
selectionFn = settings.m_ShapeSelectionFn; selectionFn = settings.m_ShapeSelectionFn;
userData = settings.m_ShapeSelectionUserData;
} }
assert(selectionFn); assert(selectionFn);
ShapeSelection selection = ShapeSelection selection =
selectionFn(x, y, block, settings.m_ShapeSelectionUserData); selectionFn(x, y, block, userData);
selection.m_SelectedModes &= settings.m_BlockModes; selection.m_SelectedModes &= settings.m_BlockModes;
assert(selection.m_SelectedModes); assert(selection.m_SelectedModes);
CompressClusters(selection, block, outBuf, NULL, NULL); CompressClusters(selection, block, settings.m_ErrorMetric, outBuf, NULL, NULL);
} }
static double EstimateTwoClusterErrorStats( static double EstimateTwoClusterErrorStats(
RGBACluster &c, double (&estimates)[2] ErrorMetric metric, RGBACluster &c, double (&estimates)[2]
) { ) {
RGBAVector Min, Max, v; RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max); c.GetBoundingBox(Min, Max);
@ -1952,7 +1942,7 @@ static double EstimateTwoClusterErrorStats(
return 0.0; return 0.0;
} }
const float *w = BPTCC::GetErrorMetric(); const float *w = BPTCC::GetErrorMetric(metric);
const double err1 = c.QuantizedError( const double err1 = c.QuantizedError(
Min, Max, 8, 0xFFFCFCFC, RGBAVector(w[0], w[1], w[2], w[3]) Min, Max, 8, 0xFFFCFCFC, RGBAVector(w[0], w[1], w[2], w[3])
@ -1980,7 +1970,7 @@ static double EstimateTwoClusterErrorStats(
} }
static double EstimateThreeClusterErrorStats( static double EstimateThreeClusterErrorStats(
RGBACluster &c, double (&estimates)[2] ErrorMetric metric, RGBACluster &c, double (&estimates)[2]
) { ) {
RGBAVector Min, Max, v; RGBAVector Min, Max, v;
c.GetBoundingBox(Min, Max); c.GetBoundingBox(Min, Max);
@ -1990,7 +1980,7 @@ static double EstimateThreeClusterErrorStats(
return 0.0; return 0.0;
} }
const float *w = BPTCC::GetErrorMetric(); const float *w = BPTCC::GetErrorMetric(metric);
const double err0 = 0.0001 + c.QuantizedError( const double err0 = 0.0001 + c.QuantizedError(
Min, Max, 4, 0xFFF0F0F0, RGBAVector(w[0], w[1], w[2], w[3]) Min, Max, 4, 0xFFF0F0F0, RGBAVector(w[0], w[1], w[2], w[3])
); );
@ -2134,7 +2124,7 @@ static void CompressBC7Block(
if(v * v == 0) { if(v * v == 0) {
modeEstimate[6] = 0.0; modeEstimate[6] = 0.0;
} else { } else {
const float *w = GetErrorMetric(); const float *w = GetErrorMetric(settings.m_ErrorMetric);
const double err = 0.0001 + blockCluster.QuantizedError( const double err = 0.0001 + blockCluster.QuantizedError(
Min, Max, 4, 0xFEFEFEFE, RGBAVector(w[0], w[1], w[2], w[3]) 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++) { for(int ci = 0; ci < 2; ci++) {
blockCluster.SetPartition(ci); blockCluster.SetPartition(ci);
double shapeEstimate[2] = { -1.0, -1.0 }; 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++) { for(int ei = 0; ei < 2; ei++) {
if(shapeEstimate[ei] >= 0.0) { if(shapeEstimate[ei] >= 0.0) {
@ -2209,7 +2200,8 @@ static void CompressBC7Block(
for(int ci = 0; ci < 3; ci++) { for(int ci = 0; ci < 3; ci++) {
blockCluster.SetPartition(ci); blockCluster.SetPartition(ci);
double shapeEstimate[2] = { -1.0, -1.0 }; 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++) { for(int ei = 0; ei < 2; ei++) {
if(shapeEstimate[ei] >= 0.0) { if(shapeEstimate[ei] >= 0.0) {
@ -2255,7 +2247,8 @@ static void CompressBC7Block(
selection.m_SelectedModes &= settings.m_BlockModes; selection.m_SelectedModes &= settings.m_BlockModes;
assert(selection.m_SelectedModes); 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); 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; return (a > b)? a - b : b - a;
} }
static BPTCC::CompressionSettings gBPTCSettings;
static void CompressBPTC(const CompressionJob &cj) { static void CompressBPTC(const CompressionJob &cj) {
BPTCC::Compress(cj); BPTCC::Compress(cj, gBPTCSettings);
} }
static void CompressBPTCWithStats(const CompressionJob &cj, static void CompressBPTCWithStats(const CompressionJob &cj,
std::ostream *strm) { std::ostream *strm) {
BPTCC::CompressWithStats(cj, strm); BPTCC::CompressWithStats(cj, strm, gBPTCSettings);
} }
static void CompressPVRTC(const CompressionJob &cj) { static void CompressPVRTC(const CompressionJob &cj) {
@ -135,7 +136,7 @@ static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) {
switch(s.format) { switch(s.format) {
case FasTC::eCompressionFormat_BPTC: case FasTC::eCompressionFormat_BPTC:
{ {
BPTCC::SetQualityLevel(s.iQuality); gBPTCSettings.m_NumSimulatedAnnealingSteps = s.iQuality;
#ifdef HAS_SSE_41 #ifdef HAS_SSE_41
if(s.bUseSIMD) { if(s.bUseSIMD) {
return BPTCC::CompressImageBPTCSIMD; return BPTCC::CompressImageBPTCSIMD;