diff --git a/Core/Config.h b/Core/Config.h index fc96c761c6..b413058436 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -161,7 +161,7 @@ public: bool bVendorBugChecksEnabled; int iRenderingMode; // 0 = non-buffered rendering 1 = buffered rendering - int iTexFiltering; // 1 = off , 2 = nearest , 3 = linear , 4 = linear(CG) + int iTexFiltering; // 1 = auto , 2 = nearest , 3 = linear , 4 = auto max quality int iBufFilter; // 1 = linear, 2 = nearest int iSmallDisplayZoomType; // Used to fit display into screen 0 = stretch, 1 = partial stretch, 2 = auto scaling, 3 = manual scaling. float fSmallDisplayOffsetX; // Along with Y it goes from 0.0 to 1.0, XY (0.5, 0.5) = center of the screen diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index a3899b0646..debeee4808 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -45,6 +45,13 @@ enum { ROTATION_AUTO_HORIZONTAL = 5, }; +enum TextureFiltering { + TEX_FILTER_AUTO = 1, + TEX_FILTER_FORCE_NEAREST = 2, + TEX_FILTER_FORCE_LINEAR = 3, + TEX_FILTER_AUTO_MAX_QUALITY = 4, +}; + enum BufferFilter { SCALE_LINEAR = 1, SCALE_NEAREST = 2, diff --git a/GPU/Common/SplineCommon.cpp b/GPU/Common/SplineCommon.cpp index 86226907f0..f1e47b257b 100644 --- a/GPU/Common/SplineCommon.cpp +++ b/GPU/Common/SplineCommon.cpp @@ -532,7 +532,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic int vertexSize = vdecoder->VertexSize(); if (vertexSize != sizeof(SimpleVertex)) { - ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, (int)sizeof(SimpleVertex)); + ERROR_LOG(G3D, "Something went really wrong, vertex size: %d vs %d", vertexSize, (int)sizeof(SimpleVertex)); } // Make an array of pointers to the control points, to get rid of indices. diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 36d72ef0af..097e036be5 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -241,10 +241,18 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac } break; case TEX_FILTER_FORCE_NEAREST: - default: // Just force to nearest without checks. Safe (but ugly). forceFiltering = TEX_FILTER_FORCE_NEAREST; break; + case TEX_FILTER_AUTO_MAX_QUALITY: + default: + forceFiltering = TEX_FILTER_AUTO_MAX_QUALITY; + if (gstate.isModeThrough() && g_Config.iInternalResolution != 1) { + bool uglyColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && gstate.getColorTestRef() != 0; + if (uglyColorTest) + forceFiltering = TEX_FILTER_FORCE_NEAREST; + } + break; } } @@ -260,6 +268,18 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.magFilt = 0; key.minFilt = 0; break; + case TEX_FILTER_AUTO_MAX_QUALITY: + // NOTE: We do not override magfilt here. If a game should have pixellated filtering, + // let it keep it. But we do enforce minification and mipmap filtering and max out the level. + // Later we'll also auto-generate any missing mipmaps. + key.minFilt = 1; + key.mipFilt = 1; + key.maxLevel = 9 * 256; + key.lodBias = 0.0f; + if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + key.aniso = true; + } + break; } return key; diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index b00958a296..863e509cba 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -27,16 +27,11 @@ enum CheckAlphaResult { #include "Common/Common.h" #include "Common/Swap.h" #include "Core/MemMap.h" +#include "Core/ConfigValues.h" #include "GPU/ge_constants.h" #include "GPU/Common/TextureDecoderNEON.h" #include "GPU/GPUState.h" -enum TextureFiltering { - TEX_FILTER_AUTO = 1, - TEX_FILTER_FORCE_NEAREST = 2, - TEX_FILTER_FORCE_LINEAR = 3, -}; - void SetupTextureDecoder(); // Pitch must be aligned to 16 bits (as is the case on a PSP) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 7a679a8566..628f133f98 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -819,6 +819,10 @@ void DrawEngineVulkan::DoFlush() { } shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform + if (!vshader) { + // We're screwed. + return; + } _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index f39c43a730..e2a02e3497 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -751,6 +751,15 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { // such as when using replacement textures - but let's keep the same amount of levels. int maxLevelToGenerate = maxLevel; + if (g_Config.iTexFiltering == TEX_FILTER_AUTO_MAX_QUALITY) { + // Boost the number of mipmaps. + int maxPossibleMipmaps = log2i(std::min(gstate.getTextureWidth(0), gstate.getTextureHeight(0))); + if (maxPossibleMipmaps != maxLevelToGenerate) { + maxLevelToGenerate = maxPossibleMipmaps; + } + } + + // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. VkFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat()); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 7c94269ff8..8240e45137 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -547,7 +547,7 @@ void GameSettingsScreen::CreateViews() { PopupMultiChoice *anisoFiltering = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAnisotropyLevel, gr->T("Anisotropic Filtering"), anisoLevels, 0, ARRAY_SIZE(anisoLevels), gr->GetName(), screenManager())); anisoFiltering->SetDisabledPtr(&g_Config.bSoftwareRendering); - static const char *texFilters[] = { "Auto", "Nearest", "Linear" }; + 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), gr->GetName(), screenManager())); static const char *bufFilters[] = { "Linear", "Nearest", }; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 026540f443..a4c958fde3 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -1225,11 +1225,12 @@ namespace MainWindow { ID_OPTIONS_TEXTUREFILTERING_AUTO, ID_OPTIONS_NEARESTFILTERING, ID_OPTIONS_LINEARFILTERING, + ID_OPTIONS_AUTOMAXQUALITYFILTERING, }; if (g_Config.iTexFiltering < TEX_FILTER_AUTO) g_Config.iTexFiltering = TEX_FILTER_AUTO; - else if (g_Config.iTexFiltering > TEX_FILTER_FORCE_LINEAR) - g_Config.iTexFiltering = TEX_FILTER_FORCE_LINEAR; + else if (g_Config.iTexFiltering > TEX_FILTER_AUTO_MAX_QUALITY) + g_Config.iTexFiltering = TEX_FILTER_AUTO_MAX_QUALITY; for (int i = 0; i < ARRAY_SIZE(texfilteringitems); i++) { CheckMenuItem(menu, texfilteringitems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iTexFiltering ? MF_CHECKED : MF_UNCHECKED)); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index cd0655dc24..b9ea154e26 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -632,6 +632,7 @@ BEGIN MENUITEM "Auto", ID_OPTIONS_TEXTUREFILTERING_AUTO MENUITEM "Nearest", ID_OPTIONS_NEARESTFILTERING MENUITEM "Linear", ID_OPTIONS_LINEARFILTERING + MENUITEM "Auto Max Quality", ID_OPTIONS_AUTOMAXQUALITYFILTERING END POPUP "Screen Scaling Filter", ID_OPTIONS_SCREENFILTER_MENU BEGIN diff --git a/Windows/resource.h b/Windows/resource.h index 1121a59da5..27c95fd839 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -207,6 +207,7 @@ #define ID_OPTIONS_HARDWARETRANSFORM 40030 #define IDC_STEPHLE 40032 #define ID_OPTIONS_LINEARFILTERING 40033 +#define ID_OPTIONS_AUTOMAXQUALITYFILTERING 40043 #define ID_FILE_QUICKSAVESTATE 40034 #define ID_FILE_QUICKLOADSTATE 40035 #define ID_FILE_QUICKSAVESTATE_HC 40036