From 0befbf8021951b7e3a621fd3659622837d8adf59 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 26 Nov 2024 18:00:17 +1000 Subject: [PATCH] GPU: Add Uncorrected Borders crop mode Should behave the same as the old "All Borders" mode. The pixel aspect ratio WILL BE WRONG. Also fixes the size of screenshots in internal resolution mode. --- src/core/gpu.cpp | 108 +++++++++++++++++++++--------------- src/core/gpu.h | 7 +++ src/core/imgui_overlays.cpp | 2 +- src/core/settings.cpp | 5 +- src/core/system.cpp | 16 +++--- src/core/types.h | 1 + 6 files changed, 82 insertions(+), 57 deletions(-) diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 4340c2042..c0748bb6e 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -609,9 +609,8 @@ float GPU::ComputeDisplayAspectRatio() const { if (g_settings.display_aspect_ratio == DisplayAspectRatio::MatchWindow && g_gpu_device->HasMainSwapChain()) { - // Match window has already been corrected. - return static_cast(g_gpu_device->GetMainSwapChain()->GetWidth()) / - static_cast(g_gpu_device->GetMainSwapChain()->GetHeight()); + ar = static_cast(g_gpu_device->GetMainSwapChain()->GetWidth()) / + static_cast(g_gpu_device->GetMainSwapChain()->GetHeight()); } else if (g_settings.display_aspect_ratio == DisplayAspectRatio::Custom) { @@ -624,7 +623,19 @@ float GPU::ComputeDisplayAspectRatio() const } } - return ComputeAspectRatioCorrection() * ar; + return ar; +} + +float GPU::ComputeSourceAspectRatio() const +{ + const float source_aspect_ratio = + static_cast(m_crtc_state.display_width) / static_cast(m_crtc_state.display_height); + + // Correction is applied to the GTE for stretch to fit, that way it fills the window. + const float source_aspect_ratio_correction = + (g_settings.display_aspect_ratio == DisplayAspectRatio::MatchWindow) ? 1.0f : ComputeAspectRatioCorrection(); + + return source_aspect_ratio / source_aspect_ratio_correction; } float GPU::ComputeAspectRatioCorrection() const @@ -632,8 +643,9 @@ float GPU::ComputeAspectRatioCorrection() const 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 || - g_settings.display_crop_mode == DisplayCropMode::OverscanUncorrected) + if (relative_width <= 0 || relative_height <= 0 || g_settings.display_aspect_ratio == DisplayAspectRatio::PAR1_1 || + g_settings.display_crop_mode == DisplayCropMode::OverscanUncorrected || + g_settings.display_crop_mode == DisplayCropMode::BordersUncorrected) { return 1.0f; } @@ -652,6 +664,24 @@ float GPU::ComputeAspectRatioCorrection() const return (relative_width / relative_height); } +void GPU::ApplyPixelAspectRatioToSize(float* width, float* height) const +{ + const float dar = ComputeDisplayAspectRatio(); + const float sar = ComputeSourceAspectRatio(); + const float par = dar / sar; + + if (par < 1.0f) + { + // stretch height, preserve width + *height = std::ceil(*height / par); + } + else + { + // stretch width, preserve height + *width = std::ceil(*width * par); + } +} + void GPU::UpdateCRTCConfig() { static constexpr std::array dot_clock_dividers = {{10, 8, 5, 4, 7, 7, 7, 7}}; @@ -770,6 +800,7 @@ void GPU::UpdateCRTCDisplayParameters() break; case DisplayCropMode::Borders: + case DisplayCropMode::BordersUncorrected: default: cs.horizontal_visible_start = horizontal_display_start; cs.horizontal_visible_end = horizontal_display_end; @@ -808,6 +839,7 @@ void GPU::UpdateCRTCDisplayParameters() break; case DisplayCropMode::Borders: + case DisplayCropMode::BordersUncorrected: default: cs.horizontal_visible_start = horizontal_display_start; cs.horizontal_visible_end = horizontal_display_end; @@ -2341,20 +2373,20 @@ void GPU::CalculateDrawRect(s32 window_width, s32 window_height, bool apply_rota const bool integer_scale = (g_settings.display_scaling == DisplayScalingMode::NearestInteger || g_settings.display_scaling == DisplayScalingMode::BilinearInteger); const bool show_vram = g_settings.debugging.show_vram; - const float display_aspect_ratio = ComputeDisplayAspectRatio(); const float window_ratio = static_cast(window_width) / static_cast(window_height); const float crtc_display_width = static_cast(show_vram ? VRAM_WIDTH : m_crtc_state.display_width); const float crtc_display_height = static_cast(show_vram ? VRAM_HEIGHT : m_crtc_state.display_height); - const float x_scale = - apply_aspect_ratio ? - (display_aspect_ratio / (static_cast(crtc_display_width) / static_cast(crtc_display_height))) : - 1.0f; + const float display_aspect_ratio = ComputeDisplayAspectRatio(); + const float source_aspect_ratio = ComputeSourceAspectRatio(); + const float pixel_aspect_ratio = display_aspect_ratio / source_aspect_ratio; + const float x_scale = apply_aspect_ratio ? pixel_aspect_ratio : 1.0f; float display_width = crtc_display_width; float display_height = crtc_display_height; float active_left = static_cast(show_vram ? 0 : m_crtc_state.display_origin_left); float active_top = static_cast(show_vram ? 0 : m_crtc_state.display_origin_top); float active_width = static_cast(show_vram ? VRAM_WIDTH : m_crtc_state.display_vram_width); float active_height = static_cast(show_vram ? VRAM_HEIGHT : m_crtc_state.display_vram_height); + if (!g_settings.display_stretch_vertically) { display_width *= x_scale; @@ -2604,52 +2636,30 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const GSVector4i displ void GPU::CalculateScreenshotSize(DisplayScreenshotMode mode, u32* width, u32* height, GSVector4i* display_rect, GSVector4i* draw_rect) const { - *width = g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetWidth() : 1; - *height = g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetHeight() : 1; - CalculateDrawRect(*width, *height, true, !g_settings.debugging.show_vram, display_rect, draw_rect); - const bool internal_resolution = (mode != DisplayScreenshotMode::ScreenResolution || g_settings.debugging.show_vram); if (internal_resolution && m_display_texture_view_width != 0 && m_display_texture_view_height != 0) { if (mode == DisplayScreenshotMode::InternalResolution) { - const u32 draw_width = static_cast(display_rect->width()); - const u32 draw_height = static_cast(display_rect->height()); - - // If internal res, scale the computed draw rectangle to the internal res. - // We re-use the draw rect because it's already been AR corrected. - const float sar = - static_cast(m_display_texture_view_width) / static_cast(m_display_texture_view_height); - const float dar = static_cast(draw_width) / static_cast(draw_height); - if (sar >= dar) - { - // stretch height, preserve width - const float scale = static_cast(m_display_texture_view_width) / static_cast(draw_width); - *width = m_display_texture_view_width; - *height = static_cast(std::round(static_cast(draw_height) * scale)); - } - else - { - // stretch width, preserve height - const float scale = static_cast(m_display_texture_view_height) / static_cast(draw_height); - *width = static_cast(std::round(static_cast(draw_width) * scale)); - *height = m_display_texture_view_height; - } + float f_width = static_cast(m_display_texture_view_width); + float f_height = static_cast(m_display_texture_view_height); + ApplyPixelAspectRatioToSize(&f_width, &f_height); // DX11 won't go past 16K texture size. - const u32 max_texture_size = g_gpu_device->GetMaxTextureSize(); - if (*width > max_texture_size) + const float max_texture_size = static_cast(g_gpu_device->GetMaxTextureSize()); + if (f_width > max_texture_size) { - *height = static_cast(static_cast(*height) / - (static_cast(*width) / static_cast(max_texture_size))); - *width = max_texture_size; + f_height = f_height / (f_width / max_texture_size); + f_width = max_texture_size; } - if (*height > max_texture_size) + if (f_height > max_texture_size) { - *height = max_texture_size; - *width = static_cast(static_cast(*width) / - (static_cast(*height) / static_cast(max_texture_size))); + f_height = max_texture_size; + f_width = f_width / (f_height / max_texture_size); } + + *width = static_cast(std::ceil(f_width)); + *height = static_cast(std::ceil(f_height)); } else // if (mode == DisplayScreenshotMode::UncorrectedInternalResolution) { @@ -2661,6 +2671,12 @@ void GPU::CalculateScreenshotSize(DisplayScreenshotMode mode, u32* width, u32* h *draw_rect = GSVector4i(0, 0, static_cast(*width), static_cast(*height)); *display_rect = *draw_rect; } + else + { + *width = g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetWidth() : 1; + *height = g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetHeight() : 1; + CalculateDrawRect(*width, *height, true, !g_settings.debugging.show_vram, display_rect, draw_rect); + } } bool GPU::RenderScreenshotToFile(std::string path, DisplayScreenshotMode mode, u8 quality, bool compress_on_thread, diff --git a/src/core/gpu.h b/src/core/gpu.h index 3469a513a..cb57fa3d5 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -184,8 +184,15 @@ public: float ComputeHorizontalFrequency() const; float ComputeVerticalFrequency() const; float ComputeDisplayAspectRatio() const; + float ComputeSourceAspectRatio() const; + + /// Computes aspect ratio correction, i.e. the scale to apply to the source aspect ratio to preserve + /// the original pixel aspect ratio regardless of how much cropping has been applied. float ComputeAspectRatioCorrection() const; + /// Applies the pixel aspect ratio to a given size, preserving the larger dimension. + void ApplyPixelAspectRatioToSize(float* width, float* height) const; + static std::unique_ptr CreateHardwareRenderer(); static std::unique_ptr CreateSoftwareRenderer(); diff --git a/src/core/imgui_overlays.cpp b/src/core/imgui_overlays.cpp index e21f1cf94..afd09ec3b 100644 --- a/src/core/imgui_overlays.cpp +++ b/src/core/imgui_overlays.cpp @@ -389,7 +389,7 @@ void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, float if (g_settings.display_show_resolution) { const u32 resolution_scale = g_gpu->GetResolutionScale(); - const auto [display_width, display_height] = g_gpu->GetFullDisplayResolution(); + const auto [display_width, display_height] = g_gpu->GetFullDisplayResolution();// wrong const bool interlaced = g_gpu->IsInterlacedDisplayEnabled(); const bool pal = g_gpu->IsInPALMode(); text.format("{}x{} {} {} [{}x]", display_width * resolution_scale, display_height * resolution_scale, diff --git a/src/core/settings.cpp b/src/core/settings.cpp index d13091974..29ef1facb 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -1620,12 +1620,15 @@ const char* Settings::GetDisplayDeinterlacingModeDisplayName(DisplayDeinterlacin "DisplayDeinterlacingMode"); } -static constexpr const std::array s_display_crop_mode_names = {"None", "Overscan", "OverscanUncorrected", "Borders"}; +static constexpr const std::array s_display_crop_mode_names = { + "None", "Overscan", "OverscanUncorrected", "Borders", "BordersUncorrected", +}; static constexpr const std::array s_display_crop_mode_display_names = { TRANSLATE_DISAMBIG_NOOP("Settings", "None", "DisplayCropMode"), TRANSLATE_DISAMBIG_NOOP("Settings", "Only Overscan Area", "DisplayCropMode"), TRANSLATE_DISAMBIG_NOOP("Settings", "Only Overscan Area (Aspect Uncorrected)", "DisplayCropMode"), TRANSLATE_DISAMBIG_NOOP("Settings", "All Borders", "DisplayCropMode"), + TRANSLATE_DISAMBIG_NOOP("Settings", "All Borders (Aspect Uncorrected)", "DisplayCropMode"), }; std::optional Settings::ParseDisplayCropMode(const char* str) diff --git a/src/core/system.cpp b/src/core/system.cpp index cfc60ba89..4b425f1c8 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -5678,20 +5678,18 @@ void System::RequestDisplaySize(float scale /*= 0.0f*/) if (scale == 0.0f) scale = g_gpu->IsHardwareRenderer() ? static_cast(g_settings.gpu_resolution_scale) : 1.0f; - const float y_scale = - (static_cast(g_gpu->GetCRTCDisplayWidth()) / static_cast(g_gpu->GetCRTCDisplayHeight())) / - g_gpu->ComputeDisplayAspectRatio(); - - u32 requested_width = - std::max(static_cast(std::ceil(static_cast(g_gpu->GetCRTCDisplayWidth()) * scale)), 1); - u32 requested_height = - std::max(static_cast(std::ceil(static_cast(g_gpu->GetCRTCDisplayHeight()) * y_scale * scale)), 1); + float requested_width = static_cast(g_gpu->GetCRTCDisplayWidth()) * scale; + float requested_height = static_cast(g_gpu->GetCRTCDisplayHeight()) * scale; + g_gpu->ApplyPixelAspectRatioToSize(&requested_width, &requested_height); if (g_settings.display_rotation == DisplayRotation::Rotate90 || g_settings.display_rotation == DisplayRotation::Rotate270) + { std::swap(requested_width, requested_height); + } - Host::RequestResizeHostDisplay(static_cast(requested_width), static_cast(requested_height)); + Host::RequestResizeHostDisplay(static_cast(std::ceil(requested_width)), + static_cast(std::ceil(requested_height))); } void System::DisplayWindowResized() diff --git a/src/core/types.h b/src/core/types.h index 4ebcc2dfb..3c532b73b 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -143,6 +143,7 @@ enum class DisplayCropMode : u8 Overscan, OverscanUncorrected, Borders, + BordersUncorrected, MaxCount };