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)

This commit is contained in:
Filoppi 2023-06-27 12:45:01 +03:00
parent cb34d1aafe
commit 6c7f34d5da
2 changed files with 54 additions and 17 deletions

View File

@ -280,9 +280,12 @@ Presenter::ConvertStereoRectangle(const MathUtil::Rectangle<int>& rc) const
return std::make_tuple(left_rc, right_rc); 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 stretch is enabled, we prefer the aspect ratio of the window.
if (aspect_mode == AspectMode::Stretch) 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; 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); return std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1);
} }
void Presenter::SetWindowSize(int width, int height) 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. // 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) 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_width = out_width;
m_last_window_request_height = out_height; 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); Host_RequestRenderWindowSize(out_width, out_height);
} }
// Crop to exactly 16:9 or 4:3 if enabled and not AspectMode::Stretch. // Crop to exactly 16:9 or 4:3 if enabled and not AspectMode::Stretch.
std::tuple<float, float> Presenter::ApplyStandardAspectCrop(float width, float height) const std::tuple<float, float> 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) if (!g_ActiveConfig.bCrop || aspect_mode == AspectMode::Stretch)
return {width, height}; return {width, height};
@ -506,14 +520,14 @@ void Presenter::UpdateDrawRectangle()
m_target_rectangle.bottom = m_target_rectangle.top + int_draw_height; m_target_rectangle.bottom = m_target_rectangle.top + int_draw_height;
} }
std::tuple<float, float> Presenter::ScaleToDisplayAspectRatio(const int width, std::tuple<float, float> Presenter::ScaleToDisplayAspectRatio(const int width, const int height,
const int height) const bool allow_stretch) const
{ {
// Scale either the width or height depending the content aspect ratio. // Scale either the width or height depending the content aspect ratio.
// This way we preserve as much resolution as possible when scaling. // This way we preserve as much resolution as possible when scaling.
float scaled_width = static_cast<float>(width); float scaled_width = static_cast<float>(width);
float scaled_height = static_cast<float>(height); float scaled_height = static_cast<float>(height);
const float draw_aspect = CalculateDrawAspectRatio(); const float draw_aspect = CalculateDrawAspectRatio(allow_stretch);
if (scaled_width / scaled_height >= draw_aspect) if (scaled_width / scaled_height >= draw_aspect)
scaled_height = scaled_width / draw_aspect; scaled_height = scaled_width / draw_aspect;
else else
@ -521,18 +535,38 @@ std::tuple<float, float> Presenter::ScaleToDisplayAspectRatio(const int width,
return std::make_tuple(scaled_width, scaled_height); return std::make_tuple(scaled_width, scaled_height);
} }
std::tuple<int, int> Presenter::CalculateOutputDimensions(int width, int height) const std::tuple<int, int> Presenter::CalculateOutputDimensions(int width, int height,
bool allow_stretch) const
{ {
width = std::max(width, 1); width = std::max(width, 1);
height = std::max(height, 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. // 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<int>(std::ceil(scaled_width)); auto aspect_mode = g_ActiveConfig.aspect_mode;
height = static_cast<int>(std::ceil(scaled_height));
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<int>(std::ceil(scaled_width));
height = static_cast<int>(std::ceil(scaled_height));
}
if (g_frame_dumper->IsFrameDumping()) if (g_frame_dumper->IsFrameDumping())
{ {

View File

@ -58,7 +58,7 @@ public:
void UpdateDrawRectangle(); 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 // 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 // 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; void ProcessFrameDumping(u64 ticks) const;
std::tuple<int, int> CalculateOutputDimensions(int width, int height) const; std::tuple<int, int> CalculateOutputDimensions(int width, int height,
std::tuple<float, float> ApplyStandardAspectCrop(float width, float height) const; bool allow_stretch = true) const;
std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height) const; std::tuple<float, float> ApplyStandardAspectCrop(float width, float height,
bool allow_stretch = true) const;
std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height,
bool allow_stretch = true) const;
// Use this to convert a single target rectangle to two stereo rectangles // Use this to convert a single target rectangle to two stereo rectangles
std::tuple<MathUtil::Rectangle<int>, MathUtil::Rectangle<int>> std::tuple<MathUtil::Rectangle<int>, MathUtil::Rectangle<int>>