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.
This commit is contained in:
Stenzek 2024-11-26 18:00:17 +10:00
parent be7a20fef2
commit 0befbf8021
No known key found for this signature in database
6 changed files with 82 additions and 57 deletions

View File

@ -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<float>(g_gpu_device->GetMainSwapChain()->GetWidth()) /
static_cast<float>(g_gpu_device->GetMainSwapChain()->GetHeight());
ar = static_cast<float>(g_gpu_device->GetMainSwapChain()->GetWidth()) /
static_cast<float>(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<float>(m_crtc_state.display_width) / static_cast<float>(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<float>(cs.horizontal_visible_end - cs.horizontal_visible_start);
float relative_height = static_cast<float>(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<u16, 8> 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<float>(window_width) / static_cast<float>(window_height);
const float crtc_display_width = static_cast<float>(show_vram ? VRAM_WIDTH : m_crtc_state.display_width);
const float crtc_display_height = static_cast<float>(show_vram ? VRAM_HEIGHT : m_crtc_state.display_height);
const float x_scale =
apply_aspect_ratio ?
(display_aspect_ratio / (static_cast<float>(crtc_display_width) / static_cast<float>(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<float>(show_vram ? 0 : m_crtc_state.display_origin_left);
float active_top = static_cast<float>(show_vram ? 0 : m_crtc_state.display_origin_top);
float active_width = static_cast<float>(show_vram ? VRAM_WIDTH : m_crtc_state.display_vram_width);
float active_height = static_cast<float>(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<u32>(display_rect->width());
const u32 draw_height = static_cast<u32>(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<float>(m_display_texture_view_width) / static_cast<float>(m_display_texture_view_height);
const float dar = static_cast<float>(draw_width) / static_cast<float>(draw_height);
if (sar >= dar)
{
// stretch height, preserve width
const float scale = static_cast<float>(m_display_texture_view_width) / static_cast<float>(draw_width);
*width = m_display_texture_view_width;
*height = static_cast<u32>(std::round(static_cast<float>(draw_height) * scale));
}
else
{
// stretch width, preserve height
const float scale = static_cast<float>(m_display_texture_view_height) / static_cast<float>(draw_height);
*width = static_cast<u32>(std::round(static_cast<float>(draw_width) * scale));
*height = m_display_texture_view_height;
}
float f_width = static_cast<float>(m_display_texture_view_width);
float f_height = static_cast<float>(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<float>(g_gpu_device->GetMaxTextureSize());
if (f_width > max_texture_size)
{
*height = static_cast<u32>(static_cast<float>(*height) /
(static_cast<float>(*width) / static_cast<float>(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<u32>(static_cast<float>(*width) /
(static_cast<float>(*height) / static_cast<float>(max_texture_size)));
f_height = max_texture_size;
f_width = f_width / (f_height / max_texture_size);
}
*width = static_cast<u32>(std::ceil(f_width));
*height = static_cast<u32>(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<s32>(*width), static_cast<s32>(*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,

View File

@ -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<GPU> CreateHardwareRenderer();
static std::unique_ptr<GPU> CreateSoftwareRenderer();

View File

@ -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,

View File

@ -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<DisplayCropMode> Settings::ParseDisplayCropMode(const char* str)

View File

@ -5678,20 +5678,18 @@ void System::RequestDisplaySize(float scale /*= 0.0f*/)
if (scale == 0.0f)
scale = g_gpu->IsHardwareRenderer() ? static_cast<float>(g_settings.gpu_resolution_scale) : 1.0f;
const float y_scale =
(static_cast<float>(g_gpu->GetCRTCDisplayWidth()) / static_cast<float>(g_gpu->GetCRTCDisplayHeight())) /
g_gpu->ComputeDisplayAspectRatio();
u32 requested_width =
std::max<u32>(static_cast<u32>(std::ceil(static_cast<float>(g_gpu->GetCRTCDisplayWidth()) * scale)), 1);
u32 requested_height =
std::max<u32>(static_cast<u32>(std::ceil(static_cast<float>(g_gpu->GetCRTCDisplayHeight()) * y_scale * scale)), 1);
float requested_width = static_cast<float>(g_gpu->GetCRTCDisplayWidth()) * scale;
float requested_height = static_cast<float>(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<s32>(requested_width), static_cast<s32>(requested_height));
Host::RequestResizeHostDisplay(static_cast<s32>(std::ceil(requested_width)),
static_cast<s32>(std::ceil(requested_height)));
}
void System::DisplayWindowResized()

View File

@ -143,6 +143,7 @@ enum class DisplayCropMode : u8
Overscan,
OverscanUncorrected,
Borders,
BordersUncorrected,
MaxCount
};