Merge branch 'master' into DecompressASTC

This commit is contained in:
Pavel Krajcevski 2014-11-03 18:28:44 -05:00
commit 168c6a0071
3 changed files with 131 additions and 104 deletions

View File

@ -111,13 +111,14 @@ void ExtractBasename(const char *filename, char *buf, size_t bufSz) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
int fileArg = 1; int fileArg = 1;
if(fileArg == argc) { if (fileArg == argc) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} }
char decompressedOutput[256]; decompressedOutput[0] = '\0'; char decompressedOutput[256];
bool bNoDecompress = false; decompressedOutput[0] = '\0';
bool bDecompress = true;
int numJobs = 0; int numJobs = 0;
int quality = 50; int quality = 50;
int numThreads = 1; int numThreads = 1;
@ -134,10 +135,10 @@ int main(int argc, char **argv) {
do { do {
knowArg = false; knowArg = false;
if(strcmp(argv[fileArg], "-n") == 0) { if (strcmp(argv[fileArg], "-n") == 0) {
fileArg++; fileArg++;
if(fileArg == argc || (numCompressions = atoi(argv[fileArg])) < 0) { if (fileArg == argc || (numCompressions = atoi(argv[fileArg])) < 0) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} }
@ -147,26 +148,26 @@ int main(int argc, char **argv) {
continue; continue;
} }
if(strcmp(argv[fileArg], "-f") == 0) { if (strcmp(argv[fileArg], "-f") == 0) {
fileArg++; fileArg++;
if(fileArg == argc) { if (fileArg == argc) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} else { } else {
if(!strcmp(argv[fileArg], "PVRTC")) { if (!strcmp(argv[fileArg], "PVRTC")) {
format = FasTC::eCompressionFormat_PVRTC4; format = FasTC::eCompressionFormat_PVRTC4;
} else if(!strcmp(argv[fileArg], "PVRTCLib")) { } else if (!strcmp(argv[fileArg], "PVRTCLib")) {
format = FasTC::eCompressionFormat_PVRTC4; format = FasTC::eCompressionFormat_PVRTC4;
bUsePVRTexLib = true; bUsePVRTexLib = true;
} else if(!strcmp(argv[fileArg], "BPTCLib")) { } else if (!strcmp(argv[fileArg], "BPTCLib")) {
format = FasTC::eCompressionFormat_BPTC; format = FasTC::eCompressionFormat_BPTC;
bUseNVTT = true; bUseNVTT = true;
} else if(!strcmp(argv[fileArg], "ETC1")) { } else if (!strcmp(argv[fileArg], "ETC1")) {
format = FasTC::eCompressionFormat_ETC1; format = FasTC::eCompressionFormat_ETC1;
} else if(!strcmp(argv[fileArg], "DXT1")) { } else if (!strcmp(argv[fileArg], "DXT1")) {
format = FasTC::eCompressionFormat_DXT1; format = FasTC::eCompressionFormat_DXT1;
} else if(!strcmp(argv[fileArg], "DXT5")) { } else if (!strcmp(argv[fileArg], "DXT5")) {
format = FasTC::eCompressionFormat_DXT5; format = FasTC::eCompressionFormat_DXT5;
} }
} }
@ -176,10 +177,10 @@ int main(int argc, char **argv) {
continue; continue;
} }
if(strcmp(argv[fileArg], "-d") == 0) { if (strcmp(argv[fileArg], "-d") == 0) {
fileArg++; fileArg++;
if(fileArg == argc) { if (fileArg == argc) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} else { } else {
@ -193,38 +194,38 @@ int main(int argc, char **argv) {
continue; continue;
} }
if(strcmp(argv[fileArg], "-nd") == 0) { if (strcmp(argv[fileArg], "-nd") == 0) {
fileArg++; fileArg++;
bNoDecompress = true; bDecompress = false;
knowArg = true; knowArg = true;
continue; continue;
} }
if(strcmp(argv[fileArg], "-l") == 0) { if (strcmp(argv[fileArg], "-l") == 0) {
fileArg++; fileArg++;
bSaveLog = true; bSaveLog = true;
knowArg = true; knowArg = true;
continue; continue;
} }
if(strcmp(argv[fileArg], "-v") == 0) { if (strcmp(argv[fileArg], "-v") == 0) {
fileArg++; fileArg++;
bVerbose = true; bVerbose = true;
knowArg = true; knowArg = true;
continue; continue;
} }
if(strcmp(argv[fileArg], "-simd") == 0) { if (strcmp(argv[fileArg], "-simd") == 0) {
fileArg++; fileArg++;
bUseSIMD = true; bUseSIMD = true;
knowArg = true; knowArg = true;
continue; continue;
} }
if(strcmp(argv[fileArg], "-t") == 0) { if (strcmp(argv[fileArg], "-t") == 0) {
fileArg++; fileArg++;
if(fileArg == argc || (numThreads = atoi(argv[fileArg])) < 1) { if (fileArg == argc || (numThreads = atoi(argv[fileArg])) < 1) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} }
@ -234,10 +235,10 @@ int main(int argc, char **argv) {
continue; continue;
} }
if(strcmp(argv[fileArg], "-q") == 0) { if (strcmp(argv[fileArg], "-q") == 0) {
fileArg++; fileArg++;
if(fileArg == argc || (quality = atoi(argv[fileArg])) < 0) { if (fileArg == argc || (quality = atoi(argv[fileArg])) < 0) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} }
@ -247,10 +248,10 @@ int main(int argc, char **argv) {
continue; continue;
} }
if(strcmp(argv[fileArg], "-j") == 0) { if (strcmp(argv[fileArg], "-j") == 0) {
fileArg++; fileArg++;
if(fileArg == argc || (numJobs = atoi(argv[fileArg])) < 0) { if (fileArg == argc || (numJobs = atoi(argv[fileArg])) < 0) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} }
@ -260,16 +261,16 @@ int main(int argc, char **argv) {
continue; continue;
} }
if(strcmp(argv[fileArg], "-a") == 0) { if (strcmp(argv[fileArg], "-a") == 0) {
fileArg++; fileArg++;
bUseAtomics = true; bUseAtomics = true;
knowArg = true; knowArg = true;
continue; continue;
} }
} while(knowArg && fileArg < argc); } while (knowArg && fileArg < argc);
if(fileArg == argc) { if (fileArg == argc) {
PrintUsage(); PrintUsage();
exit(1); exit(1);
} }
@ -277,15 +278,14 @@ int main(int argc, char **argv) {
char basename[256]; char basename[256];
ExtractBasename(argv[fileArg], basename, 256); ExtractBasename(argv[fileArg], basename, 256);
ImageFile file (argv[fileArg]); ImageFile file(argv[fileArg]);
if(!file.Load()) { if (!file.Load()) {
fprintf(stderr, "Error loading file: %s\n", argv[fileArg]);
return 1; return 1;
} }
FasTC::Image<> img(*file.GetImage()); FasTC::Image<> img(*file.GetImage());
if(bVerbose) { if (bVerbose) {
fprintf(stdout, "Entropy: %.5f\n", img.ComputeEntropy()); fprintf(stdout, "Entropy: %.5f\n", img.ComputeEntropy());
fprintf(stdout, "Mean Local Entropy: %.5f\n", img.ComputeMeanLocalEntropy()); fprintf(stdout, "Mean Local Entropy: %.5f\n", img.ComputeMeanLocalEntropy());
} }
@ -293,12 +293,12 @@ int main(int argc, char **argv) {
std::ofstream logFile; std::ofstream logFile;
ThreadSafeStreambuf streamBuf(logFile); ThreadSafeStreambuf streamBuf(logFile);
std::ostream logStream(&streamBuf); std::ostream logStream(&streamBuf);
if(bSaveLog) { if (bSaveLog) {
char logname[256]; char logname[256];
sprintf(logname, "%s.log", basename); sprintf(logname, "%s.log", basename);
logFile.open(logname); logFile.open(logname);
} }
SCompressionSettings settings; SCompressionSettings settings;
settings.format = format; settings.format = format;
settings.bUseSIMD = bUseSIMD; settings.bUseSIMD = bUseSIMD;
@ -309,36 +309,40 @@ int main(int argc, char **argv) {
settings.iJobSize = numJobs; settings.iJobSize = numJobs;
settings.bUsePVRTexLib = bUsePVRTexLib; settings.bUsePVRTexLib = bUsePVRTexLib;
settings.bUseNVTT = bUseNVTT; settings.bUseNVTT = bUseNVTT;
if(bSaveLog) { if (bSaveLog) {
settings.logStream = &logStream; settings.logStream = &logStream;
} else { } else {
settings.logStream = NULL; settings.logStream = NULL;
} }
CompressedImage *ci = CompressImage(&img, settings); CompressedImage *ci = CompressImage(&img, settings);
if(NULL == ci) { if (NULL == ci) {
fprintf(stderr, "Error compressing image!\n");
return 1; return 1;
} }
double PSNR = img.ComputePSNR(ci); if (ci->GetWidth() != img.GetWidth() ||
if(PSNR > 0.0) { ci->GetHeight() != img.GetHeight()) {
fprintf(stdout, "PSNR: %.3f\n", PSNR); fprintf(stderr, "Cannot compute image metrics: compressed and uncompressed dimensions differ.\n");
} } else {
else { double PSNR = img.ComputePSNR(ci);
fprintf(stderr, "Error computing PSNR\n"); if(PSNR > 0.0) {
} fprintf(stdout, "PSNR: %.3f\n", PSNR);
}
else {
fprintf(stderr, "Error computing PSNR\n");
}
if(bVerbose) { if(bVerbose) {
double SSIM = img.ComputeSSIM(ci); double SSIM = img.ComputeSSIM(ci);
if(SSIM > 0.0) { if(SSIM > 0.0) {
fprintf(stdout, "SSIM: %.9f\n", SSIM); fprintf(stdout, "SSIM: %.9f\n", SSIM);
} else { } else {
fprintf(stderr, "Error computing SSIM\n"); fprintf(stderr, "Error computing SSIM\n");
}
} }
} }
if(!bNoDecompress) { if(bDecompress) {
if(decompressedOutput[0] != '\0') { if(decompressedOutput[0] != '\0') {
memcpy(basename, decompressedOutput, 256); memcpy(basename, decompressedOutput, 256);
} else if(format == FasTC::eCompressionFormat_BPTC) { } else if(format == FasTC::eCompressionFormat_BPTC) {

View File

@ -45,16 +45,16 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstdlib>
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <string.h>
#include "ETCCompressor.h"
#include "DXTCompressor.h"
#include "BPTCCompressor.h" #include "BPTCCompressor.h"
#include "CompressionFormat.h"
#include "CompressionFuncs.h" #include "CompressionFuncs.h"
#include "Image.h" #include "DXTCompressor.h"
#include "ETCCompressor.h"
#include "ImageFile.h" #include "ImageFile.h"
#include "Pixel.h" #include "Pixel.h"
#include "PVRTCCompressor.h" #include "PVRTCCompressor.h"
@ -188,7 +188,10 @@ static double CompressImageInSerial(
const SCompressionSettings &settings const SCompressionSettings &settings
) { ) {
CompressionFunc f = ChooseFuncFromSettings(settings); CompressionFunc f = ChooseFuncFromSettings(settings);
CompressionFuncWithStats fStats = ChooseFuncFromSettingsWithStats(settings); CompressionFuncWithStats fStats = NULL;
if (settings.logStream) {
fStats = ChooseFuncFromSettingsWithStats(settings);
}
double cmpTimeTotal = 0.0; double cmpTimeTotal = 0.0;
@ -392,30 +395,51 @@ CompressedImage *CompressImage(
) { ) {
if(!img) return NULL; if(!img) return NULL;
const uint32 w = img->GetWidth(); uint32 width = img->GetWidth();
const uint32 h = img->GetHeight(); uint32 height = img->GetHeight();
assert(width > 0);
assert(height > 0);
// Make sure that the width and height of the image is a multiple of
// the block size of the format
uint32 blockDims[2];
FasTC::GetBlockDimensions(settings.format, blockDims);
if ((width % blockDims[0]) != 0 || (height % blockDims[1]) != 0) {
ReportError("WARNING - Image size is not a multiple of block size. Padding with zeros...");
uint32 newWidth = ((width + (blockDims[0] - 1)) / blockDims[0]) * blockDims[0];
uint32 newHeight = ((height + (blockDims[1] - 1)) / blockDims[1]) * blockDims[1];
assert(newWidth > width || newHeight > height);
assert(newWidth % blockDims[0] == 0);
assert(newHeight % blockDims[1] == 0);
width = newWidth;
height = newHeight;
}
uint32 dataSz = width * height * 4;
uint32 *data = new uint32[dataSz / 4];
memset(data, 0, dataSz);
CompressedImage *outImg = NULL; CompressedImage *outImg = NULL;
const unsigned int dataSz = w * h * 4;
uint32 *data = new uint32[dataSz / 4];
assert(dataSz > 0);
// Allocate data based on the compression method // Allocate data based on the compression method
uint32 cmpDataSz = CompressedImage::GetCompressedSize(dataSz, settings.format); uint32 cmpDataSz = CompressedImage::GetCompressedSize(dataSz, settings.format);
// Make sure that we have RGBA data... // Make sure that we have RGBA data...
img->ComputePixels(); img->ComputePixels();
const PixelType *pixels = img->GetPixels(); for(uint32 j = 0; j < img->GetHeight(); j++) {
for(uint32 i = 0; i < img->GetNumPixels(); i++) { for(uint32 i = 0; i < img->GetWidth(); i++) {
data[i] = pixels[i].Pack(); data[j * width + i] = (*img)(i, j).Pack();
}
} }
unsigned char *cmpData = new unsigned char[cmpDataSz]; unsigned char *cmpData = new unsigned char[cmpDataSz];
CompressImageData(reinterpret_cast<uint8 *>(data), w, h, cmpData, cmpDataSz, settings); uint8 *dataPtr = reinterpret_cast<uint8 *>(data);
if (CompressImageData(dataPtr, width, height, cmpData, cmpDataSz, settings)) {
outImg = new CompressedImage(width, height, settings.format, cmpData);
}
outImg = new CompressedImage(w, h, settings.format, cmpData);
delete [] data; delete [] data;
delete [] cmpData; delete [] cmpData;
return outImg; return outImg;
@ -433,7 +457,7 @@ bool CompressImageData(
uint8 *compressedData, uint8 *compressedData,
const uint32 cmpDataSz, const uint32 cmpDataSz,
const SCompressionSettings &settings const SCompressionSettings &settings
) { ) {
uint32 dataSz = width * height * 4; uint32 dataSz = width * height * 4;
@ -471,6 +495,19 @@ bool CompressImageData(
} }
} }
uint32 blockDims[2];
FasTC::GetBlockDimensions(settings.format, blockDims);
if ((width % blockDims[0]) != 0 || (height % blockDims[1]) != 0) {
ReportError("ERROR - CompressImageData: width or height is not multiple of block dimension");
return false;
} else if (settings.format == FasTC::eCompressionFormat_PVRTC4 &&
((width & (width - 1)) != 0 ||
(height & (height - 1)) != 0 ||
width != height)) {
ReportError("ERROR - CompressImageData: PVRTC4 images must be square and power-of-two.");
return false;
}
// Allocate data based on the compression method // Allocate data based on the compression method
uint32 compressedDataSzNeeded = uint32 compressedDataSzNeeded =
CompressedImage::GetCompressedSize(dataSz, settings.format); CompressedImage::GetCompressedSize(dataSz, settings.format);

View File

@ -85,8 +85,8 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) {
return 0; return 0;
} }
uint32 prec; uint32 prec = 0;
const uint8 *data; const uint8 *data = NULL;
switch(ch) { switch(ch) {
case 0: case 0:
@ -135,7 +135,7 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) {
} }
} }
return ret; return static_cast<unsigned int>(ret);
} }
else if(prec > 8) { else if(prec > 8) {
const int32 toShift = prec - 8; const int32 toShift = prec - 8;
@ -164,10 +164,10 @@ bool ImageLoader::LoadFromPixelBuffer(const uint32 *data, bool flipY) {
if(flipY) if(flipY)
idx = (m_Height - j - 1)*m_Height + i; idx = (m_Height - j - 1)*m_Height + i;
uint32 pixel = data[idx]; uint32 pixel = data[idx];
m_RedData[pIdx] = pixel & 0xFF; m_RedData[pIdx] = static_cast<uint8>(pixel & 0xFF);
m_GreenData[pIdx] = (pixel >> 8) & 0xFF; m_GreenData[pIdx] = static_cast<uint8>((pixel >> 8) & 0xFF);
m_BlueData[pIdx] = (pixel >> 16) & 0xFF; m_BlueData[pIdx] = static_cast<uint8>((pixel >> 16) & 0xFF);
m_AlphaData[pIdx] = (pixel >> 24) & 0xFF; m_AlphaData[pIdx] = static_cast<uint8>((pixel >> 24) & 0xFF);
} }
} }
@ -189,24 +189,13 @@ FasTC::Image<> *ImageLoader::LoadImage() {
m_Width = GetWidth(); m_Width = GetWidth();
m_Height = GetHeight(); m_Height = GetHeight();
// Populate buffer in block stream order... make
// sure that width and height are aligned to multiples of four.
const unsigned int aw = ((m_Width + 3) >> 2) << 2;
const unsigned int ah = ((m_Height + 3) >> 2) << 2;
// Create RGBA buffer // Create RGBA buffer
const unsigned int dataSz = 4 * aw * ah; const unsigned int dataSz = 4 * GetWidth() * GetHeight();
m_PixelData = new unsigned char[dataSz]; m_PixelData = new unsigned char[dataSz];
#ifndef NDEBUG
if(aw != m_Width || ah != m_Height)
fprintf(stderr, "Warning: Image dimension not multiple of four. "
"Space will be filled with black.\n");
#endif
int byteIdx = 0; int byteIdx = 0;
for(uint32 j = 0; j < ah; j++) { for(uint32 j = 0; j < GetHeight(); j++) {
for(uint32 i = 0; i < aw; i++) { for(uint32 i = 0; i < GetWidth(); i++) {
unsigned int redVal = GetChannelForPixel(i, j, 0); unsigned int redVal = GetChannelForPixel(i, j, 0);
if(redVal == INT_MAX) { if(redVal == INT_MAX) {
@ -239,22 +228,19 @@ FasTC::Image<> *ImageLoader::LoadImage() {
} }
// Red channel // Red channel
m_PixelData[byteIdx++] = redVal & 0xFF; m_PixelData[byteIdx++] = static_cast<uint8>(redVal & 0xFF);
// Green channel // Green channel
m_PixelData[byteIdx++] = greenVal & 0xFF; m_PixelData[byteIdx++] = static_cast<uint8>(greenVal & 0xFF);
// Blue channel // Blue channel
m_PixelData[byteIdx++] = blueVal & 0xFF; m_PixelData[byteIdx++] = static_cast<uint8>(blueVal & 0xFF);
// Alpha channel // Alpha channel
m_PixelData[byteIdx++] = alphaVal & 0xFF; m_PixelData[byteIdx++] = static_cast<uint8>(alphaVal & 0xFF);
} }
} }
m_Width = aw;
m_Height = ah;
uint32 *pixels = reinterpret_cast<uint32 *>(m_PixelData); uint32 *pixels = reinterpret_cast<uint32 *>(m_PixelData);
return new FasTC::Image<>(m_Width, m_Height, pixels); return new FasTC::Image<>(m_Width, m_Height, pixels);
} }