Plug in the infrastructure to start passing images to be compressed.

This commit is contained in:
Pavel Krajcevski 2013-09-20 12:43:59 -04:00
parent 995c237e5e
commit 1093447055
9 changed files with 166 additions and 67 deletions

View file

@ -53,6 +53,7 @@
void PrintUsage() {
fprintf(stderr, "Usage: tc [OPTIONS] imagefile\n");
fprintf(stderr, "\n");
fprintf(stderr, "\t-f\t\tFormat to use. Either \"BPTC\" or \"PVRTC\". Default: BPTC\n");
fprintf(stderr, "\t-l\t\tSave an output log.\n");
fprintf(stderr, "\t-q <quality>\tSet compression quality level. Default: 50\n");
fprintf(stderr, "\t-n <num>\tCompress the image num times and give the average time and PSNR. Default: 1\n");
@ -92,6 +93,7 @@ int main(int argc, char **argv) {
bool bUseSIMD = false;
bool bSaveLog = false;
bool bUseAtomics = false;
ECompressionFormat format = eCompressionFormat_BPTC;
bool knowArg = false;
do {
@ -110,6 +112,23 @@ int main(int argc, char **argv) {
continue;
}
if(strcmp(argv[fileArg], "-f") == 0) {
fileArg++;
if(fileArg == argc) {
PrintUsage();
exit(1);
} else {
if(!strcmp(argv[fileArg], "PVRTC")) {
format = eCompressionFormat_PVRTC;
}
}
fileArg++;
knowArg = true;
continue;
}
if(strcmp(argv[fileArg], "-l") == 0) {
fileArg++;
bSaveLog = true;
@ -195,6 +214,7 @@ int main(int argc, char **argv) {
}
SCompressionSettings settings;
settings.format = format;
settings.bUseSIMD = bUseSIMD;
settings.bUseAtomics = bUseAtomics;
settings.iNumThreads = numThreads;

View file

@ -71,6 +71,9 @@ ELSE()
SET( LINK_FLAGS -lrt ${LINK_FLAGS} )
ENDIF()
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR} )
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/PVRTCEncoder/include )
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/BPTCEncoder/include )
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/BPTCEncoder/include )
@ -149,6 +152,7 @@ ADD_LIBRARY( FasTCCore
TARGET_LINK_LIBRARIES( FasTCCore FasTCIO )
TARGET_LINK_LIBRARIES( FasTCCore BPTCEncoder )
TARGET_LINK_LIBRARIES( FasTCCore PVRTCEncoder )
IF( THREAD_API MATCHES "Boost" )
TARGET_LINK_LIBRARIES( FasTCCore ${Boost_LIBRARIES} )

View file

@ -44,10 +44,13 @@
#ifndef _COMPRESSED_IMAGE_H_
#define _COMPRESSED_IMAGE_H_
#include "TexCompTypes.h"
enum ECompressionFormat {
eCompressionFormat_DXT1,
eCompressionFormat_DXT5,
eCompressionFormat_BPTC,
eCompressionFormat_PVRTC,
kNumCompressionFormats
};
@ -55,15 +58,15 @@ enum ECompressionFormat {
class CompressedImage {
private:
unsigned int m_Width;
unsigned int m_Height;
uint32 m_Width;
uint32 m_Height;
ECompressionFormat m_Format;
unsigned char *m_Data;
unsigned int m_DataSz;
uint8 *m_Data;
uint32 m_DataSz;
void InitData(const unsigned char *withData);
void InitData(const uint8 *withData);
public:
CompressedImage();
@ -71,23 +74,29 @@ class CompressedImage {
// the passed format. The size of the data is expected to conform
// to the width, height, and format specified.
CompressedImage(
const unsigned int width,
const unsigned int height,
const uint32 width,
const uint32 height,
const ECompressionFormat format,
const unsigned char *data
const uint8 *data
);
unsigned int GetHeight() const { return m_Height; }
unsigned int GetWidth() const { return m_Width; }
uint32 GetHeight() const { return m_Height; }
uint32 GetWidth() const { return m_Width; }
CompressedImage( const CompressedImage &other );
~CompressedImage();
static uint32 GetCompressedSize(uint32 uncompressedSize, ECompressionFormat format);
static uint32 GetUncompressedSize(uint32 compressedSize, ECompressionFormat format) {
uint32 cmp = GetCompressedSize(compressedSize, format);
return compressedSize * (compressedSize / cmp);
}
// Decompress the compressed image data into outBuf. outBufSz is expected
// to be the proper size determined by the width, height, and format.
// !FIXME! We should have a function to explicitly return the in/out buf
// size for a given compressed image.
bool DecompressImage(unsigned char *outBuf, unsigned int outBufSz) const;
bool DecompressImage(uint8 *outBuf, uint32 outBufSz) const;
};
#endif // _COMPRESSED_IMAGE_H_

View file

@ -93,7 +93,8 @@ struct SCompressionSettings {
extern bool CompressImageData(
const unsigned char *data,
const unsigned int dataSz,
const unsigned int width,
const unsigned int height,
unsigned char *cmpData,
const unsigned int cmpDataSz,
const SCompressionSettings &settings

View file

@ -50,6 +50,7 @@
#include "TexCompTypes.h"
#include "BC7Compressor.h"
#include "PVRTCCompressor.h"
CompressedImage::CompressedImage()
: m_Width(0)
@ -85,16 +86,7 @@ CompressedImage::CompressedImage(
}
void CompressedImage::InitData(const unsigned char *withData) {
m_DataSz = 0;
int uncompDataSz = m_Width * m_Height * 4;
switch(m_Format) {
default: assert(!"Not implemented!"); // Fall through V
case eCompressionFormat_DXT1: m_DataSz = uncompDataSz / 8; break;
case eCompressionFormat_DXT5: m_DataSz = uncompDataSz / 4; break;
case eCompressionFormat_BPTC: m_DataSz = uncompDataSz / 4; break;
}
m_DataSz = GetCompressedSize(m_Width * m_Height * 4, m_Format);
if(m_DataSz > 0) {
m_Data = new unsigned char[m_DataSz];
memcpy(m_Data, withData, m_DataSz);
@ -111,14 +103,7 @@ CompressedImage::~CompressedImage() {
bool CompressedImage::DecompressImage(unsigned char *outBuf, unsigned int outBufSz) const {
// First make sure that we have enough data
uint32 dataSz = 0;
switch(m_Format) {
default: assert(!"Not implemented!"); // Fall through V
case eCompressionFormat_DXT1: dataSz = m_DataSz * 8; break;
case eCompressionFormat_DXT5: dataSz = m_DataSz * 4; break;
case eCompressionFormat_BPTC: dataSz = m_DataSz * 4; break;
}
uint32 dataSz = GetUncompressedSize(m_DataSz, m_Format);
if(dataSz > outBufSz) {
fprintf(stderr, "Not enough space to store entire decompressed image! "
"Got %d bytes, but need %d!\n", outBufSz, dataSz);
@ -126,6 +111,13 @@ bool CompressedImage::DecompressImage(unsigned char *outBuf, unsigned int outBuf
}
switch(m_Format) {
case eCompressionFormat_PVRTC:
{
DecompressionJob dj (m_Data, outBuf, m_Width, m_Height);
PVRTCC::Decompress(dj);
}
break;
case eCompressionFormat_BPTC:
{
DecompressionJob dj (m_Data, outBuf, m_Width, m_Height);
@ -142,3 +134,26 @@ bool CompressedImage::DecompressImage(unsigned char *outBuf, unsigned int outBuf
return true;
}
uint32 CompressedImage::GetCompressedSize(uint32 uncompressedSize, ECompressionFormat format) {
assert(uncompressedSize % 8 == 0);
uint32 cmpDataSzNeeded = 0;
switch(format) {
default:
assert(!"Not implemented!");
// Fall through V
case eCompressionFormat_DXT1:
case eCompressionFormat_PVRTC:
cmpDataSzNeeded = uncompressedSize / 8;
break;
case eCompressionFormat_DXT5:
case eCompressionFormat_BPTC:
cmpDataSzNeeded = uncompressedSize / 4;
break;
}
return cmpDataSzNeeded;
}

View file

@ -149,16 +149,10 @@ CompressedImage *Image::Compress(const SCompressionSettings &settings) const {
assert(dataSz > 0);
// Allocate data based on the compression method
int cmpDataSz = 0;
switch(settings.format) {
default: assert(!"Not implemented!"); // Fall Through V
case eCompressionFormat_DXT1: cmpDataSz = dataSz / 8; break;
case eCompressionFormat_DXT5: cmpDataSz = dataSz / 4; break;
case eCompressionFormat_BPTC: cmpDataSz = dataSz / 4; break;
}
int cmpDataSz = CompressedImage::GetCompressedSize(dataSz, settings.format);
unsigned char *cmpData = new unsigned char[cmpDataSz];
CompressImageData(m_PixelData, dataSz, cmpData, cmpDataSz, settings);
CompressImageData(m_PixelData, GetWidth(), GetHeight(), cmpData, cmpDataSz, settings);
outImg = new CompressedImage(GetWidth(), GetHeight(), settings.format, cmpData);

View file

@ -49,6 +49,7 @@
#include <cstdio>
#include <cassert>
#include "PVRTCCompressor.h"
#include "BC7Compressor.h"
#include "Thread.h"
#include "WorkerQueue.h"
@ -68,6 +69,10 @@ static inline T sad(const T &a, const T &b) {
return (a > b)? a - b : b - a;
}
static void CompressPVRTC(const CompressionJob &cj) {
PVRTCC::Compress(cj);
}
SCompressionSettings:: SCompressionSettings()
: format(eCompressionFormat_BPTC)
, bUseSIMD(false)
@ -86,6 +91,12 @@ static CompressionFuncWithStats ChooseFuncFromSettingsWithStats(const SCompress
}
break;
case eCompressionFormat_PVRTC:
{
// !FIXME! actually implement one of these methods...
return NULL;
}
default:
{
assert(!"Not implemented!");
@ -109,6 +120,11 @@ static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) {
}
break;
case eCompressionFormat_PVRTC:
{
return CompressPVRTC;
}
default:
{
assert(!"Not implemented!");
@ -123,8 +139,9 @@ static void ReportError(const char *msg) {
}
static double CompressImageInSerial(
const unsigned char *imgData,
const unsigned int imgDataSz,
const uint8 *imgData,
const uint32 imgWidth,
const uint32 imgHeight,
const SCompressionSettings &settings,
unsigned char *outBuf
) {
@ -133,14 +150,14 @@ static double CompressImageInSerial(
double cmpTimeTotal = 0.0;
StopWatch stopWatch = StopWatch();
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...
CompressionJob cj (imgData, outBuf, imgDataSz / 16, 4);
CompressionJob cj (imgData, outBuf, imgWidth, imgHeight);
if(fStats && settings.pStatManager) {
(*fStats)(cj, *(settings.pStatManager));
}
@ -332,12 +349,15 @@ static double CompressImageWithWorkerQueue(
bool CompressImageData(
const unsigned char *data,
const unsigned int dataSz,
const unsigned int width,
const unsigned int height,
unsigned char *cmpData,
const unsigned int cmpDataSz,
const SCompressionSettings &settings
) {
uint32 dataSz = width * height * 4;
// Make sure that platform supports SSE if they chose this
// option...
#ifndef HAS_SSE_41
@ -352,15 +372,23 @@ bool CompressImageData(
return false;
}
// Allocate data based on the compression method
uint32 cmpDataSzNeeded = 0;
switch(settings.format) {
default: assert(!"Not implemented!"); // Fall through V
case eCompressionFormat_DXT1: cmpDataSzNeeded = dataSz / 8; break;
case eCompressionFormat_DXT5: cmpDataSzNeeded = dataSz / 4; break;
case eCompressionFormat_BPTC: cmpDataSzNeeded = dataSz / 4; break;
uint32 numThreads = settings.iNumThreads;
if(settings.format == eCompressionFormat_PVRTC &&
(settings.iNumThreads > 1 || settings.pStatManager)) {
if(settings.iNumThreads > 1) {
ReportError("WARNING - PVRTC compressor does not support multithreading.");
numThreads = 1;
}
if(settings.pStatManager) {
ReportError("WARNING - PVRTC compressor does not support stat collection.");
}
}
// Allocate data based on the compression method
uint32 cmpDataSzNeeded =
CompressedImage::GetCompressedSize(dataSz, settings.format);
if(cmpDataSzNeeded == 0) {
ReportError("Unknown compression format");
return false;
@ -375,21 +403,17 @@ bool CompressImageData(
double cmpMSTime = 0.0;
if(settings.iNumThreads > 1) {
if(numThreads > 1) {
if(settings.bUseAtomics) {
//!KLUDGE!
unsigned int height = 4;
unsigned int width = dataSz / 16;
cmpMSTime = CompressImageWithAtomics(data, width, height, settings, cmpData);
}
else if(settings.iJobSize > 0)
} else if(settings.iJobSize > 0) {
cmpMSTime = CompressImageWithWorkerQueue(data, dataSz, settings, cmpData);
else
} else {
cmpMSTime = CompressImageWithThreads(data, dataSz, settings, cmpData);
}
}
else {
cmpMSTime = CompressImageInSerial(data, dataSz, settings, cmpData);
cmpMSTime = CompressImageInSerial(data, width, height, settings, cmpData);
}
// Report compression time

View file

@ -76,7 +76,7 @@ namespace PVRTCC {
// Takes a stream of uncompressed RGBA8 data and compresses it into PVRTC
// version one. The width and height must be specified in order to properly
// decompress the data.
void Compress(const DecompressionJob &,
void Compress(const CompressionJob &,
bool bTwoBitMode = false,
const EWrapMode wrapMode = eWrapMode_Wrap);

View file

@ -57,20 +57,52 @@
namespace PVRTCC {
void Compress(const DecompressionJob &dcj,
void Compress(const CompressionJob &dcj,
bool bTwoBitMode,
const EWrapMode wrapMode) {
Image img(dcj.height, dcj.width);
for(uint32 j = 0; j < dcj.height; j++) {
for(uint32 i = 0; i < dcj.width; i++) {
uint32 nPixels = dcj.height * dcj.width;
for(uint32 i = 0; i < nPixels; i++) {
// Assume block stream order (whyyyy)
uint32 blockIdx = i / 16;
uint32 blockWidth = dcj.width / 4;
uint32 blockX = blockIdx % blockWidth;
uint32 blockY = blockIdx / blockWidth;
uint32 x = blockX * 4 + (i % 4);
uint32 y = blockY * 4 + (i % 16) / 4;
const uint32 *pixels = reinterpret_cast<const uint32 *>(dcj.inBuf);
img(i, j).UnpackRGBA(pixels[j * dcj.width + i]);
}
img(x, y).UnpackRGBA(pixels[i]);
}
Image original = img;
img.DebugOutput("Original");
// Downscale it using anisotropic diffusion based scheme in order to preserve
// image features, then reupscale and compute deltas. Use deltas to generate
// initial A & B images followed by modulation data.
img.ContentAwareDownscale(1, 1, eWrapMode_Wrap, true);
img.DebugOutput("DownscaledOnce");
img.ContentAwareDownscale(1, 1, eWrapMode_Wrap, false);
img.DebugOutput("DownscaledTwice");
Image downscaled = img;
// Upscale it again
img.BilinearUpscale(2, 2, eWrapMode_Wrap);
img.DebugOutput("Reconstruction");
// Compute difference...
Image difference = img;
for(uint32 j = 0; j < dcj.height; j++) {
for(uint32 i = 0; i < dcj.width; i++) {
for(uint32 c = 0; c < 4; c++) {
difference(i, j).Component(c) -= img(i, j).Component(c);
}
}
}
}
} // namespace PVRTCC