From fbfd838e22c9e3e28378904027dd6643b56e5c7c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 10 Apr 2020 15:12:16 +1000 Subject: [PATCH] GPU: Add pixel aspect ratio option Can display in 4:3, 16:9, 1:1 ratios. --- src/core/gpu.cpp | 17 ++++++++---- src/core/host_display.cpp | 27 ------------------ src/core/host_interface.cpp | 5 +++- src/core/save_state_version.h | 2 +- src/core/settings.cpp | 32 ++++++++++++++++++++++ src/core/settings.h | 5 ++++ src/core/types.h | 8 ++++++ src/duckstation-qt/gpusettingswidget.cpp | 13 +++++++-- src/duckstation-qt/gpusettingswidget.ui | 18 +++++++++--- src/duckstation-sdl/sdl_host_interface.cpp | 15 ++++++++++ 10 files changed, 101 insertions(+), 41 deletions(-) diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 21ea01d71..93e1fc03f 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -29,6 +29,8 @@ bool GPU::Initialize(HostDisplay* host_display, System* system, DMA* dma, Interr m_timers = timers; m_force_progressive_scan = m_system->GetSettings().display_force_progressive_scan; m_force_ntsc_timings = m_system->GetSettings().gpu_force_ntsc_timings; + m_crtc_state.display_aspect_ratio = + Settings::GetDisplayAspectRatioValue(m_system->GetSettings().display_aspect_ratio); m_tick_event = m_system->CreateTimingEvent("GPU Tick", 1, 1, std::bind(&GPU::Execute, this, std::placeholders::_1), true); return true; @@ -44,6 +46,9 @@ void GPU::UpdateSettings() UpdateCRTCConfig(); } + m_crtc_state.display_aspect_ratio = + Settings::GetDisplayAspectRatioValue(m_system->GetSettings().display_aspect_ratio); + // Crop mode calls this, so recalculate the display area UpdateCRTCDisplayParameters(); } @@ -64,10 +69,14 @@ void GPU::SoftReset() m_drawing_area.Set(0, 0, 0, 0); m_drawing_area_changed = true; m_drawing_offset = {}; - std::memset(&m_crtc_state, 0, sizeof(m_crtc_state)); - m_crtc_state.regs.display_address_start = 0; + std::memset(&m_crtc_state.regs, 0, sizeof(m_crtc_state.regs)); m_crtc_state.regs.horizontal_display_range = 0xC60260; m_crtc_state.regs.vertical_display_range = 0x3FC10; + m_crtc_state.fractional_ticks = 0; + m_crtc_state.current_tick_in_scanline = 0; + m_crtc_state.current_scanline = 0; + m_crtc_state.in_hblank = false; + m_crtc_state.in_vblank = false; m_state = State::Idle; m_blitter_ticks = 0; m_command_total_words = 0; @@ -136,7 +145,6 @@ bool GPU::DoState(StateWrapper& sw) sw.Do(&m_crtc_state.fractional_ticks); sw.Do(&m_crtc_state.current_tick_in_scanline); sw.Do(&m_crtc_state.current_scanline); - sw.Do(&m_crtc_state.display_aspect_ratio); sw.Do(&m_crtc_state.in_hblank); sw.Do(&m_crtc_state.in_vblank); @@ -521,9 +529,6 @@ void GPU::UpdateCRTCDisplayParameters() (vertical_visible_end_line - std::max(vertical_display_start, vertical_visible_start_line)) << height_shift, VRAM_HEIGHT - cs.display_vram_top); } - - // Aspect ratio is always 4:3. - cs.display_aspect_ratio = 4.0f / 3.0f; } TickCount GPU::GetPendingGPUTicks() const diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index 335cf105b..494e7ea4d 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -20,32 +20,6 @@ void HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height) std::tuple HostDisplay::CalculateDrawRect() const { -#if 0 - // convert display region to correct pixel aspect ratio - float display_width, display_height, active_left, active_top, active_width, active_height; - if (m_display_width >= m_display_height) - { - display_width = static_cast(m_display_width); - display_height = static_cast(m_display_width) / m_display_pixel_aspect_ratio; - - const float scale = display_height / static_cast(m_display_height); - active_left = static_cast(m_display_active_left); - active_top = static_cast(m_display_active_top) * scale; - active_width = static_cast(m_display_active_width); - active_height = static_cast(m_display_active_width) / m_display_pixel_aspect_ratio; - } - else - { - display_width = static_cast(m_display_height) * m_display_pixel_aspect_ratio; - display_height = static_cast(m_display_height); - - const float scale = display_width / static_cast(m_display_width); - active_left = static_cast(m_display_active_left) * scale; - active_top = static_cast(m_display_active_top); - active_width = static_cast(m_display_active_height) * m_display_pixel_aspect_ratio; - active_height = static_cast(m_display_active_height); - } -#else const float y_scale = (static_cast(m_display_width) / static_cast(m_display_height)) / m_display_pixel_aspect_ratio; const float display_width = static_cast(m_display_width); @@ -54,7 +28,6 @@ std::tuple HostDisplay::CalculateDrawRect() const const float active_top = static_cast(m_display_active_top) * y_scale; const float active_width = static_cast(m_display_active_width); const float active_height = static_cast(m_display_active_height) * y_scale; -#endif // now fit it within the window const s32 window_width = m_window_width; diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index ec6c06a3c..8822bf6ca 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -880,6 +880,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetBoolValue("GPU", "ForceNTSCTimings", false); si.SetStringValue("Display", "CropMode", "Overscan"); + si.SetStringValue("Display", "PixelAspectRatio", "4:3"); si.SetBoolValue("Display", "ForceProgressiveScan", true); si.SetBoolValue("Display", "LinearFiltering", true); si.SetBoolValue("Display", "ShowOSDMessages", true); @@ -934,6 +935,7 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) const bool old_audio_sync_enabled = m_settings.audio_sync_enabled; const bool old_speed_limiter_enabled = m_settings.speed_limiter_enabled; const DisplayCropMode old_display_crop_mode = m_settings.display_crop_mode; + const DisplayAspectRatio old_display_aspect_ratio = m_settings.display_aspect_ratio; const bool old_display_linear_filtering = m_settings.display_linear_filtering; const bool old_cdrom_read_thread = m_settings.cdrom_read_thread; std::array old_controller_types = m_settings.controller_types; @@ -983,7 +985,8 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) m_settings.gpu_texture_filtering != old_gpu_texture_filtering || m_settings.gpu_force_ntsc_timings != old_gpu_force_ntsc_timings || m_settings.display_force_progressive_scan != old_display_force_progressive_scan || - m_settings.display_crop_mode != old_display_crop_mode) + m_settings.display_crop_mode != old_display_crop_mode || + m_settings.display_aspect_ratio != old_display_aspect_ratio) { m_system->UpdateGPUSettings(); } diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index 9b110ae52..f7193a1bd 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -2,4 +2,4 @@ #include "types.h" static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; -static constexpr u32 SAVE_STATE_VERSION = 20; +static constexpr u32 SAVE_STATE_VERSION = 21; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index f48841e08..a1a780118 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -32,6 +32,10 @@ void Settings::Load(SettingsInterface& si) display_crop_mode = ParseDisplayCropMode( si.GetStringValue("Display", "CropMode", GetDisplayCropModeName(DisplayCropMode::None)).c_str()) .value_or(DisplayCropMode::None); + display_aspect_ratio = + ParseDisplayAspectRatio( + si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DisplayAspectRatio::R4_3)).c_str()) + .value_or(DisplayAspectRatio::R4_3); display_force_progressive_scan = si.GetBoolValue("Display", "ForceProgressiveScan", true); display_linear_filtering = si.GetBoolValue("Display", "LinearFiltering", true); display_show_osd_messages = si.GetBoolValue("Display", "ShowOSDMessages", true); @@ -93,6 +97,7 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings); si.SetStringValue("Display", "CropMode", GetDisplayCropModeName(display_crop_mode)); + si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio)); si.SetBoolValue("Display", "ForceProgressiveScan", display_force_progressive_scan); si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages); @@ -288,6 +293,33 @@ 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", "1:1"}}; +static constexpr std::array s_display_aspect_ratio_values = {{4.0f / 3.0f, 16.0f / 9.0f, 1.0f}}; + +std::optional Settings::ParseDisplayAspectRatio(const char* str) +{ + int index = 0; + for (const char* name : s_display_aspect_ratio_names) + { + if (StringUtil::Strcasecmp(name, str) == 0) + return static_cast(index); + + index++; + } + + return std::nullopt; +} + +const char* Settings::GetDisplayAspectRatioName(DisplayAspectRatio ar) +{ + return s_display_aspect_ratio_names[static_cast(ar)]; +} + +float Settings::GetDisplayAspectRatioValue(DisplayAspectRatio ar) +{ + return s_display_aspect_ratio_values[static_cast(ar)]; +} + static std::array s_audio_backend_names = {{"Null", "Cubeb", "SDL"}}; static std::array s_audio_backend_display_names = {{"Null (No Output)", "Cubeb", "SDL"}}; diff --git a/src/core/settings.h b/src/core/settings.h index 3f1dd5897..be495d70f 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -53,6 +53,7 @@ struct Settings bool gpu_use_debug_device = false; bool gpu_force_ntsc_timings = false; DisplayCropMode display_crop_mode = DisplayCropMode::None; + DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3; bool display_force_progressive_scan = false; bool display_linear_filtering = true; bool display_show_osd_messages = false; @@ -114,6 +115,10 @@ struct Settings static const char* GetDisplayCropModeName(DisplayCropMode crop_mode); static const char* GetDisplayCropModeDisplayName(DisplayCropMode crop_mode); + static std::optional ParseDisplayAspectRatio(const char* str); + static const char* GetDisplayAspectRatioName(DisplayAspectRatio ar); + static float GetDisplayAspectRatioValue(DisplayAspectRatio ar); + static std::optional ParseAudioBackend(const char* str); static const char* GetAudioBackendName(AudioBackend backend); static const char* GetAudioBackendDisplayName(AudioBackend backend); diff --git a/src/core/types.h b/src/core/types.h index f551457d5..d7f3e6529 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -66,6 +66,14 @@ enum class DisplayCropMode : u8 Count }; +enum class DisplayAspectRatio : u8 +{ + R4_3, + R16_9, + R1_1, + Count +}; + enum class AudioBackend : u8 { Null, diff --git a/src/duckstation-qt/gpusettingswidget.cpp b/src/duckstation-qt/gpusettingswidget.cpp index 661364c0b..c0721e13f 100644 --- a/src/duckstation-qt/gpusettingswidget.cpp +++ b/src/duckstation-qt/gpusettingswidget.cpp @@ -12,7 +12,10 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.renderer, "GPU/Renderer", &Settings::ParseRendererName, &Settings::GetRendererName); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.useDebugDevice, "GPU/UseDebugDevice"); - SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cropMode, "Display/CropMode", + SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayAspectRatio, "Display/AspectRatio", + &Settings::ParseDisplayAspectRatio, + &Settings::GetDisplayAspectRatioName); + SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayCropMode, "Display/CropMode", &Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.forceProgressiveScan, "Display/ForceProgressiveScan"); @@ -46,9 +49,15 @@ void GPUSettingsWidget::setupAdditionalUi() for (u32 i = 0; i < static_cast(GPURenderer::Count); i++) m_ui.renderer->addItem(QString::fromLocal8Bit(Settings::GetRendererDisplayName(static_cast(i)))); + for (u32 i = 0; i < static_cast(DisplayAspectRatio::Count); i++) + { + m_ui.displayAspectRatio->addItem( + QString::fromLocal8Bit(Settings::GetDisplayAspectRatioName(static_cast(i)))); + } + for (u32 i = 0; i < static_cast(DisplayCropMode::Count); i++) { - m_ui.cropMode->addItem( + m_ui.displayCropMode->addItem( QString::fromLocal8Bit(Settings::GetDisplayCropModeDisplayName(static_cast(i)))); } diff --git a/src/duckstation-qt/gpusettingswidget.ui b/src/duckstation-qt/gpusettingswidget.ui index ea1507bfa..a42d62ffb 100644 --- a/src/duckstation-qt/gpusettingswidget.ui +++ b/src/duckstation-qt/gpusettingswidget.ui @@ -59,23 +59,33 @@ + + + Aspect Ratio: + + + + + + + Crop: - - + + - + Linear Upscaling - + VSync diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index f4d0e64e4..d028c4579 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -1245,6 +1245,21 @@ void SDLHostInterface::DrawSettingsWindow() if (DrawSettingsSectionHeader("Display Output")) { + ImGui::Text("Aspect Ratio:"); + ImGui::SameLine(indent); + int display_aspect_ratio = static_cast(m_settings_copy.display_aspect_ratio); + if (ImGui::Combo( + "##display_pixel_aspect_ratio", &display_aspect_ratio, + [](void*, int index, const char** out_text) { + *out_text = Settings::GetDisplayAspectRatioName(static_cast(index)); + return true; + }, + nullptr, static_cast(DisplayAspectRatio::Count))) + { + m_settings_copy.display_aspect_ratio = static_cast(display_aspect_ratio); + settings_changed = true; + } + ImGui::Text("Crop:"); ImGui::SameLine(indent);