Reorganize a lot of code. Should probably split image and image file classes to separate IO operations and whatnot.

This commit is contained in:
Pavel Krajcevski 2012-09-21 12:39:09 -04:00
parent 72c44f51d1
commit c1222d75f9
7 changed files with 121 additions and 55 deletions

View file

@ -3,6 +3,7 @@
#include <string.h>
#include "TexComp.h"
#include "ImageFile.h"
void PrintUsage() {
fprintf(stderr, "Usage: tc [-s|-t <num>] <imagefile>\n");
@ -82,7 +83,7 @@ int main(int argc, char **argv) {
settings.iQuality = quality;
settings.iNumCompressions = numCompressions;
CompressedImage *ci = CompressImage(file, settings);
CompressedImage *ci = file.Compress(settings);
if(NULL == ci) {
fprintf(stderr, "Error compressing image!\n");
return 1;

View file

@ -1,30 +1,62 @@
#ifndef _TEX_COMP_H_
#define _TEX_COMP_H_
#include "ImageFile.h"
#include "CompressedImage.h"
// Forward declarations
class ImageFile;
class CompressedImage;
struct SCompressionSettings {
SCompressionSettings(); // defaults
// The compression format for the image.
ECompressionFormat format;
// The flag that requests us to use SIMD, if it is available
bool bUseSIMD;
// The number of threads to spawn in order to process the data
int iNumThreads;
// Some compression formats take a measurement of quality when
// compressing an image. If the format supports it, this value
// will be used for quality purposes.
int iQuality;
// The number of compressions to perform. The program will compress
// the image this many times, and then take the average of the timing.
int iNumCompressions;
// This setting measures the number of blocks that a thread
// will process at any given time. If this value is zero,
// which is the default, the work will be divided by the
// number of threads, and each thread will do it's job and
// exit.
int iJobSize;
};
extern CompressedImage * CompressImage(
const ImageFile &,
extern bool CompressImageData(
const unsigned char *data,
const unsigned int dataSz,
unsigned char *cmpData,
const unsigned int cmpDataSz,
const SCompressionSettings &settings
);
// A compression function format. It takes the raw data and image dimensions and
// returns the compressed image data into outData. It is assumed that there is
// enough space allocated for outData to store the compressed data. Allocation
// is dependent on the compression format.
typedef void (* CompressionFunc)(
const unsigned char *inData,
unsigned char *outData,
unsigned int width,
unsigned int height
const unsigned char *inData, // Raw image data
unsigned char *outData, // Buffer to store compressed data.
unsigned int width, // Image width
unsigned int height // Image height
);
extern double ComputePSNR(const CompressedImage &, const ImageFile &);
// This function computes the Peak Signal to Noise Ratio between a
// compressed image and a raw image.
extern double ComputePSNR(const CompressedImage &ci, const ImageFile &file);
#endif //_TEX_COMP_H_

View file

@ -1,6 +1,7 @@
#include "BC7Compressor.h"
#include "TexComp.h"
#include "ThreadGroup.h"
#include "ImageFile.h"
#include <math.h>
#include <stdlib.h>
@ -22,6 +23,11 @@ static void clamp(T &x, const T &minX, const T &maxX) {
x = max(min(maxX, x), minX);
}
template <typename T>
static inline T sad(const T &a, const T &b) {
return (a > b)? a - b : b - a;
}
SCompressionSettings:: SCompressionSettings()
: format(eCompressionFormat_BPTC)
, bUseSIMD(false)
@ -58,7 +64,8 @@ static void ReportError(const char *msg) {
}
static double CompressImageInSerial(
const ImageFile &img,
const unsigned char *imgData,
const unsigned int imgDataSz,
const SCompressionSettings &settings,
const CompressionFunc f,
unsigned char *outBuf
@ -71,7 +78,8 @@ static double CompressImageInSerial(
stopWatch.Reset();
stopWatch.Start();
(*f)(img.GetPixels(), outBuf, img.GetWidth(), img.GetHeight());
// !FIXME! We're assuming that we have 4x4 blocks here...
(*f)(imgData, outBuf, imgDataSz / 16, 4);
stopWatch.Stop();
@ -83,16 +91,17 @@ static double CompressImageInSerial(
}
static double CompressImageWithThreads(
const ImageFile &img,
const unsigned char *imgData,
const unsigned int imgDataSz,
const SCompressionSettings &settings,
const CompressionFunc f,
unsigned char *outBuf
) {
ThreadGroup tgrp (settings.iNumThreads, img, f, outBuf);
ThreadGroup tgrp (settings.iNumThreads, imgData, imgDataSz, f, outBuf);
if(!(tgrp.PrepareThreads())) {
assert(!"Thread group failed to prepare threads?!");
return NULL;
return -1.0f;
}
double cmpTimeTotal = 0.0;
@ -120,10 +129,13 @@ static double CompressImageWithWorkerQueue(
unsigned char *outBuf
) {
return 0.0;
}
}
CompressedImage * CompressImage(
const ImageFile &img,
bool CompressImageData(
const unsigned char *data,
const unsigned int dataSz,
unsigned char *cmpData,
const unsigned int cmpDataSz,
const SCompressionSettings &settings
) {
@ -132,27 +144,31 @@ CompressedImage * CompressImage(
#ifndef HAS_SSE_41
if(settings.bUseSIMD) {
ReportError("Platform does not support SIMD!\n");
return NULL;
return false;
}
#endif
const unsigned int dataSz = img.GetWidth() * img.GetHeight() * 4;
if(dataSz <= 0) {
ReportError("No data sent to compress!");
return false;
}
// Allocate data based on the compression method
int cmpDataSz = 0;
int cmpDataSzNeeded = 0;
switch(settings.format) {
case eCompressionFormat_DXT1: cmpDataSz = dataSz / 8;
case eCompressionFormat_DXT5: cmpDataSz = dataSz / 4;
case eCompressionFormat_BPTC: cmpDataSz = dataSz / 4;
case eCompressionFormat_DXT1: cmpDataSzNeeded = dataSz / 8;
case eCompressionFormat_DXT5: cmpDataSzNeeded = dataSz / 4;
case eCompressionFormat_BPTC: cmpDataSzNeeded = dataSz / 4;
}
if(cmpDataSz == 0) {
if(cmpDataSzNeeded == 0) {
ReportError("Unknown compression format");
return NULL;
return false;
}
else if(cmpDataSzNeeded > cmpDataSz) {
ReportError("Not enough space for compressed data!");
return false;
}
CompressedImage *outImg = NULL;
unsigned char *cmpData = new unsigned char[cmpDataSz];
CompressionFunc f = ChooseFuncFromSettings(settings);
if(f) {
@ -160,32 +176,21 @@ CompressedImage * CompressImage(
double cmpMSTime = 0.0;
if(settings.iNumThreads > 1) {
cmpMSTime = CompressImageWithThreads(img, settings, f, cmpData);
cmpMSTime = CompressImageWithThreads(data, dataSz, settings, f, cmpData);
}
else {
cmpMSTime = CompressImageInSerial(img, settings, f, cmpData);
cmpMSTime = CompressImageInSerial(data, dataSz, settings, f, cmpData);
}
outImg = new CompressedImage(img.GetWidth(), img.GetHeight(), settings.format, cmpData);
// Report compression time
fprintf(stdout, "Compression time: %0.3f ms\n", cmpMSTime);
}
else {
ReportError("Could not find adequate compression function for specified settings");
delete [] cmpData;
return NULL;
return false;
}
// Cleanup
delete [] cmpData;
return outImg;
}
template <typename T>
static inline T sad(const T &a, const T &b) {
return (a > b)? a - b : b - a;
return true;
}
double ComputePSNR(const CompressedImage &ci, const ImageFile &file) {
@ -196,7 +201,7 @@ double ComputePSNR(const CompressedImage &ci, const ImageFile &file) {
return -1.0f;
}
const unsigned char *rawData = file.GetPixels();
const unsigned char *rawData = file.RawData();
const double wr = 1.0;
const double wg = 1.0;

View file

@ -52,14 +52,15 @@ void CmpThread::operator()() {
}
ThreadGroup::ThreadGroup( int numThreads, const ImageFile &image, CompressionFunc func, unsigned char *outBuf )
ThreadGroup::ThreadGroup( int numThreads, const unsigned char *inBuf, unsigned int inBufSz, CompressionFunc func, unsigned char *outBuf )
: m_StartBarrier(new boost::barrier(numThreads + 1))
, m_FinishMutex(new boost::mutex())
, m_FinishCV(new boost::condition_variable())
, m_NumThreads(numThreads)
, m_ActiveThreads(0)
, m_Func(func)
, m_Image(image)
, m_ImageDataSz(inBufSz)
, m_ImageData(inBuf)
, m_OutBuf(outBuf)
, m_ThreadState(eThreadState_Done)
, m_ExitFlag(false)
@ -107,13 +108,9 @@ bool ThreadGroup::PrepareThreads() {
return true;
}
// Make sure that the image dimensions are multiples of 4
assert((m_Image.GetWidth() & 3) == 0);
assert((m_Image.GetHeight() & 3) == 0);
// We can assume that the image data is in block stream order
// so, the size of the data given to each thread will be (nb*4)x4
int numBlocks = (m_Image.GetWidth() * m_Image.GetHeight()) / 16;
int numBlocks = m_ImageDataSz / 64;
int blocksProcessed = 0;
int blocksPerThread = (numBlocks/m_NumThreads) + ((numBlocks % m_NumThreads)? 1 : 0);
@ -135,7 +132,7 @@ bool ThreadGroup::PrepareThreads() {
t.m_Width = numBlocksThisThread * 4;
t.m_CmpFunc = m_Func;
t.m_OutBuf = m_OutBuf + (blocksProcessed * GetCompressedBlockSize());
t.m_InBuf = m_Image.GetPixels() + (blocksProcessed * GetUncompressedBlockSize());
t.m_InBuf = m_ImageData + (blocksProcessed * GetUncompressedBlockSize());
blocksProcessed += numBlocksThisThread;

View file

@ -42,7 +42,7 @@ public:
class ThreadGroup {
public:
ThreadGroup( int numThreads, const ImageFile &, CompressionFunc func, unsigned char *outBuf );
ThreadGroup( int numThreads, const unsigned char *inBuf, unsigned int inBufSz, CompressionFunc func, unsigned char *outBuf );
~ThreadGroup();
bool PrepareThreads();
@ -74,7 +74,8 @@ class ThreadGroup {
boost::thread *m_ThreadHandles[kMaxNumThreads];
// State variables.
const ImageFile &m_Image;
const unsigned int m_ImageDataSz;
const unsigned char *const m_ImageData;
const CompressionFunc m_Func;
unsigned char *m_OutBuf;

View file

@ -3,6 +3,10 @@
#include "ImageFileFormat.h"
// Forward declare
class CompressedImage;
// Class definition
class ImageFile {
public:
@ -13,7 +17,9 @@ public:
unsigned int GetWidth() const { return m_Width; }
unsigned int GetHeight() const { return m_Height; }
const unsigned char *GetPixels() const { return m_PixelData; }
CompressedImage *Compress(const SCompressionSettings &) const;
const unsigned char *RawData() const { return m_PixelData; }
private:
unsigned int m_Handle;

View file

@ -4,8 +4,10 @@
#include <limits.h>
#include <assert.h>
#include "TexComp.h"
#include "ImageFile.h"
#include "ImageLoader.h"
#include "CompressedImage.h"
#ifdef PNG_FOUND
# include "ImageLoaderPNG.h"
@ -302,3 +304,25 @@ unsigned char *ImageFile::ReadFileData(const char *filename) {
return rawData;
}
#endif
CompressedImage *ImageFile::Compress(const SCompressionSettings &settings) const {
CompressedImage *outImg = NULL;
const unsigned int dataSz = GetWidth() * GetHeight() * 4;
assert(dataSz > 0);
// Allocate data based on the compression method
int cmpDataSz = 0;
switch(settings.format) {
case eCompressionFormat_DXT1: cmpDataSz = dataSz / 8;
case eCompressionFormat_DXT5: cmpDataSz = dataSz / 4;
case eCompressionFormat_BPTC: cmpDataSz = dataSz / 4;
}
unsigned char *cmpData = new unsigned char[cmpDataSz];
CompressImageData(m_PixelData, dataSz, cmpData, cmpDataSz, settings);
outImg = new CompressedImage(GetWidth(), GetHeight(), settings.format, cmpData);
return outImg;
}