From 3c2ee6bd65acc169d8812a6b0763bfa96fc0568d Mon Sep 17 00:00:00 2001 From: Peter Thoman Date: Fri, 3 May 2013 16:21:46 +0200 Subject: [PATCH] Added texture deposterization option --- Core/Config.cpp | 2 + Core/Config.h | 1 + GPU/GLES/TextureScaler.cpp | 90 +++++++++++++++++++++++++++++++++---- GPU/GLES/TextureScaler.h | 4 +- Windows/WndMainWindow.cpp | 6 +++ Windows/ppsspp.rc | Bin 37596 -> 37842 bytes Windows/resource.h | Bin 164264 -> 164358 bytes 7 files changed, 94 insertions(+), 9 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 7f5ec88649..d7feb25fe9 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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); diff --git a/Core/Config.h b/Core/Config.h index 8058bf51e2..2d54d90f71 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -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; diff --git a/GPU/GLES/TextureScaler.cpp b/GPU/GLES/TextureScaler.cpp index 13e6b0174e..5d92bd7c37 100644 --- a/GPU/GLES/TextureScaler.cpp +++ b/GPU/GLES/TextureScaler.cpp @@ -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: diff --git a/GPU/GLES/TextureScaler.h b/GPU/GLES/TextureScaler.h index 6991cbd375..5451722e97 100644 --- a/GPU/GLES/TextureScaler.h +++ b/GPU/GLES/TextureScaler.h @@ -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 bufInput, bufOutput, bufTmp1, bufTmp2, bufTmp3; + SimpleBuf bufInput, bufDeposter, bufOutput, bufTmp1, bufTmp2, bufTmp3; }; diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index acf24b7732..e35320d38a 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -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); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 58592b51f52d0b80ee51bc0f297d1d5bdc1ea9b6..7a74baeaf71fd0f71cb10af28910a594c15d115b 100644 GIT binary patch delta 156 zcmcb!lHKK D>3%kY delta 98 zcmcb#oaxR|rVU%lS^XK(7}6#OR+vv#s8pFOR$<0yG+D4Je)75s6Gme&%catU(FDx8 uRcSI=py~>H1%neq5JS}DzzS2aF1Kon$qm&Flk*C7CI|G}Y!0Yx5(5D4J|qtS diff --git a/Windows/resource.h b/Windows/resource.h index d74c24156cf1742b55f606014f8ab1fd01e20552..d581544bcbb7826669859bd04857267a87438969 100644 GIT binary patch delta 46 zcmZ3{%+=Py)zHGYg{i7|`nh~21yL6USB3xve}-U&5C&I