diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index 5873377d81b48..b7411f62894ab 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -155,7 +155,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget* SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy", s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0"); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.dithering, "EmuCore/GS", "dithering_ps2", 2); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.mipmapping, "EmuCore/GS", "hw_mipmap", true); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.hwMipmapMode, "EmuCore/GS", "hw_mipmap_mode", + static_cast(GSHWMipmapMode::Enabled)); SettingWidgetBinder::BindWidgetToIntSetting( sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast(AccBlendLevel::Basic)); SettingWidgetBinder::BindWidgetToIntSetting( @@ -506,8 +507,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget* "FMV resolution will remain unchanged, as the video files are pre-rendered.")); dialog->registerWidgetHelp( - m_ui.mipmapping, tr("Mipmapping"), tr("Checked"), tr("Enables mipmapping, which some games require to render correctly.")); - + m_ui.hwMipmapMode, tr("Mipmapping"), tr("Enabled"), tr("Enables mipmapping, which many games require to render correctly. " + "Unclamped allows higher texture detail levels to be used, but may break certain graphical effects.")); dialog->registerWidgetHelp( m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"), tr("Changes what filtering algorithm is used to map textures to surfaces.
" diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui index 220815443a8fa..99c667a3f3d9c 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui @@ -611,22 +611,46 @@ - + Manual Hardware Renderer Fixes - - - - Mipmapping - - - + + + + Mipmapping: + + + + + + + + Disabled + + + + + Enabled + + + + + All Levels + + + + + Unclamped + + + + diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 3b12a969482a3..aba5df9734d4f 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -286,6 +286,15 @@ enum class BiFiltering : u8 Forced_But_Sprite, }; +enum class GSHWMipmapMode : u8 +{ + Disabled, + Enabled, + AllLevels, + Unclamped, + MaxCount +}; + enum class TriFiltering : s8 { Automatic = -1, @@ -637,7 +646,6 @@ struct Pcsx2Config AutoFlushSW : 1, PreloadFrameWithGSData : 1, Mipmap : 1, - HWMipmap : 1, ManualUserHacks : 1, UserHacks_AlignSpriteX : 1, UserHacks_CPUFBConversion : 1, @@ -694,6 +702,7 @@ struct Pcsx2Config float UpscaleMultiplier = 1.0f; AccBlendLevel AccurateBlendingUnit = AccBlendLevel::Basic; + GSHWMipmapMode HWMipmapMode = GSHWMipmapMode::Disabled; BiFiltering TextureFiltering = BiFiltering::PS2; TexturePreloadingLevel TexturePreloading = TexturePreloadingLevel::Full; GSDumpCompressionMethod GSDumpCompression = GSDumpCompressionMethod::Zstandard; diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 98bb62ba502a5..7c285a53bef1c 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -762,7 +762,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) // reload texture cache when trilinear filtering or TC options change if ( - (GSIsHardwareRenderer() && GSConfig.HWMipmap != old_config.HWMipmap) || + (GSIsHardwareRenderer() && GSConfig.HWMipmapMode != old_config.HWMipmapMode) || GSConfig.TexturePreloading != old_config.TexturePreloading || GSConfig.TriFilter != old_config.TriFilter || GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion || @@ -1138,9 +1138,10 @@ BEGIN_HOTKEY_LIST(g_gs_hotkeys){"Screenshot", TRANSLATE_NOOP("Hotkeys", "Graphic [](s32 pressed) { if (!pressed) { - EmuConfig.GS.HWMipmap = !EmuConfig.GS.HWMipmap; + EmuConfig.GS.HWMipmapMode = + (EmuConfig.GS.HWMipmapMode >= GSHWMipmapMode::Enabled) ? GSHWMipmapMode::Disabled : GSHWMipmapMode::Enabled; Host::AddKeyedOSDMessage("ToggleMipmapMode", - EmuConfig.GS.HWMipmap ? + (EmuConfig.GS.HWMipmapMode >= GSHWMipmapMode::Enabled) ? TRANSLATE_STR("Hotkeys", "Hardware mipmapping is now enabled.") : TRANSLATE_STR("Hotkeys", "Hardware mipmapping is now disabled."), Host::OSD_INFO_DURATION); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 2563f239a6dac..cd7279ca66827 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -16,7 +16,7 @@ GSRendererHW::GSRendererHW() : GSRenderer() { MULTI_ISA_SELECT(GSRendererHWPopulateFunctions)(*this); - m_mipmap = GSConfig.HWMipmap; + m_mipmap = (GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled); SetTCOffset(); pxAssert(!g_texture_cache); @@ -88,7 +88,7 @@ void GSRendererHW::Reset(bool hardware_reset) void GSRendererHW::UpdateSettings(const Pcsx2Config::GSOptions& old_config) { GSRenderer::UpdateSettings(old_config); - m_mipmap = GSConfig.HWMipmap; + m_mipmap = (GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled); SetTCOffset(); } @@ -2398,7 +2398,8 @@ void GSRendererHW::Draw() GIFRegTEX0 TEX0 = {}; GSTextureCache::Source* src = nullptr; TextureMinMaxResult tmm; - + bool mipmap_active = false; + // Disable texture mapping if the blend is black and using alpha from vertex. if (m_process_texture) { @@ -2407,7 +2408,8 @@ void GSRendererHW::Draw() m_lod = GSVector2i(0, 0); // Code from the SW renderer - if (IsMipMapActive()) + mipmap_active = IsMipMapActive(); + if (mipmap_active) { const int interpolation = (context->TEX1.MMIN & 1) + 1; // 1: round, 2: tri @@ -2464,25 +2466,39 @@ void GSRendererHW::Draw() m_lod.x = std::min(m_lod.x, mxl); m_lod.y = std::min(m_lod.y, mxl); - TEX0 = (m_lod.x == 0) ? m_cached_ctx.TEX0 : GetTex0Layer(m_lod.x); + if (GSConfig.HWMipmapMode < GSHWMipmapMode::AllLevels) + { + TEX0 = (m_lod.x == 0) ? m_cached_ctx.TEX0 : GetTex0Layer(m_lod.x); - // upload the full chain (with offset) for the hash cache, in case some other texture uses more levels - // for basic mipmapping, we can get away with just doing the base image, since all the mips get generated anyway. - hash_lod_range = GSVector2i(m_lod.x, GSConfig.HWMipmap ? mxl : m_lod.x); + // upload the full chain (with offset) for the hash cache, in case some other texture uses more levels + // for basic mipmapping, we can get away with just doing the base image, since all the mips get generated anyway. + hash_lod_range = GSVector2i(m_lod.x, mxl); - MIP_CLAMP.MINU >>= m_lod.x; - MIP_CLAMP.MINV >>= m_lod.x; - MIP_CLAMP.MAXU >>= m_lod.x; - MIP_CLAMP.MAXV >>= m_lod.x; + MIP_CLAMP.MINU >>= m_lod.x; + MIP_CLAMP.MINV >>= m_lod.x; + MIP_CLAMP.MAXU >>= m_lod.x; + MIP_CLAMP.MAXV >>= m_lod.x; - for (int i = 0; i < m_lod.x; i++) + for (int i = 0; i < m_lod.x; i++) + { + m_vt.m_min.t *= 0.5f; + m_vt.m_max.t *= 0.5f; + } + } + else { - m_vt.m_min.t *= 0.5f; - m_vt.m_max.t *= 0.5f; + hash_lod_range = GSVector2i(0, mxl); + TEX0 = m_cached_ctx.TEX0; } - - GL_CACHE("Mipmap LOD %d %d (%f %f) new size %dx%d (K %d L %u)", m_lod.x, m_lod.y, m_vt.m_lod.x, m_vt.m_lod.y, 1 << TEX0.TW, 1 << TEX0.TH, m_context->TEX1.K, m_context->TEX1.L); + GL_CACHE("Mipmap LOD %d %d (%f %f) new size %dx%d (K %d L %u)", m_lod.x, m_lod.y, m_vt.m_lod.x, m_vt.m_lod.y, + (1 << m_cached_ctx.TEX0.TW) >> m_lod.x, (1 << m_cached_ctx.TEX0.TH) >> m_lod.x, m_context->TEX1.K, m_context->TEX1.L); } + else if (GSConfig.HWMipmapMode >= GSHWMipmapMode::AllLevels && m_context->TEX1.MXL > 0 && !m_context->TEX1.LCM) + { + mipmap_active = true; + hash_lod_range = GSVector2i(0, std::min(static_cast(m_context->TEX1.MXL), 6)); + TEX0 = m_cached_ctx.TEX0; + GL_CACHE("Looking up all %d texture LODs", hash_lod_range.y); } else { TEX0 = m_cached_ctx.TEX0; @@ -2563,7 +2579,7 @@ void GSRendererHW::Draw() else { src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME.Block(), req_color, req_alpha) : - g_texture_cache->LookupSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr, + g_texture_cache->LookupSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME.Block(), req_color, req_alpha); if (!src) [[unlikely]] @@ -2958,7 +2974,7 @@ void GSRendererHW::Draw() } // Round 2 - if (IsMipMapActive() && GSConfig.HWMipmap && !tex_psm.depth && !src->m_from_hash_cache) + if (mipmap_active && !tex_psm.depth && !src->m_from_hash_cache) { // Upload remaining texture layers const GSVector4 tmin = m_vt.m_min.t; @@ -4910,7 +4926,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, const bool shader_emulated_sampler = tex->m_palette || (tex->m_target && !m_conf.ps.shuffle && cpsm.fmt != 0) || complex_wms_wmt || psm.depth || target_region; const bool can_trilinear = !tex->m_palette && !tex->m_target && !m_conf.ps.shuffle; - const bool trilinear_manual = need_mipmap && GSConfig.HWMipmap; + bool trilinear_manual = need_mipmap && GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled; bool bilinear = m_vt.IsLinear(); int trilinear = 0; @@ -4925,7 +4941,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, if (can_trilinear) { trilinear = static_cast(GS_MIN_FILTER::Linear_Mipmap_Linear); - trilinear_auto = !tex->m_target && (!need_mipmap || !GSConfig.HWMipmap); + trilinear_auto = !tex->m_target && (!need_mipmap || GSConfig.HWMipmapMode == GSHWMipmapMode::Disabled); } } break; @@ -4934,10 +4950,10 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, case TriFiltering::Automatic: { // Can only use PS2 trilinear when mipmapping is enabled. - if (need_mipmap && GSConfig.HWMipmap && can_trilinear) + if (need_mipmap && GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled && can_trilinear) { trilinear = m_context->TEX1.MMIN; - trilinear_auto = !tex->m_target && !GSConfig.HWMipmap; + trilinear_auto = !tex->m_target && GSConfig.HWMipmapMode == GSHWMipmapMode::Disabled; } } break; @@ -4946,6 +4962,12 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, default: break; } + if (GSConfig.HWMipmapMode >= GSHWMipmapMode::Unclamped && !shader_emulated_sampler && + m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5 && !m_context->TEX1.LCM) + { + trilinear = static_cast(m_vt.IsLinear() ? GS_MIN_FILTER::Linear_Mipmap_Linear : GS_MIN_FILTER::Nearest_Mipmap_Linear); + trilinear_manual = false; + } // 1 and 0 are equivalent m_conf.ps.wms = (wms & 2 || target_region) ? wms : 0; @@ -5146,7 +5168,10 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, { m_conf.cb_ps.LODParams.x = static_cast(m_context->TEX1.K) / 16.0f; m_conf.cb_ps.LODParams.y = static_cast(1 << m_context->TEX1.L); - m_conf.cb_ps.LODParams.z = static_cast(m_lod.x); // Offset because first layer is m_lod, dunno if we can do better + m_conf.cb_ps.LODParams.z = (GSConfig.HWMipmapMode >= GSHWMipmapMode::Unclamped) ? + std::log2(rt ? rt->GetScale() : ds->GetScale()) : + static_cast((GSConfig.HWMipmapMode == GSHWMipmapMode::AllLevels) ? 0.0f : m_lod.x); + m_conf.cb_ps.LODParams.w = static_cast(m_lod.y); m_conf.ps.manual_lod = 1; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 1060dc49f2fea..b868f7f559060 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -4447,7 +4447,9 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con { // lod won't contain the full range when using basic mipmapping, only that // which is hashed, so we just allocate the full thing. - tlevels = GSConfig.HWMipmap ? std::min(lod->y - lod->x + 1, GSDevice::GetMipmapLevelsForSize(tw, th)) : -1; + tlevels = (GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled) ? + std::min(lod->y - lod->x + 1, GSDevice::GetMipmapLevelsForSize(tw, th)) : + -1; src->m_lod = *lod; } @@ -5390,7 +5392,10 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0 // expand/upload texture const int tw = region.HasX() ? region.GetWidth() : (1 << TEX0.TW); const int th = region.HasY() ? region.GetHeight() : (1 << TEX0.TH); - const int tlevels = lod ? (GSConfig.HWMipmap ? std::min(lod->y - lod->x + 1, GSDevice::GetMipmapLevelsForSize(tw, th)) : -1) : 1; + const int tlevels = lod ? ((GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled) ? + std::min(lod->y - lod->x + 1, GSDevice::GetMipmapLevelsForSize(tw, th)) : + -1) : + 1; GSTexture* tex = g_gs_device->CreateTexture(tw, th, tlevels, paltex ? GSTexture::Format::UNorm8 : GSTexture::Format::Color); if (!tex) { diff --git a/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp b/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp index 3274d7dcbf876..822512523a812 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp @@ -661,7 +661,7 @@ void GSTextureReplacements::PrecacheReplacementTextures() // predict whether the requests will come with mipmaps // TODO: This will be wrong for hw mipmap games like Jak. - const bool mipmap = GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced; + const bool mipmap = (GSConfig.HWMipmapMode >= GSHWMipmapMode::Enabled || GSConfig.TriFilter == TriFiltering::Forced); // pretty simple, just go through the filenames and if any aren't cached, cache them for (const auto& it : s_replacement_texture_filenames) diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index 08dafee041537..52b4d81befdf4 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -622,7 +622,7 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti return (static_cast(config.PCRTCOverscan) == value); case GSHWFixId::Mipmap: - return (static_cast(config.HWMipmap) == value); + return (static_cast(config.HWMipmapMode) == value); case GSHWFixId::TrilinearFiltering: return (config.TriFilter == TriFiltering::Automatic || static_cast(config.TriFilter) == value); @@ -780,8 +780,10 @@ void GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions& break; case GSHWFixId::Mipmap: - config.HWMipmap = (value > 0); - break; + { + if (value >= 0 && value < static_cast(GSHWMipmapMode::MaxCount)) + config.HWMipmapMode = static_cast(value > 0); + } case GSHWFixId::TrilinearFiltering: { diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index e6893440bb3d6..ec029a62c5780 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -3569,6 +3569,12 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad "11", "12", }; + static constexpr const char* s_mipmapping_options[] = { + FSUI_NSTR("Disabled"), + FSUI_NSTR("Enabled"), + FSUI_NSTR("All Levels"), + FSUI_NSTR("Unclamped"), + }; static constexpr const char* s_bilinear_options[] = { FSUI_NSTR("Nearest"), FSUI_NSTR("Bilinear (Forced)"), @@ -3702,6 +3708,9 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad DrawStringListSetting(bsi, FSUI_CSTR("Internal Resolution"), FSUI_CSTR("Multiplies the render resolution by the specified factor (upscaling)."), "EmuCore/GS", "upscale_multiplier", "1.000000", s_resolution_options, s_resolution_values, std::size(s_resolution_options), true); + DrawIntListSetting( + bsi, FSUI_CSTR("Mipmapping"), FSUI_CSTR("Enables emulation of the GS's texture mipmapping."), "EmuCore/GS", "hw_mipmap_mode", + static_cast(GSHWMipmapMode::Enabled), s_mipmapping_options, std::size(s_mipmapping_options), true); DrawIntListSetting(bsi, FSUI_CSTR("Bilinear Filtering"), FSUI_CSTR("Selects where bilinear filtering is utilized when rendering textures."), "EmuCore/GS", "filter", static_cast(BiFiltering::PS2), s_bilinear_options, std::size(s_bilinear_options), true); @@ -3721,8 +3730,6 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."), "EmuCore/GS", "texture_preloading", static_cast(TexturePreloadingLevel::Off), s_preloading_options, std::size(s_preloading_options), true); - DrawToggleSetting( - bsi, FSUI_CSTR("Mipmapping"), FSUI_CSTR("Enables emulation of the GS's texture mipmapping."), "EmuCore/GS", "hw_mipmap", true); } else { @@ -7027,6 +7034,8 @@ TRANSLATE_NOOP("FullscreenUI", "Enables internal Anti-Blur hacks. Less accurate TRANSLATE_NOOP("FullscreenUI", "Rendering"); TRANSLATE_NOOP("FullscreenUI", "Internal Resolution"); TRANSLATE_NOOP("FullscreenUI", "Multiplies the render resolution by the specified factor (upscaling)."); +TRANSLATE_NOOP("FullscreenUI", "Mipmapping"); +TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's texture mipmapping."); TRANSLATE_NOOP("FullscreenUI", "Bilinear Filtering"); TRANSLATE_NOOP("FullscreenUI", "Selects where bilinear filtering is utilized when rendering textures."); TRANSLATE_NOOP("FullscreenUI", "Trilinear Filtering"); @@ -7039,8 +7048,6 @@ TRANSLATE_NOOP("FullscreenUI", "Blending Accuracy"); TRANSLATE_NOOP("FullscreenUI", "Determines the level of accuracy when emulating blend modes not supported by the host graphics API."); TRANSLATE_NOOP("FullscreenUI", "Texture Preloading"); TRANSLATE_NOOP("FullscreenUI", "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."); -TRANSLATE_NOOP("FullscreenUI", "Mipmapping"); -TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's texture mipmapping."); TRANSLATE_NOOP("FullscreenUI", "Software Rendering Threads"); TRANSLATE_NOOP("FullscreenUI", "Number of threads to use in addition to the main GS thread for rasterization."); TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Software)"); diff --git a/pcsx2/ImGui/ImGuiOverlays.cpp b/pcsx2/ImGui/ImGuiOverlays.cpp index c997fcec46db3..fdc04e8fee261 100644 --- a/pcsx2/ImGui/ImGuiOverlays.cpp +++ b/pcsx2/ImGui/ImGuiOverlays.cpp @@ -406,8 +406,8 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa if (GSConfig.HWDownloadMode != GSHardwareDownloadMode::Enabled) APPEND("DL={} ", static_cast(GSConfig.HWDownloadMode)); - if (GSConfig.HWMipmap) - APPEND("MM "); + if (GSConfig.HWMipmapMode != GSHWMipmapMode::Disabled) + APPEND("MM={} ", static_cast(GSConfig.HWMipmapMode)); // deliberately test global and print local here for auto values if (EmuConfig.GS.TextureFiltering != BiFiltering::PS2) diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index fc87c91c99475..4c3865f6e05d3 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -644,7 +644,6 @@ Pcsx2Config::GSOptions::GSOptions() AutoFlushSW = true; PreloadFrameWithGSData = false; Mipmap = true; - HWMipmap = true; ManualUserHacks = false; UserHacks_AlignSpriteX = false; @@ -712,6 +711,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const OpEqu(UpscaleMultiplier) && OpEqu(AccurateBlendingUnit) && + OpEqu(HWMipmapMode) && OpEqu(TextureFiltering) && OpEqu(TexturePreloading) && OpEqu(GSDumpCompression) && @@ -899,7 +899,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapIntEnumEx(Renderer, "Renderer"); SettingsWrapEntryEx(UpscaleMultiplier, "upscale_multiplier"); - SettingsWrapBitBoolEx(HWMipmap, "hw_mipmap"); + SettingsWrapIntEnumEx(HWMipmapMode, "hw_mipmap_mode"); SettingsWrapIntEnumEx(AccurateBlendingUnit, "accurate_blending_unit"); SettingsWrapIntEnumEx(TextureFiltering, "filter"); SettingsWrapIntEnumEx(TexturePreloading, "texture_preloading"); diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 4d38938540650..4dfd296445d3a 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -3158,10 +3158,10 @@ void VMManager::WarnAboutUnsafeSettings() append(ICON_FA_EXCLAMATION_CIRCLE, TRANSLATE_SV("VMManager", "Texture dumping is enabled, this will continually dump textures to disk.")); } - if (!EmuConfig.GS.HWMipmap) + if (EmuConfig.GS.HWMipmapMode != GSHWMipmapMode::Enabled && EmuConfig.GS.HWMipmapMode != GSHWMipmapMode::AllLevels) { append(ICON_FA_IMAGES, - TRANSLATE_SV("VMManager", "Mipmapping is disabled. This may break rendering in some games.")); + TRANSLATE_SV("VMManager", "Mipmapping is not set to Enabled/All Levels. This may break rendering in some games.")); } } if (EmuConfig.GS.TextureFiltering != BiFiltering::PS2)