diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index 4b7dad18f3..d291aab616 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -502,7 +502,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget* dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"), tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto Standard (4:3/3:2 " - "Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era.")); + "Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era, and adapts to widescreen/ultrawide game patches.")); dialog->registerWidgetHelp(m_ui.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr("Determines the deinterlacing method to be used on the interlaced screen of the emulated console. Automatic should be able to correctly deinterlace most games, but if you see visibly shaky graphics, try one of the available options.")); diff --git a/pcsx2/Config.h b/pcsx2/Config.h index e879aada39..f6bd3ce2d3 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -223,8 +223,8 @@ enum class DebugFunctionScanMode enum class AspectRatioType : u8 { - Stretch, - RAuto4_3_3_2, + Stretch, // Stretches to the whole window/display size, allowing a custom aspect ratio override if it's set + RAuto4_3_3_2, // Automatically scales to the target aspect ratio if there's a widescreen patch R4_3, R16_9, R10_7, @@ -233,7 +233,7 @@ enum class AspectRatioType : u8 enum class FMVAspectRatioSwitchType : u8 { - Off, + Off, // Falls back on the selected generic aspect ratio type RAuto4_3_3_2, R4_3, R16_9, @@ -1324,6 +1324,8 @@ struct Pcsx2Config std::string CurrentIRX; std::string CurrentGameArgs; AspectRatioType CurrentAspectRatio = AspectRatioType::RAuto4_3_3_2; + // Fall back aspect ratio for games that have patches (when AspectRatioType::RAuto4_3_3_2) is active. + float CurrentCustomAspectRatio = 0.f; bool IsPortableMode = false; Pcsx2Config(); diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index 4fff716634..3b1b4aba3e 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -268,8 +268,25 @@ float GSRenderer::GetModXYOffset() static float GetCurrentAspectRatioFloat(bool is_progressive) { - static constexpr std::array(AspectRatioType::MaxCount) + 1> ars = {{4.0f / 3.0f, 4.0f / 3.0f, 4.0f / 3.0f, 16.0f / 9.0f, 10.0f / 7.0f, 3.0f / 2.0f}}; - return ars[static_cast(GSConfig.AspectRatio) + (3u * (is_progressive && GSConfig.AspectRatio == AspectRatioType::RAuto4_3_3_2))]; + switch (GSConfig.AspectRatio) + { + default: + // We don't know the AR of the display here, nor we care about it + case AspectRatioType::Stretch: + case AspectRatioType::RAuto4_3_3_2: + if (EmuConfig.CurrentCustomAspectRatio > 0.f) + return EmuConfig.CurrentCustomAspectRatio; + else if (is_progressive) + return 3.0f / 2.0f; + else + return 4.0f / 3.0f; + case AspectRatioType::R4_3: + return 4.0f / 3.0f; + case AspectRatioType::R16_9: + return 16.0f / 9.0f; + case AspectRatioType::R10_7: + return 10.0f / 7.0f; + } } static GSVector4 CalculateDrawDstRect(s32 window_width, s32 window_height, const GSVector4i& src_rect, const GSVector2i& src_size, GSDisplayAlignment alignment, bool flip_y, bool is_progressive) @@ -285,6 +302,9 @@ static GSVector4 CalculateDrawDstRect(s32 window_width, s32 window_height, const targetAr = 3.0f / 2.0f; else targetAr = 4.0f / 3.0f; + // Fall back on the custom aspect ratio set by patches (e.g. 16:9, 21:9) + if (EmuConfig.CurrentCustomAspectRatio > 0.f) + targetAr = EmuConfig.CurrentCustomAspectRatio; } else if (EmuConfig.CurrentAspectRatio == AspectRatioType::R4_3) { @@ -298,6 +318,10 @@ static GSVector4 CalculateDrawDstRect(s32 window_width, s32 window_height, const { targetAr = 10.0f / 7.0f; } + else if (EmuConfig.CurrentCustomAspectRatio > 0.f) + { + targetAr = EmuConfig.CurrentCustomAspectRatio; + } const float crop_adjust = (static_cast(src_rect.width()) / static_cast(src_size.x)) / (static_cast(src_rect.height()) / static_cast(src_size.y)); diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp index add4a078c9..2f02c1d9ad 100644 --- a/pcsx2/Patch.cpp +++ b/pcsx2/Patch.cpp @@ -111,7 +111,7 @@ namespace Patch struct PatchGroup { std::string name; - std::optional override_aspect_ratio; + std::optional override_aspect_ratio; std::optional override_interlace_mode; std::vector patches; std::vector dpatches; @@ -186,7 +186,7 @@ namespace Patch static EnablePatchList s_just_enabled_cheats; static EnablePatchList s_just_enabled_patches; static u32 s_patches_crc; - static std::optional s_override_aspect_ratio; + static std::optional s_override_aspect_ratio; static std::optional s_override_interlace_mode; static const PatchTextTable s_patch_commands[] = { @@ -797,17 +797,13 @@ void Patch::UpdateActivePatches(bool reload_enabled_list, bool verbose, bool ver void Patch::ApplyPatchSettingOverrides() { - // Switch to 16:9 if widescreen patches are enabled, and AR is auto. + // Switch to 16:9 (or any custom aspect ratio) if widescreen patches are enabled, and AR is auto. if (s_override_aspect_ratio.has_value() && EmuConfig.GS.AspectRatio == AspectRatioType::RAuto4_3_3_2) { - // Don't change when reloading settings in the middle of a FMV with switch. - if (EmuConfig.CurrentAspectRatio == EmuConfig.GS.AspectRatio) - EmuConfig.CurrentAspectRatio = s_override_aspect_ratio.value(); + EmuConfig.CurrentCustomAspectRatio = s_override_aspect_ratio.value(); Console.WriteLn(Color_Gray, - fmt::format("Patch: Setting aspect ratio to {} by patch request.", - Pcsx2Config::GSOptions::AspectRatioNames[static_cast(s_override_aspect_ratio.value())])); - EmuConfig.GS.AspectRatio = s_override_aspect_ratio.value(); + fmt::format("Patch: Setting aspect ratio to {} by patch request.", s_override_aspect_ratio.value())); } // Disable interlacing in GS if active. @@ -821,9 +817,13 @@ void Patch::ApplyPatchSettingOverrides() bool Patch::ReloadPatchAffectingOptions() { + // Restore the aspect ratio + interlacing setting the user had set before reloading the patch, + // as the custom patch settings only apply if the "Auto" settings are selected. + const AspectRatioType current_ar = EmuConfig.GS.AspectRatio; const GSInterlaceMode current_interlace = EmuConfig.GS.InterlaceMode; - + const float custom_aspect_ratio = EmuConfig.CurrentCustomAspectRatio; + // This is pretty gross, but we're not using a config layer, so... AspectRatioType new_ar = Pcsx2Config::GSOptions::DEFAULT_ASPECT_RATIO; const std::string ar_value = Host::GetStringSettingValue("EmuCore/GS", "AspectRatio", @@ -836,15 +836,14 @@ bool Patch::ReloadPatchAffectingOptions() break; } } - if (EmuConfig.CurrentAspectRatio == EmuConfig.GS.AspectRatio) - EmuConfig.CurrentAspectRatio = new_ar; EmuConfig.GS.AspectRatio = new_ar; EmuConfig.GS.InterlaceMode = static_cast(Host::GetIntSettingValue( "EmuCore/GS", "deinterlace_mode", static_cast(Pcsx2Config::GSOptions::DEFAULT_INTERLACE_MODE))); ApplyPatchSettingOverrides(); - return (current_ar != EmuConfig.GS.AspectRatio || current_interlace != EmuConfig.GS.InterlaceMode); + // Return true if any config setting changed + return current_ar != EmuConfig.GS.AspectRatio || custom_aspect_ratio != EmuConfig.CurrentCustomAspectRatio || current_interlace != EmuConfig.GS.InterlaceMode; } void Patch::UnloadPatches() @@ -941,13 +940,22 @@ void Patch::PatchFunc::patch(PatchGroup* group, const std::string_view cmd, cons void Patch::PatchFunc::gsaspectratio(PatchGroup* group, const std::string_view cmd, const std::string_view param) { - for (u32 i = 0; i < static_cast(AspectRatioType::MaxCount); i++) + std::string str(param); + std::istringstream ss(str); + uint dividend, divisor; + char delimiter; + float aspect_ratio = 0.f; + + ss >> dividend >> delimiter >> divisor; + if (!ss.fail() && delimiter == ':' && divisor != 0) { - if (param == Pcsx2Config::GSOptions::AspectRatioNames[i]) - { - group->override_aspect_ratio = static_cast(i); - return; - } + aspect_ratio = static_cast(dividend) / static_cast(divisor); + } + + if (aspect_ratio > 0.f) + { + group->override_aspect_ratio = aspect_ratio; + return; } Console.Error(fmt::format("Patch error: {} is an unknown aspect ratio.", param)); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index dca9dafd9b..2e5cb62c7d 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -636,7 +636,7 @@ void Pcsx2Config::CpuOptions::LoadSave(SettingsWrapper& wrap) Recompiler.LoadSave(wrap); } -const char* Pcsx2Config::GSOptions::AspectRatioNames[] = { +const char* Pcsx2Config::GSOptions::AspectRatioNames[(size_t)AspectRatioType::MaxCount + 1] = { "Stretch", "Auto 4:3/3:2", "4:3", @@ -644,7 +644,7 @@ const char* Pcsx2Config::GSOptions::AspectRatioNames[] = { "10:7", nullptr}; -const char* Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames[] = { +const char* Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames[(size_t)FMVAspectRatioSwitchType::MaxCount + 1] = { "Off", "Auto 4:3/3:2", "4:3", @@ -1983,7 +1983,13 @@ void Pcsx2Config::LoadSaveCore(SettingsWrapper& wrap) if (wrap.IsLoading()) { + // Patches will get re-applied after loading the state so this doesn't matter too much CurrentAspectRatio = GS.AspectRatio; + // Don't override it if the user had set it to a custom value + if (CurrentAspectRatio == AspectRatioType::RAuto4_3_3_2) + { + CurrentCustomAspectRatio = 0.f; + } } } @@ -2035,6 +2041,7 @@ void Pcsx2Config::CopyRuntimeConfig(Pcsx2Config& cfg) CurrentIRX = std::move(cfg.CurrentIRX); CurrentGameArgs = std::move(cfg.CurrentGameArgs); CurrentAspectRatio = cfg.CurrentAspectRatio; + CurrentCustomAspectRatio = cfg.CurrentCustomAspectRatio; IsPortableMode = cfg.IsPortableMode; for (u32 i = 0; i < sizeof(Mcd) / sizeof(Mcd[0]); i++) diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 95c9e149ff..edcee8faaa 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -876,7 +876,9 @@ void VMManager::RequestDisplaySize(float scale /*= 0.0f*/) switch (GSConfig.AspectRatio) { case AspectRatioType::RAuto4_3_3_2: - if (GSgetDisplayMode() == GSVideoMode::SDTV_480P) + if (EmuConfig.CurrentCustomAspectRatio > 0.f) + x_scale = EmuConfig.CurrentCustomAspectRatio / (static_cast(iwidth) / static_cast(iheight)); + else if (GSgetDisplayMode() == GSVideoMode::SDTV_480P) x_scale = (3.0f / 2.0f) / (static_cast(iwidth) / static_cast(iheight)); else x_scale = (4.0f / 3.0f) / (static_cast(iwidth) / static_cast(iheight)); @@ -893,6 +895,8 @@ void VMManager::RequestDisplaySize(float scale /*= 0.0f*/) case AspectRatioType::Stretch: default: x_scale = 1.0f; + if (EmuConfig.CurrentCustomAspectRatio > 0.f) + x_scale = EmuConfig.CurrentCustomAspectRatio / (static_cast(iwidth) / static_cast(iheight)); break; }