From 41b19e262f2778ddd022f91e6bd4fe911788e376 Mon Sep 17 00:00:00 2001 From: Filoppi Date: Mon, 18 Dec 2023 02:37:19 +0200 Subject: [PATCH] Add custom relative and raw (squared pixels) aspect ratio modes --- .../Config/Graphics/GeneralWidget.cpp | 35 ++++++++------ Source/Core/DolphinQt/HotkeyScheduler.cpp | 6 +++ Source/Core/VideoCommon/Present.cpp | 47 ++++++++++++++----- Source/Core/VideoCommon/VideoConfig.h | 10 ++-- 4 files changed, 69 insertions(+), 29 deletions(-) diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp index 5981c21348..c419cabc97 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp @@ -55,9 +55,9 @@ void GeneralWidget::CreateWidgets() m_video_layout = new QGridLayout(); m_backend_combo = new ToolTipComboBox(); - m_aspect_combo = new ConfigChoice( - {tr("Auto"), tr("Force 16:9"), tr("Force 4:3"), tr("Stretch to Window"), tr("Custom")}, - Config::GFX_ASPECT_RATIO); + m_aspect_combo = new ConfigChoice({tr("Auto"), tr("Force 16:9"), tr("Force 4:3"), + tr("Stretch to Window"), tr("Custom"), tr("Custom (Stretch)")}, + Config::GFX_ASPECT_RATIO); m_custom_aspect_label = new QLabel(tr("Custom Aspect Ratio:")); m_custom_aspect_label->setHidden(true); constexpr int MAX_CUSTOM_ASPECT_RATIO_RESOLUTION = 10000; @@ -155,7 +155,8 @@ void GeneralWidget::ConnectWidgets() emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))); }); connect(m_aspect_combo, qOverload(&QComboBox::currentIndexChanged), this, [&](int index) { - const bool is_custom_aspect_ratio = (index == static_cast(AspectMode::Custom)); + const bool is_custom_aspect_ratio = (index == static_cast(AspectMode::Custom)) || + (index == static_cast(AspectMode::CustomStretch)); m_custom_aspect_width->setEnabled(is_custom_aspect_ratio); m_custom_aspect_height->setEnabled(is_custom_aspect_ratio); m_custom_aspect_label->setHidden(!is_custom_aspect_ratio); @@ -170,7 +171,9 @@ void GeneralWidget::LoadSettings() m_backend_combo->setCurrentIndex(m_backend_combo->findData( QVariant(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))))); - const bool is_custom_aspect_ratio = (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::Custom); + const bool is_custom_aspect_ratio = + (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::Custom) || + (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::CustomStretch); m_custom_aspect_width->setEnabled(is_custom_aspect_ratio); m_custom_aspect_height->setEnabled(is_custom_aspect_ratio); m_custom_aspect_label->setHidden(!is_custom_aspect_ratio); @@ -247,15 +250,19 @@ void GeneralWidget::AddDescriptions() QT_TR_NOOP("Uses the main Dolphin window for rendering rather than " "a separate render window.

If unsure, leave " "this unchecked."); - static const char TR_ASPECT_RATIO_DESCRIPTION[] = - QT_TR_NOOP("Selects which aspect ratio to use when rendering.
" - "Each game can have a slightly different native aspect ratio." - "

Auto: Uses the native aspect ratio" - "
Force 16:9: Mimics an analog TV with a widescreen aspect ratio." - "
Force 4:3: Mimics a standard 4:3 analog TV." - "
Stretch to Window: Stretches the picture to the window size." - "
Custom: For games running with specific custom aspect ratio cheats.

" - "If unsure, select Auto."); + static const char TR_ASPECT_RATIO_DESCRIPTION[] = QT_TR_NOOP( + "Selects which aspect ratio to use when drawing on the render window.
" + "Each game can have a slightly different native aspect ratio.
They can vary by " + "scene and settings and rarely ever exactly match 4:3 or 16:9." + "

Auto: Uses the native aspect ratio" + "

Force 16:9: Mimics an analog TV with a widescreen aspect ratio." + "

Force 4:3: Mimics a standard 4:3 analog TV." + "

Stretch to Window: Stretches the picture to the window size." + "

Custom: Forces the specified aspect ratio." + "
This is mostly intended to be used with aspect ratio cheats/mods." + "

Custom (Stretch): Similar to `Custom` but not relative to the " + "title's native aspect ratio.
This is not meant to be used under normal circumstances." + "

If unsure, select Auto."); static const char TR_VSYNC_DESCRIPTION[] = QT_TR_NOOP( "Waits for vertical blanks in order to prevent tearing.

Decreases performance " "if emulation speed is below 100%.

If unsure, leave " diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index fc485a7de2..ff18fa578b 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -410,6 +410,12 @@ void HotkeyScheduler::Run() case AspectMode::Custom: OSD::AddMessage("Custom"); break; + case AspectMode::CustomStretch: + OSD::AddMessage("Custom (Stretch)"); + break; + case AspectMode::Raw: + OSD::AddMessage("Raw (Square Pixels)"); + break; case AspectMode::Auto: default: OSD::AddMessage("Auto"); diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index d475c15c24..0cc19d6e14 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -356,12 +356,20 @@ float Presenter::CalculateDrawAspectRatio(bool allow_stretch) const { return SourceAspectRatioToWidescreen(source_aspect_ratio); } - // For the "custom" mode, we force the exact target aspect ratio, without - // acknowleding the difference between the source aspect ratio and 4:3. else if (aspect_mode == AspectMode::Custom) + { + return source_aspect_ratio * (g_ActiveConfig.GetCustomAspectRatio() / (4.0f / 3.0f)); + } + // For the "custom stretch" mode, we force the exact target aspect ratio, without + // acknowleding the difference between the source aspect ratio and 4:3. + else if (aspect_mode == AspectMode::CustomStretch) { return g_ActiveConfig.GetCustomAspectRatio(); } + else if (aspect_mode == AspectMode::Raw) + { + return m_xfb_entry ? (static_cast(m_last_xfb_width) / m_last_xfb_height) : 1.f; + } return source_aspect_ratio; } @@ -428,9 +436,11 @@ void* Presenter::GetNewSurfaceHandle() u32 Presenter::AutoIntegralScale() const { - // Take the source resolution (XFB) and stretch it on the target aspect ratio. + // Take the source/native resolution (XFB) and stretch it on the target (window) aspect ratio. // If the target resolution is larger (on either x or y), we scale the source // by a integer multiplier until it won't have to be scaled up anymore. + // NOTE: this might conflict with "Config::MAIN_RENDER_WINDOW_AUTOSIZE", + // as they mutually influence each other. u32 source_width = m_last_xfb_width; u32 source_height = m_last_xfb_height; const u32 target_width = m_target_rectangle.GetWidth(); @@ -477,7 +487,7 @@ std::tuple Presenter::ApplyStandardAspectCrop(float width, float h if (!allow_stretch && aspect_mode == AspectMode::Stretch) aspect_mode = AspectMode::Auto; - if (!g_ActiveConfig.bCrop || aspect_mode == AspectMode::Stretch) + if (!g_ActiveConfig.bCrop || aspect_mode == AspectMode::Stretch || aspect_mode == AspectMode::Raw) return {width, height}; // Force aspect ratios by cropping the image. @@ -495,9 +505,12 @@ std::tuple Presenter::ApplyStandardAspectCrop(float width, float h case AspectMode::ForceStandard: expected_aspect = 4.0f / 3.0f; break; - // There should be no cropping needed in the custom case, - // as output should always exactly match the target aspect ratio + // For the custom (relative) case, we want to crop from the native aspect ratio + // to the specific target one, as they likely have a small difference case AspectMode::Custom: + // There should be no cropping needed in the custom strech case, + // as output should always exactly match the target aspect ratio + case AspectMode::CustomStretch: expected_aspect = g_ActiveConfig.GetCustomAspectRatio(); break; } @@ -602,9 +615,10 @@ void Presenter::UpdateDrawRectangle() int_draw_width = static_cast(draw_width); int_draw_height = static_cast(draw_height); } - else + else if (g_ActiveConfig.aspect_mode != AspectMode::Raw || !m_xfb_entry) { - // Find the best integer resolution: the closest aspect ratio with the least black bars + // Find the best integer resolution: the closest aspect ratio with the least black bars. + // This should have no influence if "AspectMode::Stretch" is active. const float updated_draw_aspect_ratio = draw_width / draw_height; const auto int_draw_res = FindClosestIntegerResolution(draw_width, draw_height, updated_draw_aspect_ratio); @@ -612,13 +626,21 @@ void Presenter::UpdateDrawRectangle() int_draw_height = std::get<1>(int_draw_res); if (!g_ActiveConfig.bCrop) { - TryToSnapToXFBSize(int_draw_width, int_draw_height, m_xfb_rect.GetWidth(), - m_xfb_rect.GetHeight()); + if (g_ActiveConfig.aspect_mode != AspectMode::Stretch) + { + TryToSnapToXFBSize(int_draw_width, int_draw_height, m_xfb_rect.GetWidth(), + m_xfb_rect.GetHeight()); + } // We can't draw something bigger than the window, it will crop int_draw_width = std::min(int_draw_width, static_cast(win_width)); int_draw_height = std::min(int_draw_height, static_cast(win_height)); } } + else + { + int_draw_width = m_xfb_rect.GetWidth(); + int_draw_height = m_xfb_rect.GetHeight(); + } m_target_rectangle.left = static_cast(std::round(win_width / 2.0 - int_draw_width / 2.0)); m_target_rectangle.top = static_cast(std::round(win_height / 2.0 - int_draw_height / 2.0)); @@ -665,7 +687,10 @@ std::tuple Presenter::CalculateOutputDimensions(int width, int height, const float draw_aspect_ratio = CalculateDrawAspectRatio(allow_stretch); auto [int_width, int_height] = FindClosestIntegerResolution(scaled_width, scaled_height, draw_aspect_ratio); - TryToSnapToXFBSize(int_width, int_height, m_xfb_rect.GetWidth(), m_xfb_rect.GetHeight()); + if (aspect_mode != AspectMode::Raw) + { + TryToSnapToXFBSize(int_width, int_height, m_xfb_rect.GetWidth(), m_xfb_rect.GetHeight()); + } width = int_width; height = int_height; } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 31c10059d5..d7ab34f142 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -21,11 +21,13 @@ constexpr int EFB_SCALE_AUTO_INTEGRAL = 0; enum class AspectMode : int { - Auto, // 4:3 or 16:9 - ForceWide, // 16:9 - ForceStandard, // 4:3 + Auto, // ~4:3 or ~16:9 (auto detected) + ForceWide, // ~16:9 + ForceStandard, // ~4:3 Stretch, - Custom, + Custom, // Forced relative custom AR + CustomStretch, // Forced absolute custom AR + Raw, // Forced squared pixels }; enum class StereoMode : int