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 <string.h>
|
||||||
|
|
||||||
#include "TexComp.h"
|
#include "TexComp.h"
|
||||||
|
#include "ImageFile.h"
|
||||||
|
|
||||||
void PrintUsage() {
|
void PrintUsage() {
|
||||||
fprintf(stderr, "Usage: tc [-s|-t <num>] <imagefile>\n");
|
fprintf(stderr, "Usage: tc [-s|-t <num>] <imagefile>\n");
|
||||||
|
@ -82,7 +83,7 @@ int main(int argc, char **argv) {
|
||||||
settings.iQuality = quality;
|
settings.iQuality = quality;
|
||||||
settings.iNumCompressions = numCompressions;
|
settings.iNumCompressions = numCompressions;
|
||||||
|
|
||||||
CompressedImage *ci = CompressImage(file, settings);
|
CompressedImage *ci = file.Compress(settings);
|
||||||
if(NULL == ci) {
|
if(NULL == ci) {
|
||||||
fprintf(stderr, "Error compressing image!\n");
|
fprintf(stderr, "Error compressing image!\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1,30 +1,62 @@
|
||||||
#ifndef _TEX_COMP_H_
|
#ifndef _TEX_COMP_H_
|
||||||
#define _TEX_COMP_H_
|
#define _TEX_COMP_H_
|
||||||
|
|
||||||
#include "ImageFile.h"
|
|
||||||
#include "CompressedImage.h"
|
#include "CompressedImage.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class ImageFile;
|
||||||
|
class CompressedImage;
|
||||||
|
|
||||||
struct SCompressionSettings {
|
struct SCompressionSettings {
|
||||||
SCompressionSettings(); // defaults
|
SCompressionSettings(); // defaults
|
||||||
|
|
||||||
|
// The compression format for the image.
|
||||||
ECompressionFormat format;
|
ECompressionFormat format;
|
||||||
|
|
||||||
|
// The flag that requests us to use SIMD, if it is available
|
||||||
bool bUseSIMD;
|
bool bUseSIMD;
|
||||||
|
|
||||||
|
// The number of threads to spawn in order to process the data
|
||||||
int iNumThreads;
|
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;
|
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;
|
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(
|
extern bool CompressImageData(
|
||||||
const ImageFile &,
|
const unsigned char *data,
|
||||||
|
const unsigned int dataSz,
|
||||||
|
unsigned char *cmpData,
|
||||||
|
const unsigned int cmpDataSz,
|
||||||
const SCompressionSettings &settings
|
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)(
|
typedef void (* CompressionFunc)(
|
||||||
const unsigned char *inData,
|
const unsigned char *inData, // Raw image data
|
||||||
unsigned char *outData,
|
unsigned char *outData, // Buffer to store compressed data.
|
||||||
unsigned int width,
|
unsigned int width, // Image width
|
||||||
unsigned int height
|
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_
|
#endif //_TEX_COMP_H_
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "BC7Compressor.h"
|
#include "BC7Compressor.h"
|
||||||
#include "TexComp.h"
|
#include "TexComp.h"
|
||||||
#include "ThreadGroup.h"
|
#include "ThreadGroup.h"
|
||||||
|
#include "ImageFile.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.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);
|
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()
|
SCompressionSettings:: SCompressionSettings()
|
||||||
: format(eCompressionFormat_BPTC)
|
: format(eCompressionFormat_BPTC)
|
||||||
, bUseSIMD(false)
|
, bUseSIMD(false)
|
||||||
|
@ -58,7 +64,8 @@ static void ReportError(const char *msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static double CompressImageInSerial(
|
static double CompressImageInSerial(
|
||||||
const ImageFile &img,
|
const unsigned char *imgData,
|
||||||
|
const unsigned int imgDataSz,
|
||||||
const SCompressionSettings &settings,
|
const SCompressionSettings &settings,
|
||||||
const CompressionFunc f,
|
const CompressionFunc f,
|
||||||
unsigned char *outBuf
|
unsigned char *outBuf
|
||||||
|
@ -71,7 +78,8 @@ static double CompressImageInSerial(
|
||||||
stopWatch.Reset();
|
stopWatch.Reset();
|
||||||
stopWatch.Start();
|
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();
|
stopWatch.Stop();
|
||||||
|
|
||||||
|
@ -83,16 +91,17 @@ static double CompressImageInSerial(
|
||||||
}
|
}
|
||||||
|
|
||||||
static double CompressImageWithThreads(
|
static double CompressImageWithThreads(
|
||||||
const ImageFile &img,
|
const unsigned char *imgData,
|
||||||
|
const unsigned int imgDataSz,
|
||||||
const SCompressionSettings &settings,
|
const SCompressionSettings &settings,
|
||||||
const CompressionFunc f,
|
const CompressionFunc f,
|
||||||
unsigned char *outBuf
|
unsigned char *outBuf
|
||||||
) {
|
) {
|
||||||
|
|
||||||
ThreadGroup tgrp (settings.iNumThreads, img, f, outBuf);
|
ThreadGroup tgrp (settings.iNumThreads, imgData, imgDataSz, f, outBuf);
|
||||||
if(!(tgrp.PrepareThreads())) {
|
if(!(tgrp.PrepareThreads())) {
|
||||||
assert(!"Thread group failed to prepare threads?!");
|
assert(!"Thread group failed to prepare threads?!");
|
||||||
return NULL;
|
return -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
double cmpTimeTotal = 0.0;
|
double cmpTimeTotal = 0.0;
|
||||||
|
@ -120,10 +129,13 @@ static double CompressImageWithWorkerQueue(
|
||||||
unsigned char *outBuf
|
unsigned char *outBuf
|
||||||
) {
|
) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressedImage * CompressImage(
|
bool CompressImageData(
|
||||||
const ImageFile &img,
|
const unsigned char *data,
|
||||||
|
const unsigned int dataSz,
|
||||||
|
unsigned char *cmpData,
|
||||||
|
const unsigned int cmpDataSz,
|
||||||
const SCompressionSettings &settings
|
const SCompressionSettings &settings
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -132,27 +144,31 @@ CompressedImage * CompressImage(
|
||||||
#ifndef HAS_SSE_41
|
#ifndef HAS_SSE_41
|
||||||
if(settings.bUseSIMD) {
|
if(settings.bUseSIMD) {
|
||||||
ReportError("Platform does not support SIMD!\n");
|
ReportError("Platform does not support SIMD!\n");
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
// Allocate data based on the compression method
|
||||||
int cmpDataSz = 0;
|
int cmpDataSzNeeded = 0;
|
||||||
switch(settings.format) {
|
switch(settings.format) {
|
||||||
case eCompressionFormat_DXT1: cmpDataSz = dataSz / 8;
|
case eCompressionFormat_DXT1: cmpDataSzNeeded = dataSz / 8;
|
||||||
case eCompressionFormat_DXT5: cmpDataSz = dataSz / 4;
|
case eCompressionFormat_DXT5: cmpDataSzNeeded = dataSz / 4;
|
||||||
case eCompressionFormat_BPTC: cmpDataSz = dataSz / 4;
|
case eCompressionFormat_BPTC: cmpDataSzNeeded = dataSz / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmpDataSz == 0) {
|
if(cmpDataSzNeeded == 0) {
|
||||||
ReportError("Unknown compression format");
|
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);
|
CompressionFunc f = ChooseFuncFromSettings(settings);
|
||||||
if(f) {
|
if(f) {
|
||||||
|
@ -160,32 +176,21 @@ CompressedImage * CompressImage(
|
||||||
double cmpMSTime = 0.0;
|
double cmpMSTime = 0.0;
|
||||||
|
|
||||||
if(settings.iNumThreads > 1) {
|
if(settings.iNumThreads > 1) {
|
||||||
cmpMSTime = CompressImageWithThreads(img, settings, f, cmpData);
|
cmpMSTime = CompressImageWithThreads(data, dataSz, settings, f, cmpData);
|
||||||
}
|
}
|
||||||
else {
|
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
|
// Report compression time
|
||||||
fprintf(stdout, "Compression time: %0.3f ms\n", cmpMSTime);
|
fprintf(stdout, "Compression time: %0.3f ms\n", cmpMSTime);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ReportError("Could not find adequate compression function for specified settings");
|
ReportError("Could not find adequate compression function for specified settings");
|
||||||
delete [] cmpData;
|
return false;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
return true;
|
||||||
delete [] cmpData;
|
|
||||||
|
|
||||||
return outImg;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static inline T sad(const T &a, const T &b) {
|
|
||||||
return (a > b)? a - b : b - a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double ComputePSNR(const CompressedImage &ci, const ImageFile &file) {
|
double ComputePSNR(const CompressedImage &ci, const ImageFile &file) {
|
||||||
|
@ -196,7 +201,7 @@ double ComputePSNR(const CompressedImage &ci, const ImageFile &file) {
|
||||||
return -1.0f;
|
return -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char *rawData = file.GetPixels();
|
const unsigned char *rawData = file.RawData();
|
||||||
|
|
||||||
const double wr = 1.0;
|
const double wr = 1.0;
|
||||||
const double wg = 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_StartBarrier(new boost::barrier(numThreads + 1))
|
||||||
, m_FinishMutex(new boost::mutex())
|
, m_FinishMutex(new boost::mutex())
|
||||||
, m_FinishCV(new boost::condition_variable())
|
, m_FinishCV(new boost::condition_variable())
|
||||||
, m_NumThreads(numThreads)
|
, m_NumThreads(numThreads)
|
||||||
, m_ActiveThreads(0)
|
, m_ActiveThreads(0)
|
||||||
, m_Func(func)
|
, m_Func(func)
|
||||||
, m_Image(image)
|
, m_ImageDataSz(inBufSz)
|
||||||
|
, m_ImageData(inBuf)
|
||||||
, m_OutBuf(outBuf)
|
, m_OutBuf(outBuf)
|
||||||
, m_ThreadState(eThreadState_Done)
|
, m_ThreadState(eThreadState_Done)
|
||||||
, m_ExitFlag(false)
|
, m_ExitFlag(false)
|
||||||
|
@ -107,13 +108,9 @@ bool ThreadGroup::PrepareThreads() {
|
||||||
return true;
|
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
|
// 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
|
// 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 blocksProcessed = 0;
|
||||||
int blocksPerThread = (numBlocks/m_NumThreads) + ((numBlocks % m_NumThreads)? 1 : 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_Width = numBlocksThisThread * 4;
|
||||||
t.m_CmpFunc = m_Func;
|
t.m_CmpFunc = m_Func;
|
||||||
t.m_OutBuf = m_OutBuf + (blocksProcessed * GetCompressedBlockSize());
|
t.m_OutBuf = m_OutBuf + (blocksProcessed * GetCompressedBlockSize());
|
||||||
t.m_InBuf = m_Image.GetPixels() + (blocksProcessed * GetUncompressedBlockSize());
|
t.m_InBuf = m_ImageData + (blocksProcessed * GetUncompressedBlockSize());
|
||||||
|
|
||||||
blocksProcessed += numBlocksThisThread;
|
blocksProcessed += numBlocksThisThread;
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
|
|
||||||
class ThreadGroup {
|
class ThreadGroup {
|
||||||
public:
|
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();
|
~ThreadGroup();
|
||||||
|
|
||||||
bool PrepareThreads();
|
bool PrepareThreads();
|
||||||
|
@ -74,7 +74,8 @@ class ThreadGroup {
|
||||||
boost::thread *m_ThreadHandles[kMaxNumThreads];
|
boost::thread *m_ThreadHandles[kMaxNumThreads];
|
||||||
|
|
||||||
// State variables.
|
// State variables.
|
||||||
const ImageFile &m_Image;
|
const unsigned int m_ImageDataSz;
|
||||||
|
const unsigned char *const m_ImageData;
|
||||||
const CompressionFunc m_Func;
|
const CompressionFunc m_Func;
|
||||||
unsigned char *m_OutBuf;
|
unsigned char *m_OutBuf;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
#include "ImageFileFormat.h"
|
#include "ImageFileFormat.h"
|
||||||
|
|
||||||
|
// Forward declare
|
||||||
|
class CompressedImage;
|
||||||
|
|
||||||
|
// Class definition
|
||||||
class ImageFile {
|
class ImageFile {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -13,7 +17,9 @@ public:
|
||||||
|
|
||||||
unsigned int GetWidth() const { return m_Width; }
|
unsigned int GetWidth() const { return m_Width; }
|
||||||
unsigned int GetHeight() const { return m_Height; }
|
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:
|
private:
|
||||||
unsigned int m_Handle;
|
unsigned int m_Handle;
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "TexComp.h"
|
||||||
#include "ImageFile.h"
|
#include "ImageFile.h"
|
||||||
#include "ImageLoader.h"
|
#include "ImageLoader.h"
|
||||||
|
#include "CompressedImage.h"
|
||||||
|
|
||||||
#ifdef PNG_FOUND
|
#ifdef PNG_FOUND
|
||||||
# include "ImageLoaderPNG.h"
|
# include "ImageLoaderPNG.h"
|
||||||
|
@ -302,3 +304,25 @@ unsigned char *ImageFile::ReadFileData(const char *filename) {
|
||||||
return rawData;
|
return rawData;
|
||||||
}
|
}
|
||||||
#endif
|
#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