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 };