Added texture deposterization option

This commit is contained in:
Peter Thoman 2013-05-03 16:21:46 +02:00
parent ac9f271078
commit 3c2ee6bd65
7 changed files with 94 additions and 9 deletions

View file

@ -117,6 +117,7 @@ void Config::Load(const char *iniFileName)
#endif
graphics->Get("TexScalingLevel", &iTexScalingLevel, 1);
graphics->Get("TexScalingType", &iTexScalingType, 0);
graphics->Get("TexDeposterize", &bTexDeposterize, false);
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
sound->Get("Enable", &bEnableSound, true);
@ -200,6 +201,7 @@ void Config::Save()
graphics->Set("MipMap", bMipMap);
graphics->Set("TexScalingLevel", iTexScalingLevel);
graphics->Set("TexScalingType", iTexScalingType);
graphics->Set("TexDeposterize", bTexDeposterize);
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
sound->Set("Enable", bEnableSound);

View file

@ -74,6 +74,7 @@ public:
bool bMipMap;
int iTexScalingLevel; // 1 = off, 2 = 2x, ..., 5 = 5x
int iTexScalingType; // 0 = xBRZ, 1 = Hybrid
bool bTexDeposterize;
// Sound
bool bEnableSound;

View file

@ -91,6 +91,13 @@ namespace {
#define DISTANCE(_p1,_p2) ( abs((int)((int)(R(_p1))-R(_p2))) + abs((int)((int)(G(_p1))-G(_p2))) \
+ abs((int)((int)(B(_p1)-B(_p2)))) + abs((int)((int)(A(_p1)-A(_p2)))) )
// this is sadly much faster than an inline function with a loop, at least in VC10
#define MIX_PIXELS(_p0, _p1, _factors) \
( (R(_p0)*(_factors)[0] + R(_p1)*(_factors)[1])/255 << 0 ) | \
( (G(_p0)*(_factors)[0] + G(_p1)*(_factors)[1])/255 << 8 ) | \
( (B(_p0)*(_factors)[0] + B(_p1)*(_factors)[1])/255 << 16 ) | \
( (A(_p0)*(_factors)[0] + A(_p1)*(_factors)[1])/255 << 24 )
#define BLOCK_SIZE 32
@ -117,6 +124,64 @@ namespace {
}
}
void deposterizeH(u32* data, u32* out, int w, int l, int u) {
static const int T = 8;
for(int y = l; y < u; ++y) {
for(int x = 0; x < w; ++x) {
int inpos = y*w + x;
u32 center = data[inpos];
if(x==0 || x==w-1) {
out[y*w + x] = center;
continue;
}
u32 left = data[inpos - 1];
u32 right = data[inpos + 1];
out[y*w + x] = 0;
for(int c=0; c<4; ++c) {
u8 lc = (( left>>c*8)&0xFF);
u8 cc = ((center>>c*8)&0xFF);
u8 rc = (( right>>c*8)&0xFF);
if((lc != rc) && ((lc == cc && abs((int)((int)rc)-cc) <= T) || (rc == cc && abs((int)((int)lc)-cc) <= T))) {
// blend this component
out[y*w + x] |= ((rc+lc)/2) << (c*8);
} else {
// no change for this component
out[y*w + x] |= cc << (c*8);
}
}
}
}
}
void deposterizeV(u32* data, u32* out, int w, int h, int l, int u) {
static const int T = 8;
for(int xb = 0; xb < w/BLOCK_SIZE+1; ++xb) {
for(int y = l; y < u; ++y) {
for(int x = xb*BLOCK_SIZE; x < (xb+1)*BLOCK_SIZE && x < w; ++x) {
u32 center = data[ y * w + x];
if(y==0 || y==h-1) {
out[y*w + x] = center;
continue;
}
u32 upper = data[(y-1) * w + x];
u32 lower = data[(y+1) * w + x];
out[y*w + x] = 0;
for(int c=0; c<4; ++c) {
u8 uc = (( upper>>c*8)&0xFF);
u8 cc = ((center>>c*8)&0xFF);
u8 lc = (( lower>>c*8)&0xFF);
if((uc != lc) && ((uc == cc && abs((int)((int)lc)-cc) <= T) || (lc == cc && abs((int)((int)uc)-cc) <= T))) {
// blend this component
out[y*w + x] |= ((lc+uc)/2) << (c*8);
} else {
// no change for this component
out[y*w + x] |= cc << (c*8);
}
}
}
}
}
}
void generateDistanceMask(u32* data, u32* out, int width, int height, int l, int u) {
for(int yb = 0; yb < (u-l)/BLOCK_SIZE+1; ++yb) {
for(int xb = 0; xb < width/BLOCK_SIZE+1; ++xb) {
@ -146,13 +211,6 @@ namespace {
}
}
// this is sadly much faster than an inline function with a loop, at least in VC10
#define MIX_PIXELS(_p0, _p1, _factors) \
( (R(_p0)*(_factors)[0] + R(_p1)*(_factors)[1])/255 << 0 ) | \
( (G(_p0)*(_factors)[0] + G(_p1)*(_factors)[1])/255 << 8 ) | \
( (B(_p0)*(_factors)[0] + B(_p1)*(_factors)[1])/255 << 16 ) | \
( (A(_p0)*(_factors)[0] + A(_p1)*(_factors)[1])/255 << 24 )
void mix(u32* data, u32* source, u32* mask, u32 maskmax, int width, int l, int u) {
for(int y = l; y < u; ++y) {
for(int x = 0; x < width; ++x) {
@ -236,6 +294,7 @@ namespace {
}
}
#undef BLOCK_SIZE
#undef MIX_PIXELS
#undef DISTANCE
#undef R
@ -308,7 +367,14 @@ void TextureScaler::Scale(u32* &data, GLenum &dstFmt, int &width, int &height, i
// convert texture to correct format for scaling
ConvertTo8888(dstFmt, data, inputBuf, width, height);
// deposterize
if(g_Config.bTexDeposterize) {
bufDeposter.resize(width*height);
DePosterize(inputBuf, bufDeposter.data(), width, height);
inputBuf = bufDeposter.data();
}
// scale
switch(g_Config.iTexScalingType) {
case XBRZ:
@ -377,6 +443,14 @@ void TextureScaler::ScaleHybrid(int factor, u32* source, u32* dest, int width, i
GlobalThreadPool::Loop(bind(&mix, dest, bufTmp2.data(), bufTmp3.data(), 8192, width*factor, p::_1, p::_2), 0, height*factor);
}
void TextureScaler::DePosterize(u32* source, u32* dest, int width, int height) {
bufTmp3.resize(width*height);
GlobalThreadPool::Loop(std::bind(&deposterizeH, source, bufTmp3.data(), width, p::_1, p::_2), 0, height);
GlobalThreadPool::Loop(std::bind(&deposterizeV, bufTmp3.data(), dest, width, height, p::_1, p::_2), 0, height);
GlobalThreadPool::Loop(std::bind(&deposterizeH, dest, bufTmp3.data(), width, p::_1, p::_2), 0, height);
GlobalThreadPool::Loop(std::bind(&deposterizeV, bufTmp3.data(), dest, width, height, p::_1, p::_2), 0, height);
}
void TextureScaler::ConvertTo8888(GLenum format, u32* source, u32* &dest, int width, int height) {
switch(format) {
case GL_UNSIGNED_BYTE:

View file

@ -39,10 +39,12 @@ private:
void ScaleHybrid(int factor, u32* source, u32* dest, int width, int height);
void ConvertTo8888(GLenum format, u32* source, u32* &dest, int width, int height);
void DePosterize(u32* source, u32* dest, int width, int height);
bool IsEmptyOrFlat(u32* data, int pixels, GLenum fmt);
// depending on the factor and texture sizes, these can get pretty large
// maximum is (100 MB total for a 512 by 512 texture with scaling factor 5 and hybrid scaling)
// of course, scaling factor 5 is totally silly anyway
SimpleBuf<u32> bufInput, bufOutput, bufTmp1, bufTmp2, bufTmp3;
SimpleBuf<u32> bufInput, bufDeposter, bufOutput, bufTmp1, bufTmp2, bufTmp3;
};

View file

@ -528,6 +528,11 @@ namespace MainWindow
setTexScalingType(TextureScaler::HYBRID);
break;
case ID_TEXTURESCALING_DEPOSTERIZE:
g_Config.bTexDeposterize = !g_Config.bTexDeposterize;
if(gpu) gpu->ClearCacheNextFrame();
break;
case ID_OPTIONS_BUFFEREDRENDERING:
g_Config.bBufferedRendering = !g_Config.bBufferedRendering;
if (gpu)
@ -807,6 +812,7 @@ namespace MainWindow
CHECKITEM(ID_OPTIONS_USEMEDIAENGINE, g_Config.bUseMediaEngine);
CHECKITEM(ID_OPTIONS_MIPMAP, g_Config.bMipMap);
CHECKITEM(ID_EMULATION_SOUND, g_Config.bEnableSound);
CHECKITEM(ID_TEXTURESCALING_DEPOSTERIZE, g_Config.bTexDeposterize);
EnableMenuItem(menu,ID_EMULATION_RUN, (Core_IsStepping() || globalUIState == UISTATE_PAUSEMENU) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu,ID_EMULATION_PAUSE, globalUIState == UISTATE_INGAME ? MF_ENABLED : MF_GRAYED);

Binary file not shown.

Binary file not shown.