mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2026-07-11 03:55:25 +00:00
237 lines
5.3 KiB
C++
237 lines
5.3 KiB
C++
#include "TexComp.h"
|
|
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
#include "BC7Compressor.h"
|
|
#include "WorkerQueue.h"
|
|
#include "ThreadGroup.h"
|
|
|
|
#include "ImageFile.h"
|
|
#include "Image.h"
|
|
|
|
|
|
template <typename T>
|
|
static T min(const T &a, const T &b) {
|
|
return (a < b)? a : b;
|
|
}
|
|
|
|
template <typename T>
|
|
static T max(const T &a, const T &b) {
|
|
return (a > b)? a : b;
|
|
}
|
|
|
|
template <typename T>
|
|
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)
|
|
, iNumThreads(1)
|
|
, iQuality(50)
|
|
, iNumCompressions(1)
|
|
{
|
|
clamp(iQuality, 0, 256);
|
|
}
|
|
|
|
static CompressionFuncWithStats ChooseFuncFromSettingsWithStats(const SCompressionSettings &s) {
|
|
switch(s.format) {
|
|
case eCompressionFormat_BPTC:
|
|
{
|
|
return BC7C::CompressImageBC7Stats;
|
|
}
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) {
|
|
switch(s.format) {
|
|
case eCompressionFormat_BPTC:
|
|
{
|
|
BC7C::SetQualityLevel(s.iQuality);
|
|
#ifdef HAS_SSE_41
|
|
if(s.bUseSIMD) {
|
|
return BC7C::CompressImageBC7SIMD;
|
|
}
|
|
else {
|
|
#endif
|
|
return BC7C::CompressImageBC7;
|
|
#ifdef HAS_SSE_41
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void ReportError(const char *msg) {
|
|
fprintf(stderr, "TexComp -- %s\n", msg);
|
|
}
|
|
|
|
static double CompressImageInSerial(
|
|
const unsigned char *imgData,
|
|
const unsigned int imgDataSz,
|
|
const SCompressionSettings &settings,
|
|
unsigned char *outBuf
|
|
) {
|
|
CompressionFunc f = ChooseFuncFromSettings(settings);
|
|
CompressionFuncWithStats fStats = ChooseFuncFromSettingsWithStats(settings);
|
|
|
|
double cmpTimeTotal = 0.0;
|
|
|
|
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...
|
|
if(fStats && settings.pStatManager) {
|
|
(*fStats)(imgData, outBuf, imgDataSz / 16, 4, *(settings.pStatManager));
|
|
}
|
|
else {
|
|
(*f)(imgData, outBuf, imgDataSz / 16, 4);
|
|
}
|
|
|
|
stopWatch.Stop();
|
|
|
|
cmpTimeTotal += stopWatch.TimeInMilliseconds();
|
|
}
|
|
|
|
double cmpTime = cmpTimeTotal / double(settings.iNumCompressions);
|
|
return cmpTime;
|
|
}
|
|
|
|
static double CompressImageWithThreads(
|
|
const unsigned char *imgData,
|
|
const unsigned int imgDataSz,
|
|
const SCompressionSettings &settings,
|
|
unsigned char *outBuf
|
|
) {
|
|
|
|
CompressionFunc f = ChooseFuncFromSettings(settings);
|
|
|
|
ThreadGroup tgrp (settings.iNumThreads, imgData, imgDataSz, f, outBuf);
|
|
if(!(tgrp.PrepareThreads())) {
|
|
assert(!"Thread group failed to prepare threads?!");
|
|
return -1.0f;
|
|
}
|
|
|
|
double cmpTimeTotal = 0.0;
|
|
for(int i = 0; i < settings.iNumCompressions; i++) {
|
|
if(i > 0)
|
|
tgrp.PrepareThreads();
|
|
|
|
tgrp.Start();
|
|
tgrp.Join();
|
|
|
|
StopWatch stopWatch = tgrp.GetStopWatch();
|
|
cmpTimeTotal += tgrp.GetStopWatch().TimeInMilliseconds();
|
|
}
|
|
|
|
tgrp.CleanUpThreads();
|
|
|
|
double cmpTime = cmpTimeTotal / double(settings.iNumCompressions);
|
|
return cmpTime;
|
|
}
|
|
|
|
static double CompressImageWithWorkerQueue(
|
|
const unsigned char *imgData,
|
|
const unsigned int imgDataSz,
|
|
const SCompressionSettings &settings,
|
|
unsigned char *outBuf
|
|
) {
|
|
CompressionFunc f = ChooseFuncFromSettings(settings);
|
|
|
|
WorkerQueue wq (
|
|
settings.iNumCompressions,
|
|
settings.iNumThreads,
|
|
settings.iJobSize,
|
|
imgData,
|
|
imgDataSz,
|
|
f,
|
|
outBuf
|
|
);
|
|
|
|
wq.Run();
|
|
|
|
return wq.GetStopWatch().TimeInMilliseconds() /
|
|
double(settings.iNumCompressions);
|
|
}
|
|
|
|
bool CompressImageData(
|
|
const unsigned char *data,
|
|
const unsigned int dataSz,
|
|
unsigned char *cmpData,
|
|
const unsigned int cmpDataSz,
|
|
const SCompressionSettings &settings
|
|
) {
|
|
|
|
// Make sure that platform supports SSE if they chose this
|
|
// option...
|
|
#ifndef HAS_SSE_41
|
|
if(settings.bUseSIMD) {
|
|
ReportError("Platform does not support SIMD!\n");
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
if(dataSz <= 0) {
|
|
ReportError("No data sent to compress!");
|
|
return false;
|
|
}
|
|
|
|
// Allocate data based on the compression method
|
|
int cmpDataSzNeeded = 0;
|
|
switch(settings.format) {
|
|
case eCompressionFormat_DXT1: cmpDataSzNeeded = dataSz / 8;
|
|
case eCompressionFormat_DXT5: cmpDataSzNeeded = dataSz / 4;
|
|
case eCompressionFormat_BPTC: cmpDataSzNeeded = dataSz / 4;
|
|
}
|
|
|
|
if(cmpDataSzNeeded == 0) {
|
|
ReportError("Unknown compression format");
|
|
return false;
|
|
}
|
|
else if(cmpDataSzNeeded > cmpDataSz) {
|
|
ReportError("Not enough space for compressed data!");
|
|
return false;
|
|
}
|
|
|
|
CompressionFunc f = ChooseFuncFromSettings(settings);
|
|
if(f) {
|
|
|
|
double cmpMSTime = 0.0;
|
|
|
|
if(settings.iNumThreads > 1) {
|
|
if(settings.iJobSize > 0)
|
|
cmpMSTime = CompressImageWithWorkerQueue(data, dataSz, settings, cmpData);
|
|
else
|
|
cmpMSTime = CompressImageWithThreads(data, dataSz, settings, cmpData);
|
|
}
|
|
else {
|
|
cmpMSTime = CompressImageInSerial(data, dataSz, settings, cmpData);
|
|
}
|
|
|
|
// Report compression time
|
|
fprintf(stdout, "Compression time: %0.3f ms\n", cmpMSTime);
|
|
}
|
|
else {
|
|
ReportError("Could not find adequate compression function for specified settings");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|