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");