diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index af6028218..4804e3e3e 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -7,6 +7,7 @@ #include "host_display.h" #include "host_interface.h" #include "interrupt_controller.h" +#include "settings.h" #include "stb_image_write.h" #include "system.h" #include "timers.h" @@ -456,9 +457,41 @@ float GPU::ComputeVerticalFrequency() const float GPU::GetDisplayAspectRatio() const { if (g_settings.display_force_4_3_for_24bit && m_GPUSTAT.display_area_color_depth_24) + { return 4.0f / 3.0f; + } + else if (g_settings.display_aspect_ratio == DisplayAspectRatio::Auto) + { + const CRTCState& cs = m_crtc_state; + float relative_width = static_cast(cs.horizontal_visible_end - cs.horizontal_visible_start); + float relative_height = static_cast(cs.vertical_visible_end - cs.vertical_visible_start); + + if (relative_width <= 0 || relative_height <= 0) + return 4.0f / 3.0f; + + if (m_GPUSTAT.pal_mode) + { + relative_width /= static_cast(PAL_HORIZONTAL_ACTIVE_END - PAL_HORIZONTAL_ACTIVE_START); + relative_height /= static_cast(PAL_VERTICAL_ACTIVE_END - PAL_VERTICAL_ACTIVE_START); + } + else + { + relative_width /= static_cast(NTSC_HORIZONTAL_ACTIVE_END - NTSC_HORIZONTAL_ACTIVE_START); + relative_height /= static_cast(NTSC_VERTICAL_ACTIVE_END - NTSC_VERTICAL_ACTIVE_START); + } + return (relative_width / relative_height) * (4.0f / 3.0f); + } + else if (g_settings.display_aspect_ratio == DisplayAspectRatio::PAR1_1) + { + if (m_crtc_state.display_width == 0 || m_crtc_state.display_height == 0) + return 4.0f / 3.0f; + + return static_cast(m_crtc_state.display_width) / static_cast(m_crtc_state.display_height); + } else + { return Settings::GetDisplayAspectRatioValue(g_settings.display_aspect_ratio); + } } void GPU::UpdateCRTCConfig() diff --git a/src/core/gte.cpp b/src/core/gte.cpp index 3b81c1809..d4e04e5b3 100644 --- a/src/core/gte.cpp +++ b/src/core/gte.cpp @@ -655,6 +655,7 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last) Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); break; + case DisplayAspectRatio::Auto: case DisplayAspectRatio::R4_3: case DisplayAspectRatio::PAR1_1: default: @@ -747,6 +748,7 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last) precise_x = (precise_x * 7.0f) / 6.0f; break; + case DisplayAspectRatio::Auto: case DisplayAspectRatio::R4_3: case DisplayAspectRatio::PAR1_1: default: diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index c39aa745f..c285b1525 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -138,7 +138,6 @@ void HostDisplay::CalculateDrawRect(s32 window_width, s32 window_height, s32* ou s32* out_height, s32* out_left_padding, s32* out_top_padding, float* out_scale, float* out_y_scale, bool apply_aspect_ratio) const { - apply_aspect_ratio = (m_display_aspect_ratio > 0) ? apply_aspect_ratio : false; const float y_scale = apply_aspect_ratio ? ((static_cast(m_display_width) / static_cast(m_display_height)) / m_display_aspect_ratio) : diff --git a/src/core/settings.cpp b/src/core/settings.cpp index d6c0e795c..63c802b70 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -625,10 +625,11 @@ const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode) return s_display_crop_mode_display_names[static_cast(crop_mode)]; } -static std::array s_display_aspect_ratio_names = { - {"4:3", "16:9", "16:10", "19:9", "21:9", "8:7", "5:4", "3:2", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}}; -static constexpr std::array s_display_aspect_ratio_values = { - {4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 21.0f / 9.0f, 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f, +static std::array s_display_aspect_ratio_names = {{"Auto (Game Native)", "4:3", "16:9", "16:10", + "19:9", "21:9", "8:7", "5:4", "3:2", + "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}}; +static constexpr std::array s_display_aspect_ratio_values = { + {-1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 21.0f / 9.0f, 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f, 2.0f / 1.0f, 1.0f, -1.0f}}; std::optional Settings::ParseDisplayAspectRatio(const char* str) diff --git a/src/core/settings.h b/src/core/settings.h index 8547fb447..0dc68e7fd 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -111,7 +111,7 @@ struct Settings bool gpu_pgxp_cpu = false; bool gpu_pgxp_preserve_proj_fp = false; DisplayCropMode display_crop_mode = DisplayCropMode::None; - DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3; + DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::Auto; s16 display_active_start_offset = 0; s16 display_active_end_offset = 0; s8 display_line_start_offset = 0; @@ -300,7 +300,7 @@ struct Settings #endif static constexpr DisplayCropMode DEFAULT_DISPLAY_CROP_MODE = DisplayCropMode::Overscan; - static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::R4_3; + static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto; static constexpr ControllerType DEFAULT_CONTROLLER_1_TYPE = ControllerType::DigitalController; static constexpr ControllerType DEFAULT_CONTROLLER_2_TYPE = ControllerType::None; static constexpr MemoryCardType DEFAULT_MEMORY_CARD_1_TYPE = MemoryCardType::PerGameTitle; diff --git a/src/core/types.h b/src/core/types.h index d3fca8b69..84653dfbe 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -85,6 +85,7 @@ enum class DisplayCropMode : u8 enum class DisplayAspectRatio : u8 { + Auto, R4_3, R16_9, R16_10, diff --git a/src/duckstation-libretro/libretro_host_interface.cpp b/src/duckstation-libretro/libretro_host_interface.cpp index e6f850885..5068f9191 100644 --- a/src/duckstation-libretro/libretro_host_interface.cpp +++ b/src/duckstation-libretro/libretro_host_interface.cpp @@ -704,7 +704,8 @@ static std::array s_option_definitions = {{ {"duckstation_Display.AspectRatio", "Aspect Ratio", "Sets the core-provided aspect ratio.", - {{"4:3", "4:3"}, + {{"Auto", "Auto (Game Native)"}, + {"4:3", "4:3"}, {"16:9", "16:9"}, {"16:10", "16:10"}, {"19:9", "19:9"}, @@ -715,7 +716,7 @@ static std::array s_option_definitions = {{ {"2:1 (VRAM 1:1)", "2:1 (VRAM 1:1)"}, {"1:1", "1:1"}, {"PAR 1:1", "PAR 1:1"}}, - "4:3"}, + "Auto"}, {"duckstation_Main.LoadDevicesFromSaveStates", "Load Devices From Save States", "Sets whether the contents of devices and memory cards will be loaded when a save state is loaded.", diff --git a/src/duckstation-qt/displaysettingswidget.cpp b/src/duckstation-qt/displaysettingswidget.cpp index 99c0009de..ef53cee73 100644 --- a/src/duckstation-qt/displaysettingswidget.cpp +++ b/src/duckstation-qt/displaysettingswidget.cpp @@ -62,9 +62,9 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW "renderers.
This option is only supported in Direct3D and Vulkan. OpenGL will always use the default " "device.")); dialog->registerWidgetHelp( - m_ui.displayAspectRatio, tr("Aspect Ratio"), QStringLiteral("4:3"), - tr("Changes the aspect ratio used to display the console's output to the screen. The default " - "is 4:3 which matches a typical TV of the era.")); + m_ui.displayAspectRatio, tr("Aspect Ratio"), QStringLiteral("Auto (Game Native)"), + tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto (Game Native) " + "which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era.")); dialog->registerWidgetHelp( m_ui.displayCropMode, tr("Crop Mode"), tr("Only Overscan Area"), tr("Determines how much of the area typically not visible on a consumer TV set to crop/hide.
"