#include "TexComp.h" #include #include #include #include #include "BC7Compressor.h" #include "WorkerQueue.h" #include "ThreadGroup.h" #include "ImageFile.h" #include "Image.h" template static T min(const T &a, const T &b) { return (a < b)? a : b; } template static T max(const T &a, const T &b) { return (a > b)? a : b; } template static void clamp(T &x, const T &minX, const T &maxX) { x = max(min(maxX, x), minX); } template static inline T sad(const T &a, const T &b) { return (a > b)? a - b : b - a; } SCompressionSettings:: SCompressionSettings() : format(eCompressionFormat_BPTC) , bUseSIMD(false) , iNumThreads(1) , iQuality(50) , iNumCompressions(1) { clamp(iQuality, 0, 256); } static CompressionFuncWithStats ChooseFuncFromSettingsWithStats(const SCompressionSettings &s) { switch(s.format) { case eCompressionFormat_BPTC: { return BC7C::CompressImageBC7Stats; } break; } return NULL; } static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) { switch(s.format) { case eCompressionFormat_BPTC: { BC7C::SetQualityLevel(s.iQuality); #ifdef HAS_SSE_41 if(s.bUseSIMD) { return BC7C::CompressImageBC7SIMD; } else { #endif return BC7C::CompressImageBC7; #ifdef HAS_SSE_41 } #endif } break; } return NULL; } static void ReportError(const char *msg) { fprintf(stderr, "TexComp -- %s\n", msg); } static double CompressImageInSerial( const unsigned char *imgData, const unsigned int imgDataSz, const SCompressionSettings &settings, unsigned char *outBuf ) { CompressionFunc f = ChooseFuncFromSettings(settings); CompressionFuncWithStats fStats = ChooseFuncFromSettingsWithStats(settings); double cmpTimeTotal = 0.0; for(int i = 0; i < settings.iNumCompressions; i++) { StopWatch stopWatch = StopWatch(); stopWatch.Reset(); stopWatch.Start(); // !FIXME! We're assuming that we have 4x4 blocks here... if(fStats && settings.pStatManager) { (*fStats)(imgData, outBuf, imgDataSz / 16, 4, *(settings.pStatManager)); } else { (*f)(imgData, outBuf, imgDataSz / 16, 4); } stopWatch.Stop(); cmpTimeTotal += stopWatch.TimeInMilliseconds(); } double cmpTime = cmpTimeTotal / double(settings.iNumCompressions); return cmpTime; } static double CompressImageWithThreads( const unsigned char *imgData, const unsigned int imgDataSz, const SCompressionSettings &settings, unsigned char *outBuf ) { CompressionFunc f = ChooseFuncFromSettings(settings); ThreadGroup tgrp (settings.iNumThreads, imgData, imgDataSz, f, outBuf); if(!(tgrp.PrepareThreads())) { assert(!"Thread group failed to prepare threads?!"); return -1.0f; } double cmpTimeTotal = 0.0; for(int i = 0; i < settings.iNumCompressions; i++) { if(i > 0) tgrp.PrepareThreads(); tgrp.Start(); tgrp.Join(); StopWatch stopWatch = tgrp.GetStopWatch(); cmpTimeTotal += tgrp.GetStopWatch().TimeInMilliseconds(); } tgrp.CleanUpThreads(); double cmpTime = cmpTimeTotal / double(settings.iNumCompressions); return cmpTime; } static double CompressImageWithWorkerQueue( const unsigned char *imgData, const unsigned int imgDataSz, const SCompressionSettings &settings, unsigned char *outBuf ) { CompressionFunc f = ChooseFuncFromSettings(settings); WorkerQueue wq ( settings.iNumCompressions, settings.iNumThreads, settings.iJobSize, imgData, imgDataSz, f, outBuf ); wq.Run(); return wq.GetStopWatch().TimeInMilliseconds() / double(settings.iNumCompressions); } bool CompressImageData( const unsigned char *data, const unsigned int dataSz, unsigned char *cmpData, const unsigned int cmpDataSz, const SCompressionSettings &settings ) { // Make sure that platform supports SSE if they chose this // option... #ifndef HAS_SSE_41 if(settings.bUseSIMD) { ReportError("Platform does not support SIMD!\n"); return false; } #endif if(dataSz <= 0) { ReportError("No data sent to compress!"); return false; } // Allocate data based on the compression method int cmpDataSzNeeded = 0; switch(settings.format) { case eCompressionFormat_DXT1: cmpDataSzNeeded = dataSz / 8; case eCompressionFormat_DXT5: cmpDataSzNeeded = dataSz / 4; case eCompressionFormat_BPTC: cmpDataSzNeeded = dataSz / 4; } if(cmpDataSzNeeded == 0) { ReportError("Unknown compression format"); return false; } else if(cmpDataSzNeeded > cmpDataSz) { ReportError("Not enough space for compressed data!"); return false; } CompressionFunc f = ChooseFuncFromSettings(settings); if(f) { double cmpMSTime = 0.0; if(settings.iNumThreads > 1) { if(settings.iJobSize > 0) cmpMSTime = CompressImageWithWorkerQueue(data, dataSz, settings, cmpData); else cmpMSTime = CompressImageWithThreads(data, dataSz, settings, cmpData); } else { cmpMSTime = CompressImageInSerial(data, dataSz, settings, cmpData); } // Report compression time fprintf(stdout, "Compression time: %0.3f ms\n", cmpMSTime); } else { ReportError("Could not find adequate compression function for specified settings"); return false; } return true; }