From 26e816b3db68f1b79e89a7634fcf455f1d4b7b6c Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Fri, 21 Mar 2014 12:45:47 -0400 Subject: [PATCH] Add settings for BPTC compression --- BPTCEncoder/include/BPTCCompressor.h | 70 ++++++++++++++++++++++++++-- BPTCEncoder/src/Compressor.cpp | 25 ++++++---- Core/src/TexComp.cpp | 15 ++++-- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/BPTCEncoder/include/BPTCCompressor.h b/BPTCEncoder/include/BPTCCompressor.h index 4d69741..8d581c5 100755 --- a/BPTCEncoder/include/BPTCCompressor.h +++ b/BPTCEncoder/include/BPTCCompressor.h @@ -82,6 +82,67 @@ #include namespace BPTCC { + // The various available block modes that a BPTC compressor can choose from. + // The enum is specialized to be power-of-two values so that an EBlockMode + // variable can be used as a bit mask. + enum EBlockMode { + eBlockMode_Zero = 0, + eBlockMode_One = 1, + eBlockMode_Two = 2, + eBlockMode_Three = 4, + eBlockMode_Four = 8, + eBlockMode_Five = 16, + eBlockMode_Six = 32, + eBlockMode_Seven = 64 + }; + + // 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 + // partitioning schemes defined by the BPTC format. + struct ShapeSelection { + // This is the shape index to use when evaluating two-partition shapes. + uint32 m_TwoShapeIndex; + + // This is the shape index to use when evaluating three-partition shapes. + uint32 m_ThreeShapeIndex; + + // This is the additional mask to prevent modes once shape selection + // is done. This value is &-ed with m_BlockModes from CompressionSettings + // to determine what the final considered blocks are. + EBlockMode m_AdditionalModes; + }; + + // A shape selection function is one that selects a BPTC shape from a given + // block position and pixel array. + typedef ShapeSelection + (*ShapeSelectionFn)(uint32 x, uint32 y, uint32 pixels[16]); + + // Compression parameters used to control the BPTC compressor. Each of the + // values has a default, so this is not strictly required to perform + // compression, but some aspects of the compressor can be user-defined or + // overridden. + struct CompressionSettings { + // The shape selection function to use during compression. The default (when + // this variable is set to NULL) is to use the diagonal of the axis-aligned + // bounding box of every partition to estimate the error using that + // partition would accrue. The shape with the least error is then chosen. + // This procedure is done for both two and three partition shapes, and then + // every block mode is still available. + ShapeSelectionFn m_ShapeSelectionFn; + + // The block modes that the compressor will consider during compression. + // This variable is a bit mask of EBlockMode values and by default contains + // every mode. This setting can be used to further restrict the search space + // and increase compression times. + EBlockMode m_BlockModes; + + CompressionSettings() + : m_ShapeSelectionFn(NULL) + , m_BlockModes(static_cast((1 << 7) - 1)) + { } + }; + // 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 @@ -114,13 +175,15 @@ namespace BPTCC { // Compress the image given as RGBA data to BPTC format. Width and Height are // the dimensions of the image in pixels. - void Compress(const FasTC::CompressionJob &); + void Compress(const FasTC::CompressionJob &, + CompressionSettings settings = CompressionSettings()); // Perform a compression while recording all of the choices the compressor // made into a list of statistics. We can use this to see whether or not // certain heuristics are working, such as whether or not certain modes are // being chosen more often than others, etc. - void CompressWithStats(const FasTC::CompressionJob &, std::ostream *logStream); + void CompressWithStats(const FasTC::CompressionJob &, std::ostream *logStream, + CompressionSettings settings = CompressionSettings()); #ifdef HAS_SSE_41 // Compress the image given as RGBA data to BPTC format using an algorithm @@ -146,8 +209,7 @@ namespace BPTCC { std::ostream *logStream); #endif - // Decompress the image given as BPTC data to R8G8B8A8 format. Width and Height - // are the dimensions of the image in pixels. + // Decompress the image given as BPTC data to R8G8B8A8 format. void Decompress(const FasTC::DecompressionJob &); } // namespace BPTCC diff --git a/BPTCEncoder/src/Compressor.cpp b/BPTCEncoder/src/Compressor.cpp index decebfb..8cc866e 100755 --- a/BPTCEncoder/src/Compressor.cpp +++ b/BPTCEncoder/src/Compressor.cpp @@ -1553,9 +1553,13 @@ std::ostream &operator<<(const BlockLogger &bl, const T &v) { } // Function prototypes -static void CompressBC7Block(const uint32 *block, uint8 *outBuf); static void CompressBC7Block( - const uint32 *block, uint8 *outBuf, const BlockLogger &logStream + const uint32 block[16], uint8 *outBuf, + const CompressionSettings = CompressionSettings() +); +static void CompressBC7Block( + const uint32 block[16], uint8 *outBuf, const BlockLogger &logStream, + const CompressionSettings = CompressionSettings() ); static int gQualityLevel = 50; @@ -1638,7 +1642,7 @@ void GetBlock(const uint32 x, const uint32 y, const uint32 pixelsWide, // the size of the image in pixels. The buffer pointed to by outBuf should be // large enough to store the compressed image. This implementation has an 4:1 // compression ratio. -void Compress(const FasTC::CompressionJob &cj) { +void Compress(const FasTC::CompressionJob &cj, CompressionSettings settings) { const uint32 *inPixels = reinterpret_cast(cj.InBuf()); const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_BPTC); uint8 *outBuf = cj.OutBuf() + cj.CoordsToBlockIdx(cj.XStart(), cj.YStart()) * kBlockSz; @@ -1651,7 +1655,7 @@ void Compress(const FasTC::CompressionJob &cj) { uint32 block[16]; GetBlock(i, j, cj.Width(), inPixels, block); - CompressBC7Block(block, outBuf); + CompressBC7Block(block, outBuf, settings); #ifndef NDEBUG const uint8 *inBlock = reinterpret_cast(block); @@ -1740,7 +1744,8 @@ void CompressAtomic(FasTC::CompressionJobList &cjl) { } #endif // HAS_ATOMICS -void CompressWithStats(const FasTC::CompressionJob &cj, std::ostream *logStream) { + void CompressWithStats(const FasTC::CompressionJob &cj, std::ostream *logStream, + CompressionSettings settings) { const uint32 *inPixels = reinterpret_cast(cj.InBuf()); const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_BPTC); uint8 *outBuf = cj.OutBuf() + cj.CoordsToBlockIdx(cj.XStart(), cj.YStart()) * kBlockSz; @@ -1755,9 +1760,9 @@ void CompressWithStats(const FasTC::CompressionJob &cj, std::ostream *logStream) if(logStream) { uint64 blockIdx = cj.CoordsToBlockIdx(i, j); - CompressBC7Block(block, outBuf, BlockLogger(blockIdx, *logStream)); + CompressBC7Block(block, outBuf, BlockLogger(blockIdx, *logStream), settings); } else { - CompressBC7Block(block, outBuf); + CompressBC7Block(block, outBuf, settings); } #ifndef NDEBUG @@ -1992,7 +1997,8 @@ static double EstimateThreeClusterError(RGBACluster &c) { return error; } -static void CompressBC7Block(const uint32 *block, uint8 *outBuf) { +static void CompressBC7Block(const uint32 block[16], uint8 *outBuf, + const CompressionSettings settings) { // All a single color? if(AllOneColor(block)) { BitStream bStrm(outBuf, 128, 0); @@ -2253,7 +2259,8 @@ static void PrintStat(const BlockLogger &lgr, const char *stat, const T &v) { // Compress a single block but collect statistics as well... static void CompressBC7Block( - const uint32 *block, uint8 *outBuf, const BlockLogger &logStream + const uint32 block[16], uint8 *outBuf, const BlockLogger &logStream, + const CompressionSettings settings ) { class RAIIStatSaver { diff --git a/Core/src/TexComp.cpp b/Core/src/TexComp.cpp index 9cd6d5f..43d1bdc 100644 --- a/Core/src/TexComp.cpp +++ b/Core/src/TexComp.cpp @@ -76,6 +76,15 @@ static inline T sad(const T &a, const T &b) { return (a > b)? a - b : b - a; } +static void CompressBPTC(const CompressionJob &cj) { + BPTCC::Compress(cj); +} + +static void CompressBPTCWithStats(const CompressionJob &cj, + std::ostream *strm) { + BPTCC::CompressWithStats(cj, strm); +} + static void CompressPVRTC(const CompressionJob &cj) { PVRTCC::Compress(cj); } @@ -109,7 +118,7 @@ static CompressionFuncWithStats ChooseFuncFromSettingsWithStats(const SCompress return BPTCC::CompressNVTTWithStats; else #endif - return BPTCC::CompressWithStats; + return CompressBPTCWithStats; } break; @@ -138,7 +147,7 @@ static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) { return BPTCC::CompressNVTT; else #endif - return BPTCC::Compress; + return CompressBPTC; } break; @@ -223,7 +232,7 @@ class AtomicThreadUnit : public TCCallable { virtual ~AtomicThreadUnit() { } virtual void operator()() { m_Barrier->Wait(); - if(m_CmpFnc == BPTCC::Compress) { + if(m_CmpFnc == CompressBPTC) { BPTCC::CompressAtomic(m_CompressionJobList); } else {