diff --git a/Core/Config.cpp b/Core/Config.cpp index 27f6a0cf25f1..588b3e34c02f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -611,6 +611,7 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("HardwareTransform", &g_Config.bHardwareTransform, true, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("SoftwareSkinning", &g_Config.bSoftwareSkinning, true, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("TextureFiltering", &g_Config.iTexFiltering, 1, CfgFlag::PER_GAME | CfgFlag::REPORT), + ConfigSetting("Smart2DTexFiltering", &g_Config.bSmart2DTexFiltering, false, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("InternalResolution", &g_Config.iInternalResolution, &DefaultInternalResolution, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("AndroidHwScale", &g_Config.iAndroidHwScale, &DefaultAndroidHwScale, CfgFlag::DEFAULT), ConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, CfgFlag::PER_GAME | CfgFlag::REPORT), diff --git a/Core/Config.h b/Core/Config.h index 8c7c9ef5f8b8..976776086187 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -172,6 +172,7 @@ struct Config { bool bDisableRangeCulling; int iTexFiltering; // 1 = auto , 2 = nearest , 3 = linear , 4 = auto max quality + bool bSmart2DTexFiltering; bool bDisplayStretch; // Automatically matches the aspect ratio of the window. int iDisplayFilter; // 1 = linear, 2 = nearest diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 204a1e4df8f7..50dd4d43d8b8 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -585,7 +585,7 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy inds = newInds; } - } else if (throughmode) { + } else if (throughmode && g_Config.bSmart2DTexFiltering) { // We check some common cases for pixel mapping. // TODO: It's not really optimal that some previous step has removed the triangle strip. if (vertexCount <= 6 && prim == GE_PRIM_TRIANGLES) { @@ -593,13 +593,12 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy // 0-1 1-3 3-2 2-0. Maybe can even skip the last one. Probably some simple math can get us that sequence. // Unfortunately we need to reverse the previous UV scaling operation. Fortunately these are powers of two // so the operations are exact. - bool pmapped = true; + bool pixelMapped = true; const u16 *indsIn = (const u16 *)inds; for (int t = 0; t < vertexCount; t += 3) { float uscale = gstate_c.curTextureWidth; float vscale = gstate_c.curTextureHeight; struct { int a; int b; } pairs[] = { {0, 1}, {1, 2}, {2, 0} }; - for (int i = 0; i < ARRAY_SIZE(pairs); i++) { int a = indsIn[t + pairs[i].a]; int b = indsIn[t + pairs[i].b]; @@ -608,11 +607,14 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy float dx = fabsf(transformed[a].x - transformed[b].x); float dy = fabsf(transformed[a].y - transformed[b].y); if (du != dx || dv != dy) { - pmapped = false; + pixelMapped = false; } } + if (!pixelMapped) { + break; + } } - result->pixelMapped = pmapped; + result->pixelMapped = pixelMapped; } } } @@ -662,21 +664,23 @@ void SoftwareTransform::ExpandRectangles(int vertexCount, int &maxIndex, u16 *&i vscale /= gstate_c.curTextureHeight; } - bool pixelMapped = true; + bool pixelMapped = g_Config.bSmart2DTexFiltering; for (int i = 0; i < vertexCount; i += 2) { const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]]; const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]]; - float dx = transVtxBR.x - transVtxTL.x; - float dy = transVtxBR.y - transVtxTL.y; - float du = transVtxBR.u - transVtxTL.u; - float dv = transVtxBR.v - transVtxTL.v; + if (pixelMapped) { + float dx = transVtxBR.x - transVtxTL.x; + float dy = transVtxBR.y - transVtxTL.y; + float du = transVtxBR.u - transVtxTL.u; + float dv = transVtxBR.v - transVtxTL.v; - // NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI. - // Though, there could be false positives in other games due to this. Let's see if it is a problem... - if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) { - pixelMapped = false; + // NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI. + // Though, there could be false positives in other games due to this. Let's see if it is a problem... + if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) { + pixelMapped = false; + } } // We have to turn the rectangle into two triangles, so 6 points. diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index bbc4008769d8..12c67fa7bbda 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -553,6 +553,8 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) static const char *texFilters[] = { "Auto", "Nearest", "Linear", "Auto Max Quality"}; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexFiltering, gr->T("Texture Filter"), texFilters, 1, ARRAY_SIZE(texFilters), I18NCat::GRAPHICS, screenManager())); + graphicsSettings->Add(new CheckBox(&g_Config.bSmart2DTexFiltering, gr->T("Smart 2D texture filter"))); + #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) bool showCardboardSettings = deviceType != DEVICE_TYPE_VR; #else diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index b78e9f47cedf..b4c4d1c9ba83 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -283,6 +283,7 @@ namespace MainWindow { TranslateMenuItem(menu, ID_OPTIONS_NEARESTFILTERING); TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING); TranslateMenuItem(menu, ID_OPTIONS_AUTOMAXQUALITYFILTERING); + TranslateMenuItem(menu, ID_OPTIONS_SMART2DTEXTUREFILTERING); TranslateMenuItem(menu, ID_OPTIONS_SCREENFILTER_MENU); TranslateMenuItem(menu, ID_OPTIONS_BUFLINEARFILTER); TranslateMenuItem(menu, ID_OPTIONS_BUFNEARESTFILTER); @@ -868,6 +869,8 @@ namespace MainWindow { case ID_OPTIONS_LINEARFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_LINEAR; break; case ID_OPTIONS_AUTOMAXQUALITYFILTERING: g_Config.iTexFiltering = TEX_FILTER_AUTO_MAX_QUALITY; break; + case ID_OPTIONS_SMART2DTEXTUREFILTERING: g_Config.bSmart2DTexFiltering = !g_Config.bSmart2DTexFiltering; break; + case ID_OPTIONS_BUFLINEARFILTER: g_Config.iDisplayFilter = SCALE_LINEAR; break; case ID_OPTIONS_BUFNEARESTFILTER: g_Config.iDisplayFilter = SCALE_NEAREST; break; @@ -962,6 +965,7 @@ namespace MainWindow { CHECKITEM(ID_OPTIONS_VSYNC, g_Config.bVSync); CHECKITEM(ID_OPTIONS_TOPMOST, g_Config.bTopMost); CHECKITEM(ID_OPTIONS_PAUSE_FOCUS, g_Config.bPauseOnLostFocus); + CHECKITEM(ID_OPTIONS_SMART2DTEXTUREFILTERING, g_Config.bSmart2DTexFiltering); CHECKITEM(ID_EMULATION_SOUND, g_Config.bEnableSound); CHECKITEM(ID_TEXTURESCALING_DEPOSTERIZE, g_Config.bTexDeposterize); CHECKITEM(ID_EMULATION_CHEATS, g_Config.bEnableCheats); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index f3c48d74cd9a..6b3a170b7070 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -662,6 +662,8 @@ BEGIN MENUITEM "Nearest", ID_OPTIONS_NEARESTFILTERING MENUITEM "Linear", ID_OPTIONS_LINEARFILTERING MENUITEM "Auto Max Quality", ID_OPTIONS_AUTOMAXQUALITYFILTERING + MENUITEM "", 0, MFT_SEPARATOR + MENUITEM "Smart 2D Texture Filtering", ID_OPTIONS_SMART2DTEXTUREFILTERING END POPUP "Screen Scaling Filter", ID_OPTIONS_SCREENFILTER_MENU BEGIN diff --git a/Windows/resource.h b/Windows/resource.h index efec1f414f34..fda3f1ea272c 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -162,6 +162,7 @@ #define IDC_STEPHLE 40032 #define ID_OPTIONS_LINEARFILTERING 40033 #define ID_OPTIONS_AUTOMAXQUALITYFILTERING 40043 +#define ID_OPTIONS_SMART2DTEXTUREFILTERING 40003 #define ID_FILE_QUICKSAVESTATE 40034 #define ID_FILE_QUICKLOADSTATE 40035 #define ID_FILE_QUICKSAVESTATE_HC 40036