mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2025-01-23 21:31:03 +00:00
Plug in the infrastructure to start passing images to be compressed.
This commit is contained in:
parent
995c237e5e
commit
1093447055
|
@ -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;
|
||||
|
|
|
@ -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} )
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
const uint32 *pixels = reinterpret_cast<const uint32 *>(dcj.inBuf);
|
||||
img(i, j).UnpackRGBA(pixels[j * 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(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
|
||||
|
|
Loading…
Reference in a new issue