diff --git a/pcsx2-qt/Settings/GraphicsDisplaySettingsTab.ui b/pcsx2-qt/Settings/GraphicsDisplaySettingsTab.ui index 8b895d00d0c30..61a1fdfda4648 100644 --- a/pcsx2-qt/Settings/GraphicsDisplaySettingsTab.ui +++ b/pcsx2-qt/Settings/GraphicsDisplaySettingsTab.ui @@ -206,17 +206,17 @@ - - + + - Crop: + FMV Aspect Ratio Override: - - + + - Aspect Ratio: + Crop: aspectRatio @@ -277,16 +277,10 @@ - - - - % - - - 1 - - - 300 + + + + Bilinear Filtering: @@ -387,6 +381,177 @@ + + + + Deinterlacing: + + + + + + + Fullscreen Mode: + + + + + + + Qt::Orientation::Vertical + + + + 20 + 0 + + + + + + + + + + Integer Scaling + + + + + + + Apply Widescreen Patches + + + + + + + Apply No-Interlacing Patches + + + + + + + Anti-Blur + + + Ctrl+S + + + + + + + Disable Interlace Offset + + + + + + + Screen Offsets + + + + + + + Show Overscan + + + + + + + + + % + + + 1 + + + 300 + + + + + + + + + + + Fit to Window / Fullscreen + + + + + Auto Standard (4:3 Interlaced / 3:2 Progressive) + + + + + Standard (4:3) + + + + + Widescreen (16:9) + + + + + Native/Full (10:7) + + + + + + + + Vertical Stretch: + + + + + + + Aspect Ratio: + + + + + + + Adaptive Deinterlacing Sensitivity + + + AdaptiveDeinterlacingSensitivity + + + + + + + + Low + + + + + Default + + + + + High + + + + diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index 57409e48d14c3..55b2647b6babc 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -79,6 +79,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog, SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_display.fmvAspectRatio, "EmuCore/GS", "FMVAspectRatioSwitch", Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, FMVAspectRatioSwitchType::Off); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_display.interlacing, "EmuCore/GS", "deinterlace_mode", DEFAULT_INTERLACE_MODE); + SettingWidgetBinder::BindWidgetToIntSetting( + sif, m_display.AdaptiveDeinterlacingSensitivity, "EmuCore/GS", "MADMode", static_cast(GSMADMode::Default)); SettingWidgetBinder::BindWidgetToIntSetting( sif, m_display.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast(GSPostBilinearMode::BilinearSmooth)); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_display.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false); @@ -441,6 +443,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog, dialog()->registerWidgetHelp(m_display.disableInterlaceOffset, tr("Disable Interlace Offset"), tr("Unchecked"), tr("Disables interlacing offset which may reduce blurring in some situations.")); + dialog()->registerWidgetHelp(m_display.AdaptiveDeinterlacingSensitivity, tr("Adaptive Deinterlacing Sensitivity"), tr("Default"), + tr("Changes the adaptive deinterlacing algorithm's sensitivity to recent, localized motion around pixels.
" + "Higher sensitivity makes the algorithm more responsive to changes in pixel color.")); + dialog()->registerWidgetHelp(m_display.bilinearFiltering, tr("Bilinear Filtering"), tr("Bilinear (Smooth)"), tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects " "positioning between pixels.")); diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 9b4a948f854d5..83f1f97da5f2e 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -303,6 +303,13 @@ enum class GSInterlaceMode : u8 Count }; +enum class GSMADMode : u8 +{ + Low, + Default, + High, +}; + enum class GSPostBilinearMode : u8 { Off, @@ -801,6 +808,7 @@ struct Pcsx2Config AspectRatioType AspectRatio = DEFAULT_ASPECT_RATIO; FMVAspectRatioSwitchType FMVAspectRatioSwitch = FMVAspectRatioSwitchType::Off; GSInterlaceMode InterlaceMode = DEFAULT_INTERLACE_MODE; + GSMADMode MADMode = GSMADMode::Default; GSPostBilinearMode LinearPresent = GSPostBilinearMode::BilinearSmooth; float StretchY = 100.0f; diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index 2022773357f5e..65ea0ca6e9515 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -788,7 +788,7 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse float offset = yoffset * static_cast(field); offset = GSConfig.DisableInterlaceOffset ? 0.0f : offset; - auto do_interlace = [this](GSTexture* sTex, GSTexture* dTex, ShaderInterlace shader, bool linear, float yoffset, int bufIdx) { + auto do_interlace = [this](GSTexture* sTex, GSTexture* dTex, ShaderInterlace shader, bool linear, float yoffset, int bufIdx, float sensitivity) { const GSVector2i ds_i = dTex->GetSize(); const GSVector2 ds = GSVector2(static_cast(ds_i.x), static_cast(ds_i.y)); @@ -806,7 +806,7 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse } const InterlaceConstantBuffer cb = { - GSVector4(static_cast(bufIdx), 1.0f / ds.y, ds.y, MAD_SENSITIVITY) + GSVector4(static_cast(bufIdx), 1.0f / ds.y, ds.y, sensitivity) }; GL_PUSH("DoInterlace %dx%d Shader:%d Linear:%d", ds_i.x, ds_i.y, static_cast(shader), linear); @@ -817,33 +817,49 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse { case 0: // Weave ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false); - do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field); + do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field, 0.0f); m_current = m_weavebob; break; case 1: // Bob // Field is reversed here as we are countering the bounce. ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false); - do_interlace(m_merge, m_weavebob, ShaderInterlace::BOB, true, yoffset * (1 - field), 0); + do_interlace(m_merge, m_weavebob, ShaderInterlace::BOB, true, yoffset * (1 - field), 0, 0.0f); m_current = m_weavebob; break; case 2: // Blend ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false); - do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field); + do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field, 0.0f); ResizeRenderTarget(&m_blend, ds.x, ds.y, true, false); - do_interlace(m_weavebob, m_blend, ShaderInterlace::BLEND, false, 0, 0); + do_interlace(m_weavebob, m_blend, ShaderInterlace::BLEND, false, 0, 0, 0.0f); m_current = m_blend; break; case 3: // FastMAD Motion Adaptive Deinterlacing + { + float sensitivity = DEFAULT_MAD_SENSITIVITY; + + switch (GSConfig.MADMode) + { + case GSMADMode::Low: + sensitivity = LOW_MAD_SENSITIVITY; + break; + case GSMADMode::High: + sensitivity = HIGH_MAD_SENSITIVITY; + break; + default: + break; + } + bufIdx++; bufIdx &= ~1; bufIdx |= field; bufIdx &= 3; ResizeRenderTarget(&m_mad, ds.x, ds.y * 2.0f, true, false); - do_interlace(m_merge, m_mad, ShaderInterlace::MAD_BUFFER, false, offset, bufIdx); + do_interlace(m_merge, m_mad, ShaderInterlace::MAD_BUFFER, false, offset, bufIdx, sensitivity); ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false); - do_interlace(m_mad, m_weavebob, ShaderInterlace::MAD_RECONSTRUCT, false, 0, bufIdx); + do_interlace(m_mad, m_weavebob, ShaderInterlace::MAD_RECONSTRUCT, false, 0, bufIdx, sensitivity); m_current = m_weavebob; break; + } default: m_current = m_merge; break; diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index 6c8106b2ce25b..0e8658b1a6e93 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -881,7 +881,9 @@ class GSDevice : public GSAlignedClass<32> protected: static constexpr int NUM_INTERLACE_SHADERS = 5; - static constexpr float MAD_SENSITIVITY = 0.08f; + static constexpr float LOW_MAD_SENSITIVITY = 0.08f; + static constexpr float DEFAULT_MAD_SENSITIVITY = 0.02f; + static constexpr float HIGH_MAD_SENSITIVITY = 0.0035f; static constexpr u32 MAX_POOLED_TARGETS = 300; static constexpr u32 MAX_TARGET_AGE = 20; static constexpr u32 MAX_POOLED_TEXTURES = 300; diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index 7532d7545d215..7e210842d676a 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -4330,6 +4330,11 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad FSUI_NSTR("Adaptive (Top Field First)"), FSUI_NSTR("Adaptive (Bottom Field First)"), }; + static constexpr const char* s_mad_sensitivity_options[] = { + FSUI_NSTR("Low"), + FSUI_NSTR("Default"), + FSUI_NSTR("High"), + }; static const char* s_resolution_options[] = { FSUI_NSTR("Native (PS2)"), FSUI_NSTR("2x Native (~720px/HD)"), @@ -4445,21 +4450,21 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad MenuHeading(FSUI_CSTR("Display")); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPRESS, "Aspect Ratio"), FSUI_CSTR("Selects the aspect ratio to display the game content at."), - "EmuCore/GS", "AspectRatio", "Auto 4:3/3:2", Pcsx2Config::GSOptions::AspectRatioNames, Pcsx2Config::GSOptions::AspectRatioNames, 0, - false); + "EmuCore/GS", "AspectRatio", "Auto 4:3/3:2", Pcsx2Config::GSOptions::AspectRatioNames, Pcsx2Config::GSOptions::AspectRatioNames, 0, false); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_VIDEO, "FMV Aspect Ratio Override"), FSUI_CSTR("Selects the aspect ratio for display when a FMV is detected as playing."), "EmuCore/GS", "FMVAspectRatioSwitch", "Auto 4:3/3:2", Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, 0, false); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "Deinterlacing"), FSUI_CSTR("Selects the algorithm used to convert the PS2's interlaced output to progressive for display."), "EmuCore/GS", - "deinterlace_mode", static_cast(GSInterlaceMode::Automatic), s_deinterlacing_options, std::size(s_deinterlacing_options), - true); - DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT, "Screenshot Size"), FSUI_CSTR("Determines the resolution at which screenshots will be saved."), - "EmuCore/GS", "ScreenshotSize", static_cast(GSScreenshotSize::WindowResolution), s_screenshot_sizes, - std::size(s_screenshot_sizes), true); + "deinterlace_mode", static_cast(GSInterlaceMode::Automatic), s_deinterlacing_options, std::size(s_deinterlacing_options), true); + DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_TO_EYE, "Adaptive Deinterlacing Sensitivity"), + FSUI_CSTR("Changes the adaptive deinterlacing algorithm's sensitivity to recent, localized motion around pixels."), "EmuCore/GS", + "MADMode", static_cast(GSMADMode::Default), s_mad_sensitivity_options, std::size(s_mad_sensitivity_options), true); + DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT, "Screenshot Size"), + FSUI_CSTR("Determines the resolution at which screenshots will be saved."), "EmuCore/GS", "ScreenshotSize", + static_cast(GSScreenshotSize::WindowResolution), s_screenshot_sizes, std::size(s_screenshot_sizes), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_PHOTO_FILM, "Screenshot Format"), FSUI_CSTR("Selects the format which will be used to save screenshots."), - "EmuCore/GS", "ScreenshotFormat", static_cast(GSScreenshotFormat::PNG), s_screenshot_formats, std::size(s_screenshot_formats), - true); + "EmuCore/GS", "ScreenshotFormat", static_cast(GSScreenshotFormat::PNG), s_screenshot_formats, std::size(s_screenshot_formats), true); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_GAUGE, "Screenshot Quality"), FSUI_CSTR("Selects the quality at which screenshots will be compressed."), "EmuCore/GS", "ScreenshotQuality", 90, 1, 100, FSUI_CSTR("%d%%")); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_RIGHT_ARROW_LEFT, "Vertical Stretch"), FSUI_CSTR("Increases or decreases the virtual picture size vertically."), @@ -9020,6 +9025,7 @@ TRANSLATE_NOOP("FullscreenUI", "Display"); TRANSLATE_NOOP("FullscreenUI", "Selects the aspect ratio to display the game content at."); TRANSLATE_NOOP("FullscreenUI", "Selects the aspect ratio for display when a FMV is detected as playing."); TRANSLATE_NOOP("FullscreenUI", "Selects the algorithm used to convert the PS2's interlaced output to progressive for display."); +TRANSLATE_NOOP("FullscreenUI", "Changes the adaptive deinterlacing algorithm's sensitivity to recent, localized motion around pixels."); TRANSLATE_NOOP("FullscreenUI", "Determines the resolution at which screenshots will be saved."); TRANSLATE_NOOP("FullscreenUI", "Selects the format which will be used to save screenshots."); TRANSLATE_NOOP("FullscreenUI", "Selects the quality at which screenshots will be compressed."); @@ -9463,6 +9469,9 @@ TRANSLATE_NOOP("FullscreenUI", "Blend (Top Field First, Half FPS)"); TRANSLATE_NOOP("FullscreenUI", "Blend (Bottom Field First, Half FPS)"); TRANSLATE_NOOP("FullscreenUI", "Adaptive (Top Field First)"); TRANSLATE_NOOP("FullscreenUI", "Adaptive (Bottom Field First)"); +TRANSLATE_NOOP("FullscreenUI", "Low"); +TRANSLATE_NOOP("FullscreenUI", "Default"); +TRANSLATE_NOOP("FullscreenUI", "High"); TRANSLATE_NOOP("FullscreenUI", "Native (PS2)"); TRANSLATE_NOOP("FullscreenUI", "2x Native (~720px/HD)"); TRANSLATE_NOOP("FullscreenUI", "3x Native (~1080px/FHD)"); @@ -9661,6 +9670,7 @@ TRANSLATE_NOOP("FullscreenUI", "Use Host VSync Timing"); TRANSLATE_NOOP("FullscreenUI", "Aspect Ratio"); TRANSLATE_NOOP("FullscreenUI", "FMV Aspect Ratio Override"); TRANSLATE_NOOP("FullscreenUI", "Deinterlacing"); +TRANSLATE_NOOP("FullscreenUI", "Adaptive Deinterlacing Sensitivity"); TRANSLATE_NOOP("FullscreenUI", "Screenshot Size"); TRANSLATE_NOOP("FullscreenUI", "Screenshot Format"); TRANSLATE_NOOP("FullscreenUI", "Screenshot Quality"); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index a239705293bec..ecb7911fe6422 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -716,6 +716,8 @@ Pcsx2Config::GSOptions::GSOptions() PCRTCOffsets = false; PCRTCOverscan = false; IntegerScaling = false; + InterlaceMode = GSInterlaceMode::Automatic; + MADMode = GSMADMode::Default; LinearPresent = GSPostBilinearMode::BilinearSmooth; UseDebugDevice = false; UseBlitSwapChain = false; @@ -723,6 +725,7 @@ Pcsx2Config::GSOptions::GSOptions() DisableFramebufferFetch = false; DisableVertexShaderExpand = false; SkipDuplicateFrames = false; + OsdMessagesPos = OsdOverlayPos::TopLeft; OsdPerformancePos = OsdOverlayPos::TopRight; OsdShowSpeed = false; @@ -798,10 +801,12 @@ bool Pcsx2Config::GSOptions::operator==(const GSOptions& right) const bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const { return ( - OpEqu(bitset) && + OpEqu(bitset[0]) && + OpEqu(bitset[1]) && OpEqu(InterlaceMode) && OpEqu(LinearPresent) && + OpEqu(MADMode) && OpEqu(StretchY) && OpEqu(Crop[0]) && @@ -943,6 +948,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapBitBool(DisableFramebufferFetch); SettingsWrapBitBool(DisableVertexShaderExpand); SettingsWrapBitBool(SkipDuplicateFrames); + SettingsWrapBitBool(OsdShowSpeed); SettingsWrapBitBool(OsdShowFPS); SettingsWrapBitBool(OsdShowVPS); @@ -1005,8 +1011,9 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapBitBool(EnableAudioCapture); SettingsWrapBitBool(EnableAudioCaptureParameters); - SettingsWrapIntEnumEx(LinearPresent, "linear_present_mode"); SettingsWrapIntEnumEx(InterlaceMode, "deinterlace_mode"); + SettingsWrapIntEnumEx(MADMode, "MADMode"); + SettingsWrapIntEnumEx(LinearPresent, "linear_present_mode"); SettingsWrapEntry(OsdScale); SettingsWrapIntEnumEx(OsdMessagesPos, "OsdMessagesPos");