mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Added texture deposterization option
This commit is contained in:
parent
ac9f271078
commit
3c2ee6bd65
7 changed files with 94 additions and 9 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -92,6 +92,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
|
||||
|
||||
// 3x3 convolution with Neumann boundary conditions, parallelizable
|
||||
|
@ -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
|
||||
|
@ -309,6 +368,13 @@ 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:
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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.
Loading…
Add table
Reference in a new issue