From 220a736a36bad6f8d169ea2be8373ecc02d50406 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Sat, 22 Mar 2014 19:52:58 -0400 Subject: [PATCH] Move the other BPTC settings into the settings struct --- BPTCEncoder/include/BPTCCompressor.h | 57 +++++++++++++------------ BPTCEncoder/src/CompressionMode.h | 6 ++- BPTCEncoder/src/Compressor.cpp | 63 +++++++++++++--------------- Core/src/TexComp.cpp | 7 ++-- 4 files changed, 64 insertions(+), 69 deletions(-) diff --git a/BPTCEncoder/include/BPTCCompressor.h b/BPTCEncoder/include/BPTCCompressor.h index 423f28e..c1b23db 100755 --- a/BPTCEncoder/include/BPTCCompressor.h +++ b/BPTCEncoder/include/BPTCCompressor.h @@ -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(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. diff --git a/BPTCEncoder/src/CompressionMode.h b/BPTCEncoder/src/CompressionMode.h index bd70ca2..693ea40 100755 --- a/BPTCEncoder/src/CompressionMode.h +++ b/BPTCEncoder/src/CompressionMode.h @@ -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]); diff --git a/BPTCEncoder/src/Compressor.cpp b/BPTCEncoder/src/Compressor.cpp index 777d1cb..f264796 100755 --- a/BPTCEncoder/src/Compressor.cpp +++ b/BPTCEncoder/src/Compressor.cpp @@ -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(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(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(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::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); } diff --git a/Core/src/TexComp.cpp b/Core/src/TexComp.cpp index 43d1bdc..d85faae 100644 --- a/Core/src/TexComp.cpp +++ b/Core/src/TexComp.cpp @@ -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;