mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2025-01-08 22:05:37 +00:00
Reorganize a lot of code. Should probably split image and image file classes to separate IO operations and whatnot.
This commit is contained in:
parent
72c44f51d1
commit
c1222d75f9
|
@ -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;
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
|
@ -122,8 +131,11 @@ static double CompressImageWithWorkerQueue(
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue