From 6c7f34d5da28475a4d1eb9e67ffd1617cbd501b3 Mon Sep 17 00:00:00 2001 From: Filoppi Date: Tue, 27 Jun 2023 12:45:01 +0300 Subject: [PATCH] Video: The `Auto-Adjust Window Size` setting was calculating the window size based on the resolution of the window in the previous frame if we used the "stretch" aspect ratio setting, so it's result would be self influence in a loop and behave unreliably (e.g. when changing resolution between Auto/Native/2x the automatic window scaling would behave randomly) --- Source/Core/VideoCommon/Present.cpp | 60 ++++++++++++++++++++++------- Source/Core/VideoCommon/Present.h | 11 ++++-- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index 5229b26f74..53d0d737d0 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -280,9 +280,12 @@ Presenter::ConvertStereoRectangle(const MathUtil::Rectangle& rc) const return std::make_tuple(left_rc, right_rc); } -float Presenter::CalculateDrawAspectRatio() const +float Presenter::CalculateDrawAspectRatio(bool allow_stretch) const { - const auto aspect_mode = g_ActiveConfig.aspect_mode; + auto aspect_mode = g_ActiveConfig.aspect_mode; + + if (!allow_stretch && aspect_mode == AspectMode::Stretch) + aspect_mode = AspectMode::Auto; // If stretch is enabled, we prefer the aspect ratio of the window. if (aspect_mode == AspectMode::Stretch) @@ -367,9 +370,15 @@ u32 Presenter::AutoIntegralScale() const u32 height = EFB_HEIGHT * m_target_rectangle.GetHeight() / m_last_xfb_height; return std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1); } + void Presenter::SetWindowSize(int width, int height) { - const auto [out_width, out_height] = g_presenter->CalculateOutputDimensions(width, height); + // While trying to guess the best window resolution, we can't allow it to use the + // "AspectMode::Stretch" setting because that would self influence the output result, + // given it would be based on the previous frame resolution + const bool allow_stretch = false; + const auto [out_width, out_height] = + g_presenter->CalculateOutputDimensions(width, height, allow_stretch); // Track the last values of width/height to avoid sending a window resize event every frame. if (out_width == m_last_window_request_width && out_height == m_last_window_request_height) @@ -377,13 +386,18 @@ void Presenter::SetWindowSize(int width, int height) m_last_window_request_width = out_width; m_last_window_request_height = out_height; + // Pass in the suggested window size. This might not always be acknowledged. Host_RequestRenderWindowSize(out_width, out_height); } // Crop to exactly 16:9 or 4:3 if enabled and not AspectMode::Stretch. -std::tuple Presenter::ApplyStandardAspectCrop(float width, float height) const +std::tuple Presenter::ApplyStandardAspectCrop(float width, float height, + bool allow_stretch) const { - const auto aspect_mode = g_ActiveConfig.aspect_mode; + auto aspect_mode = g_ActiveConfig.aspect_mode; + + if (!allow_stretch && aspect_mode == AspectMode::Stretch) + aspect_mode = AspectMode::Auto; if (!g_ActiveConfig.bCrop || aspect_mode == AspectMode::Stretch) return {width, height}; @@ -506,14 +520,14 @@ void Presenter::UpdateDrawRectangle() m_target_rectangle.bottom = m_target_rectangle.top + int_draw_height; } -std::tuple Presenter::ScaleToDisplayAspectRatio(const int width, - const int height) const +std::tuple Presenter::ScaleToDisplayAspectRatio(const int width, const int height, + bool allow_stretch) const { // Scale either the width or height depending the content aspect ratio. // This way we preserve as much resolution as possible when scaling. float scaled_width = static_cast(width); float scaled_height = static_cast(height); - const float draw_aspect = CalculateDrawAspectRatio(); + const float draw_aspect = CalculateDrawAspectRatio(allow_stretch); if (scaled_width / scaled_height >= draw_aspect) scaled_height = scaled_width / draw_aspect; else @@ -521,18 +535,38 @@ std::tuple Presenter::ScaleToDisplayAspectRatio(const int width, return std::make_tuple(scaled_width, scaled_height); } -std::tuple Presenter::CalculateOutputDimensions(int width, int height) const +std::tuple Presenter::CalculateOutputDimensions(int width, int height, + bool allow_stretch) const { width = std::max(width, 1); height = std::max(height, 1); - auto [scaled_width, scaled_height] = ScaleToDisplayAspectRatio(width, height); + auto [scaled_width, scaled_height] = ScaleToDisplayAspectRatio(width, height, allow_stretch); // Apply crop if enabled. - std::tie(scaled_width, scaled_height) = ApplyStandardAspectCrop(scaled_width, scaled_height); + std::tie(scaled_width, scaled_height) = + ApplyStandardAspectCrop(scaled_width, scaled_height, allow_stretch); - width = static_cast(std::ceil(scaled_width)); - height = static_cast(std::ceil(scaled_height)); + auto aspect_mode = g_ActiveConfig.aspect_mode; + + if (!allow_stretch && aspect_mode == AspectMode::Stretch) + aspect_mode = AspectMode::Auto; + + // Find the closest integer aspect ratio, + // this avoids a small black line from being drawn on one of the four edges + if (!g_ActiveConfig.bCrop && aspect_mode != AspectMode::Stretch) + { + const float draw_aspect_ratio = CalculateDrawAspectRatio(allow_stretch); + const auto [int_width, int_height] = + FindClosestIntegerResolution(scaled_width, scaled_height, draw_aspect_ratio); + width = int_width; + height = int_height; + } + else + { + width = static_cast(std::ceil(scaled_width)); + height = static_cast(std::ceil(scaled_height)); + } if (g_frame_dumper->IsFrameDumping()) { diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h index 14d2104a65..c8bbf44257 100644 --- a/Source/Core/VideoCommon/Present.h +++ b/Source/Core/VideoCommon/Present.h @@ -58,7 +58,7 @@ public: void UpdateDrawRectangle(); - float CalculateDrawAspectRatio() const; + float CalculateDrawAspectRatio(bool allow_stretch = true) const; // Crops the target rectangle to the framebuffer dimensions, reducing the size of the source // rectangle if it is greater. Works even if the source and target rectangles don't have a @@ -103,9 +103,12 @@ private: void ProcessFrameDumping(u64 ticks) const; - std::tuple CalculateOutputDimensions(int width, int height) const; - std::tuple ApplyStandardAspectCrop(float width, float height) const; - std::tuple ScaleToDisplayAspectRatio(int width, int height) const; + std::tuple CalculateOutputDimensions(int width, int height, + bool allow_stretch = true) const; + std::tuple ApplyStandardAspectCrop(float width, float height, + bool allow_stretch = true) const; + std::tuple ScaleToDisplayAspectRatio(int width, int height, + bool allow_stretch = true) const; // Use this to convert a single target rectangle to two stereo rectangles std::tuple, MathUtil::Rectangle>