Support custom and match display aspect ratios

This commit is contained in:
Connor McLaughlin 2021-04-29 02:42:08 +10:00
parent 48bc152a63
commit 256f272768
19 changed files with 283 additions and 112 deletions

View File

@ -45,6 +45,7 @@
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_names"> <string-array name="settings_display_aspect_ratio_names">
<item>Auto (Nativo del juego)</item> <item>Auto (Nativo del juego)</item>
<item>Auto (Match Display)</item>
<item>4:3</item> <item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>

View File

@ -45,6 +45,7 @@
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_names"> <string-array name="settings_display_aspect_ratio_names">
<item>Auto (Game Native)</item> <item>Auto (Game Native)</item>
<item>Auto (Match Display)</item>
<item>4:3</item> <item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>

View File

@ -45,6 +45,7 @@
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_names"> <string-array name="settings_display_aspect_ratio_names">
<item>Auto (Game Native)</item> <item>Auto (Game Native)</item>
<item>Auto (Match Display)</item>
<item>4:3</item> <item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>

View File

@ -45,6 +45,7 @@
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_names"> <string-array name="settings_display_aspect_ratio_names">
<item>Auto (Nativo)</item> <item>Auto (Nativo)</item>
<item>Auto (Match Display)</item>
<item>4:3</item> <item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>

View File

@ -44,8 +44,9 @@
<item>Все границы</item> <item>Все границы</item>
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_names"> <string-array name="settings_display_aspect_ratio_names">
<item>Автонастройка (нативное игре)</item> <item>Автонастройка (нативное игре)</item>
<item>4:3</item> <item>Auto (Match Display)</item>
<item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>
<item>19:9</item> <item>19:9</item>

View File

@ -89,6 +89,7 @@
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_names"> <string-array name="settings_display_aspect_ratio_names">
<item>Auto (Game Native)</item> <item>Auto (Game Native)</item>
<item>Auto (Match Display)</item>
<item>4:3</item> <item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>
@ -105,6 +106,7 @@
</string-array> </string-array>
<string-array name="settings_display_aspect_ratio_values"> <string-array name="settings_display_aspect_ratio_values">
<item>Auto (Game Native)</item> <item>Auto (Game Native)</item>
<item>Auto (Match Window)</item>
<item>4:3</item> <item>4:3</item>
<item>16:9</item> <item>16:9</item>
<item>16:10</item> <item>16:10</item>

View File

@ -492,7 +492,7 @@ float GPU::GetDisplayAspectRatio() const
} }
else else
{ {
return Settings::GetDisplayAspectRatioValue(g_settings.display_aspect_ratio); return g_settings.GetDisplayAspectRatioValue();
} }
} }

View File

@ -3,10 +3,13 @@
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/state_wrapper.h" #include "common/state_wrapper.h"
#include "cpu_core.h" #include "cpu_core.h"
#include "host_display.h"
#include "host_interface.h"
#include "pgxp.h" #include "pgxp.h"
#include "settings.h" #include "settings.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <numeric>
namespace GTE { namespace GTE {
@ -19,6 +22,11 @@ static constexpr s32 IR0_MAX_VALUE = 0x1000;
static constexpr s32 IR123_MIN_VALUE = -(INT64_C(1) << 15); static constexpr s32 IR123_MIN_VALUE = -(INT64_C(1) << 15);
static constexpr s32 IR123_MAX_VALUE = (INT64_C(1) << 15) - 1; static constexpr s32 IR123_MAX_VALUE = (INT64_C(1) << 15) - 1;
static DisplayAspectRatio s_aspect_ratio = DisplayAspectRatio::R4_3;
static u32 s_custom_aspect_ratio_numerator;
static u32 s_custom_aspect_ratio_denominator;
static float s_custom_aspect_ratio_f;
#define REGS CPU::g_state.gte_regs #define REGS CPU::g_state.gte_regs
ALWAYS_INLINE static u32 CountLeadingBits(u32 value) ALWAYS_INLINE static u32 CountLeadingBits(u32 value)
@ -148,6 +156,7 @@ ALWAYS_INLINE static u32 TruncateRGB(s32 value)
void Initialize() void Initialize()
{ {
UpdateAspectRatio();
Reset(); Reset();
} }
@ -162,6 +171,55 @@ bool DoState(StateWrapper& sw)
return !sw.HasError(); return !sw.HasError();
} }
void UpdateAspectRatio()
{
if (!g_settings.gpu_widescreen_hack)
{
s_aspect_ratio = DisplayAspectRatio::R4_3;
return;
}
s_aspect_ratio = g_settings.display_aspect_ratio;
u32 num, denom;
switch (s_aspect_ratio)
{
case DisplayAspectRatio::MatchWindow:
{
const HostDisplay* display = g_host_interface->GetDisplay();
if (!display)
{
s_aspect_ratio = DisplayAspectRatio::R4_3;
return;
}
num = display->GetWindowWidth();
denom = display->GetWindowHeight();
}
break;
case DisplayAspectRatio::Custom:
{
num = g_settings.display_aspect_ratio_custom_numerator;
denom = g_settings.display_aspect_ratio_custom_denominator;
}
break;
default:
return;
}
// (4 / 3) / (num / denom) => gcd((4 * denom) / (3 * num))
const u32 x = 4u * denom;
const u32 y = 3u * num;
const u32 gcd = std::gcd(x, y);
s_custom_aspect_ratio_numerator = x / gcd;
s_custom_aspect_ratio_denominator = y / gcd;
s_custom_aspect_ratio_f = static_cast<float>((4.0 / 3.0) / (static_cast<double>(num) / static_cast<double>(denom)));
}
u32 ReadRegister(u32 index) u32 ReadRegister(u32 index)
{ {
DebugAssert(index < countof(REGS.r32)); DebugAssert(index < countof(REGS.r32));
@ -614,66 +672,65 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last)
const s64 result = static_cast<s64>(ZeroExtend64(UNRDivide(REGS.H, REGS.SZ3))); const s64 result = static_cast<s64>(ZeroExtend64(UNRDivide(REGS.H, REGS.SZ3)));
s64 Sx; s64 Sx;
if (g_settings.gpu_widescreen_hack) switch (s_aspect_ratio)
{ {
const DisplayAspectRatio ar = g_settings.display_aspect_ratio; case DisplayAspectRatio::R16_9:
switch (ar) Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(4)) + s64(REGS.OFX));
{ break;
case DisplayAspectRatio::R16_9:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(4)) + s64(REGS.OFX));
break;
case DisplayAspectRatio::R16_10: case DisplayAspectRatio::R16_10:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(5)) / s64(6)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(5)) / s64(6)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R19_9: case DisplayAspectRatio::R19_9:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(12)) / s64(19)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(12)) / s64(19)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R20_9: case DisplayAspectRatio::R20_9:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(5)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(5)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R21_9: case DisplayAspectRatio::R21_9:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(9)) / s64(16)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(9)) / s64(16)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R32_9: case DisplayAspectRatio::R32_9:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(8)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(3)) / s64(8)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R8_7: case DisplayAspectRatio::R8_7:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R5_4: case DisplayAspectRatio::R5_4:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(16)) / s64(15)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(16)) / s64(15)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R3_2: case DisplayAspectRatio::R3_2:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(8)) / s64(9)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(8)) / s64(9)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R2_1: case DisplayAspectRatio::R2_1:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(2)) / s64(3)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(2)) / s64(3)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::R1_1: case DisplayAspectRatio::R1_1:
Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX)); Sx = ((((s64(result) * s64(REGS.IR1)) * s64(7)) / s64(6)) + s64(REGS.OFX));
break; break;
case DisplayAspectRatio::Auto: case DisplayAspectRatio::Custom:
case DisplayAspectRatio::R4_3: case DisplayAspectRatio::MatchWindow:
case DisplayAspectRatio::PAR1_1: Sx = ((((s64(result) * s64(REGS.IR1)) * s64(s_custom_aspect_ratio_numerator)) /
default: s64(s_custom_aspect_ratio_denominator)) +
Sx = (s64(result) * s64(REGS.IR1) + s64(REGS.OFX)); s64(REGS.OFX));
break; break;
}
} case DisplayAspectRatio::Auto:
else case DisplayAspectRatio::R4_3:
{ case DisplayAspectRatio::PAR1_1:
Sx = (s64(result) * s64(REGS.IR1) + s64(REGS.OFX)); default:
Sx = (s64(result) * s64(REGS.IR1) + s64(REGS.OFX));
break;
} }
const s64 Sy = s64(result) * s64(REGS.IR2) + s64(REGS.OFY); const s64 Sy = s64(result) * s64(REGS.IR2) + s64(REGS.OFY);
@ -713,70 +770,68 @@ static void RTPS(const s16 V[3], u8 shift, bool lm, bool last)
const float precise_h_div_sz = float(REGS.H) / precise_z; const float precise_h_div_sz = float(REGS.H) / precise_z;
const float fofx = float(REGS.OFX) / float(1 << 16); const float fofx = float(REGS.OFX) / float(1 << 16);
const float fofy = float(REGS.OFY) / float(1 << 16); const float fofy = float(REGS.OFY) / float(1 << 16);
float precise_x; float precise_x = precise_ir1 * precise_h_div_sz;
if (g_settings.gpu_widescreen_hack)
switch (s_aspect_ratio)
{ {
precise_x = precise_ir1 * precise_h_div_sz; case DisplayAspectRatio::R16_9:
const DisplayAspectRatio ar = g_settings.display_aspect_ratio; precise_x = (precise_x * 3.0f) / 4.0f;
switch (ar) break;
{
case DisplayAspectRatio::R16_9:
precise_x = (precise_x * 3.0f) / 4.0f;
break;
case DisplayAspectRatio::R16_10: case DisplayAspectRatio::R16_10:
precise_x = (precise_x * 5.0f) / 6.0f; precise_x = (precise_x * 5.0f) / 6.0f;
break; break;
case DisplayAspectRatio::R19_9: case DisplayAspectRatio::R19_9:
precise_x = (precise_x * 12.0f) / 19.0f; precise_x = (precise_x * 12.0f) / 19.0f;
break; break;
case DisplayAspectRatio::R20_9: case DisplayAspectRatio::R20_9:
precise_x = (precise_x * 3.0f) / 5.0f; precise_x = (precise_x * 3.0f) / 5.0f;
break; break;
case DisplayAspectRatio::R21_9: case DisplayAspectRatio::R21_9:
precise_x = (precise_x * 9.0f) / 16.0f; precise_x = (precise_x * 9.0f) / 16.0f;
break; break;
case DisplayAspectRatio::R32_9: case DisplayAspectRatio::R32_9:
precise_x = (precise_x * 3.0f) / 8.0f; precise_x = (precise_x * 3.0f) / 8.0f;
break; break;
case DisplayAspectRatio::R8_7: case DisplayAspectRatio::R8_7:
precise_x = (precise_x * 7.0f) / 6.0f; precise_x = (precise_x * 7.0f) / 6.0f;
break; break;
case DisplayAspectRatio::R5_4: case DisplayAspectRatio::R5_4:
precise_x = (precise_x * 16.0f) / 15.0f; precise_x = (precise_x * 16.0f) / 15.0f;
break; break;
case DisplayAspectRatio::R3_2: case DisplayAspectRatio::R3_2:
precise_x = (precise_x * 8.0f) / 9.0f; precise_x = (precise_x * 8.0f) / 9.0f;
break; break;
case DisplayAspectRatio::R2_1: case DisplayAspectRatio::R2_1:
precise_x = (precise_x * 2.0f) / 3.0f; precise_x = (precise_x * 2.0f) / 3.0f;
break; break;
case DisplayAspectRatio::R1_1: case DisplayAspectRatio::R1_1:
precise_x = (precise_x * 7.0f) / 6.0f; precise_x = (precise_x * 7.0f) / 6.0f;
break; break;
case DisplayAspectRatio::Auto: case DisplayAspectRatio::MatchWindow:
case DisplayAspectRatio::R4_3: case DisplayAspectRatio::Custom:
case DisplayAspectRatio::PAR1_1: precise_x = precise_x * s_custom_aspect_ratio_f;
default: break;
break;
} case DisplayAspectRatio::Auto:
precise_x += fofx; case DisplayAspectRatio::R4_3:
} case DisplayAspectRatio::PAR1_1:
else default:
{ break;
precise_x = fofx + (precise_ir1 * precise_h_div_sz);
} }
precise_x += fofx;
float precise_y = fofy + (precise_ir2 * precise_h_div_sz); float precise_y = fofy + (precise_ir2 * precise_h_div_sz);
precise_x = std::clamp<float>(precise_x, -1024.0f, 1023.0f); precise_x = std::clamp<float>(precise_x, -1024.0f, 1023.0f);

View File

@ -8,6 +8,7 @@ namespace GTE {
void Initialize(); void Initialize();
void Reset(); void Reset();
bool DoState(StateWrapper& sw); bool DoState(StateWrapper& sw);
void UpdateAspectRatio();
// control registers are offset by +32 // control registers are offset by +32
u32 ReadRegister(u32 index); u32 ReadRegister(u32 index);

View File

@ -533,6 +533,8 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
si.SetIntValue("Display", "LineEndOffset", 0); si.SetIntValue("Display", "LineEndOffset", 0);
si.SetStringValue("Display", "AspectRatio", si.SetStringValue("Display", "AspectRatio",
Settings::GetDisplayAspectRatioName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)); Settings::GetDisplayAspectRatioName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO));
si.SetIntValue("Display", "CustomAspectRatioNumerator", 4);
si.GetIntValue("Display", "CustomAspectRatioDenominator", 3);
si.SetBoolValue("Display", "Force4_3For24Bit", false); si.SetBoolValue("Display", "Force4_3For24Bit", false);
si.SetBoolValue("Display", "LinearFiltering", true); si.SetBoolValue("Display", "LinearFiltering", true);
si.SetBoolValue("Display", "IntegerScaling", false); si.SetBoolValue("Display", "IntegerScaling", false);
@ -803,6 +805,14 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
g_gpu->UpdateSettings(); g_gpu->UpdateSettings();
} }
if (g_settings.display_aspect_ratio != old_settings.display_aspect_ratio ||
(g_settings.display_aspect_ratio == DisplayAspectRatio::Custom &&
(g_settings.display_aspect_ratio_custom_numerator != old_settings.display_aspect_ratio_custom_numerator ||
g_settings.display_aspect_ratio_custom_denominator != old_settings.display_aspect_ratio_custom_denominator)))
{
GTE::UpdateAspectRatio();
}
if (g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable || if (g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable ||
(g_settings.gpu_pgxp_enable && (g_settings.gpu_pgxp_culling != old_settings.gpu_pgxp_culling || (g_settings.gpu_pgxp_enable && (g_settings.gpu_pgxp_culling != old_settings.gpu_pgxp_culling ||
g_settings.gpu_pgxp_cpu != old_settings.gpu_pgxp_cpu))) g_settings.gpu_pgxp_cpu != old_settings.gpu_pgxp_cpu)))
@ -899,6 +909,15 @@ void HostInterface::SetUserDirectoryToProgramDirectory()
m_user_directory = program_directory; m_user_directory = program_directory;
} }
void HostInterface::OnHostDisplayResized()
{
if (System::IsValid())
{
if (g_settings.display_aspect_ratio == DisplayAspectRatio::MatchWindow)
GTE::UpdateAspectRatio();
}
}
std::string HostInterface::GetUserDirectoryRelativePath(const char* format, ...) const std::string HostInterface::GetUserDirectoryRelativePath(const char* format, ...) const
{ {
std::va_list ap; std::va_list ap;

View File

@ -183,6 +183,9 @@ protected:
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates. /// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
virtual void SetMouseMode(bool relative, bool hide_cursor); virtual void SetMouseMode(bool relative, bool hide_cursor);
/// Call when host display size changes, use with "match display" aspect ratio setting.
virtual void OnHostDisplayResized();
/// Sets the user directory to the program directory, i.e. "portable mode". /// Sets the user directory to the program directory, i.e. "portable mode".
void SetUserDirectoryToProgramDirectory(); void SetUserDirectoryToProgramDirectory();

View File

@ -3,6 +3,7 @@
#include "common/file_system.h" #include "common/file_system.h"
#include "common/make_array.h" #include "common/make_array.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "host_display.h"
#include "host_interface.h" #include "host_interface.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -222,6 +223,10 @@ void Settings::Load(SettingsInterface& si)
ParseDisplayAspectRatio( ParseDisplayAspectRatio(
si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DEFAULT_DISPLAY_ASPECT_RATIO)).c_str()) si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DEFAULT_DISPLAY_ASPECT_RATIO)).c_str())
.value_or(DEFAULT_DISPLAY_ASPECT_RATIO); .value_or(DEFAULT_DISPLAY_ASPECT_RATIO);
display_aspect_ratio_custom_numerator = static_cast<u16>(
std::clamp<int>(si.GetIntValue("Display", "CustomAspectRatioNumerator", 4), 1, std::numeric_limits<u16>::max()));
display_aspect_ratio_custom_denominator = static_cast<u16>(
std::clamp<int>(si.GetIntValue("Display", "CustomAspectRatioDenominator", 3), 1, std::numeric_limits<u16>::max()));
display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false); display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false);
display_active_start_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveStartOffset", 0)); display_active_start_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveStartOffset", 0));
display_active_end_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveEndOffset", 0)); display_active_end_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveEndOffset", 0));
@ -395,6 +400,8 @@ void Settings::Save(SettingsInterface& si) const
si.SetIntValue("Display", "LineEndOffset", display_line_end_offset); si.SetIntValue("Display", "LineEndOffset", display_line_end_offset);
si.SetBoolValue("Display", "Force4_3For24Bit", display_force_4_3_for_24bit); si.SetBoolValue("Display", "Force4_3For24Bit", display_force_4_3_for_24bit);
si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio)); si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio));
si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator);
si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator);
si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering);
si.SetBoolValue("Display", "IntegerScaling", display_integer_scaling); si.SetBoolValue("Display", "IntegerScaling", display_integer_scaling);
si.SetBoolValue("Display", "Stretch", display_stretch); si.SetBoolValue("Display", "Stretch", display_stretch);
@ -767,12 +774,12 @@ const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode)
return s_display_crop_mode_display_names[static_cast<int>(crop_mode)]; return s_display_crop_mode_display_names[static_cast<int>(crop_mode)];
} }
static std::array<const char*, 14> s_display_aspect_ratio_names = { static std::array<const char*, 16> s_display_aspect_ratio_names = {
{TRANSLATABLE("DisplayAspectRatio", "Auto (Game Native)"), "4:3", "16:9", "16:10", "19:9", "20:9", "21:9", "32:9", {TRANSLATABLE("DisplayAspectRatio", "Auto (Game Native)"), "Auto (Match Window)", "Custom", "4:3", "16:9", "16:10",
"8:7", "5:4", "3:2", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}}; "19:9", "20:9", "21:9", "32:9", "8:7", "5:4", "3:2", "2:1 (VRAM 1:1)", "1:1", "PAR 1:1"}};
static constexpr std::array<float, 14> s_display_aspect_ratio_values = { static constexpr std::array<float, 16> s_display_aspect_ratio_values = {
{-1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 20.0f / 9.0f, 64.0f / 27.0f, 32.0f / 9.0f, {-1.0f, -1.0f, -1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 16.0f / 10.0f, 19.0f / 9.0f, 20.0f / 9.0f, 64.0f / 27.0f,
8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f, 2.0f / 1.0f, 1.0f, -1.0f}}; 32.0f / 9.0f, 8.0f / 7.0f, 5.0f / 4.0f, 3.0f / 2.0f, 2.0f / 1.0f, 1.0f, -1.0f}};
std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str) std::optional<DisplayAspectRatio> Settings::ParseDisplayAspectRatio(const char* str)
{ {
@ -793,9 +800,32 @@ const char* Settings::GetDisplayAspectRatioName(DisplayAspectRatio ar)
return s_display_aspect_ratio_names[static_cast<int>(ar)]; return s_display_aspect_ratio_names[static_cast<int>(ar)];
} }
float Settings::GetDisplayAspectRatioValue(DisplayAspectRatio ar) float Settings::GetDisplayAspectRatioValue() const
{ {
return s_display_aspect_ratio_values[static_cast<int>(ar)]; switch (display_aspect_ratio)
{
case DisplayAspectRatio::MatchWindow:
{
const HostDisplay* display = g_host_interface->GetDisplay();
if (!display)
return s_display_aspect_ratio_values[static_cast<int>(DEFAULT_DISPLAY_ASPECT_RATIO)];
const u32 width = display->GetWindowWidth();
const u32 height = display->GetWindowHeight() - display->GetDisplayTopMargin();
return static_cast<float>(width) / static_cast<float>(height);
}
case DisplayAspectRatio::Custom:
{
return static_cast<float>(display_aspect_ratio_custom_numerator) /
static_cast<float>(display_aspect_ratio_custom_denominator);
}
default:
{
return s_display_aspect_ratio_values[static_cast<int>(display_aspect_ratio)];
}
}
} }
static std::array<const char*, 3> s_audio_backend_names = {{ static std::array<const char*, 3> s_audio_backend_names = {{

View File

@ -127,6 +127,8 @@ struct Settings
bool gpu_pgxp_depth_buffer = false; bool gpu_pgxp_depth_buffer = false;
DisplayCropMode display_crop_mode = DisplayCropMode::None; DisplayCropMode display_crop_mode = DisplayCropMode::None;
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::Auto; DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::Auto;
u16 display_aspect_ratio_custom_numerator = 0;
u16 display_aspect_ratio_custom_denominator = 0;
s16 display_active_start_offset = 0; s16 display_active_start_offset = 0;
s16 display_active_end_offset = 0; s16 display_active_end_offset = 0;
s8 display_line_start_offset = 0; s8 display_line_start_offset = 0;
@ -256,6 +258,8 @@ struct Settings
return audio_output_muted ? 0 : (fast_forwarding ? audio_fast_forward_volume : audio_output_volume); return audio_output_muted ? 0 : (fast_forwarding ? audio_fast_forward_volume : audio_output_volume);
} }
float GetDisplayAspectRatioValue() const;
bool HasAnyPerGameMemoryCards() const; bool HasAnyPerGameMemoryCards() const;
static void CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator); static void CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator);
@ -316,7 +320,6 @@ struct Settings
static std::optional<DisplayAspectRatio> ParseDisplayAspectRatio(const char* str); static std::optional<DisplayAspectRatio> ParseDisplayAspectRatio(const char* str);
static const char* GetDisplayAspectRatioName(DisplayAspectRatio ar); static const char* GetDisplayAspectRatioName(DisplayAspectRatio ar);
static float GetDisplayAspectRatioValue(DisplayAspectRatio ar);
static std::optional<AudioBackend> ParseAudioBackend(const char* str); static std::optional<AudioBackend> ParseAudioBackend(const char* str);
static const char* GetAudioBackendName(AudioBackend backend); static const char* GetAudioBackendName(AudioBackend backend);

View File

@ -94,6 +94,8 @@ enum class DisplayCropMode : u8
enum class DisplayAspectRatio : u8 enum class DisplayAspectRatio : u8
{ {
Auto, Auto,
MatchWindow,
Custom,
R4_3, R4_3,
R16_9, R16_9,
R16_10, R16_10,

View File

@ -25,6 +25,10 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayAspectRatio, "Display", "AspectRatio", SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayAspectRatio, "Display", "AspectRatio",
&Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName, &Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName,
Settings::DEFAULT_DISPLAY_ASPECT_RATIO); Settings::DEFAULT_DISPLAY_ASPECT_RATIO);
SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.customAspectRatioNumerator, "Display",
"CustomAspectRatioNumerator", 1);
SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.customAspectRatioDenominator, "Display",
"CustomAspectRatioDenominator", 1);
SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayCropMode, "Display", "CropMode", SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.displayCropMode, "Display", "CropMode",
&Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName, &Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName,
Settings::DEFAULT_DISPLAY_CROP_MODE); Settings::DEFAULT_DISPLAY_CROP_MODE);
@ -59,10 +63,13 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
&DisplaySettingsWidget::onGPUAdapterIndexChanged); &DisplaySettingsWidget::onGPUAdapterIndexChanged);
connect(m_ui.fullscreenMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, connect(m_ui.fullscreenMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&DisplaySettingsWidget::onGPUFullscreenModeIndexChanged); &DisplaySettingsWidget::onGPUFullscreenModeIndexChanged);
connect(m_ui.displayAspectRatio, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&DisplaySettingsWidget::onAspectRatioChanged);
connect(m_ui.displayIntegerScaling, &QCheckBox::stateChanged, this, connect(m_ui.displayIntegerScaling, &QCheckBox::stateChanged, this,
&DisplaySettingsWidget::onIntegerFilteringChanged); &DisplaySettingsWidget::onIntegerFilteringChanged);
populateGPUAdaptersAndResolutions(); populateGPUAdaptersAndResolutions();
onIntegerFilteringChanged(); onIntegerFilteringChanged();
onAspectRatioChanged();
dialog->registerWidgetHelp( dialog->registerWidgetHelp(
m_ui.renderer, tr("Renderer"), m_ui.renderer, tr("Renderer"),
@ -283,3 +290,13 @@ void DisplaySettingsWidget::onIntegerFilteringChanged()
m_ui.displayLinearFiltering->setEnabled(!m_ui.displayIntegerScaling->isChecked()); m_ui.displayLinearFiltering->setEnabled(!m_ui.displayIntegerScaling->isChecked());
m_ui.displayStretch->setEnabled(!m_ui.displayIntegerScaling->isChecked()); m_ui.displayStretch->setEnabled(!m_ui.displayIntegerScaling->isChecked());
} }
void DisplaySettingsWidget::onAspectRatioChanged()
{
const bool is_custom =
static_cast<DisplayAspectRatio>(m_ui.displayAspectRatio->currentIndex()) == DisplayAspectRatio::Custom;
m_ui.customAspectRatioNumerator->setVisible(is_custom);
m_ui.customAspectRatioDenominator->setVisible(is_custom);
m_ui.customAspectRatioSeparator->setVisible(is_custom);
}

View File

@ -21,6 +21,7 @@ private Q_SLOTS:
void onGPUAdapterIndexChanged(); void onGPUAdapterIndexChanged();
void onGPUFullscreenModeIndexChanged(); void onGPUFullscreenModeIndexChanged();
void onIntegerFilteringChanged(); void onIntegerFilteringChanged();
void onAspectRatioChanged();
private: private:
void setupAdditionalUi(); void setupAdditionalUi();

View File

@ -111,7 +111,38 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="displayAspectRatio"/> <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0">
<item>
<widget class="QComboBox" name="displayAspectRatio"/>
</item>
<item>
<widget class="QSpinBox" name="customAspectRatioNumerator">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="customAspectRatioSeparator">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="customAspectRatioDenominator">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
</layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">

View File

@ -575,6 +575,8 @@ void CommonHostInterface::OnHostDisplayResized()
const u32 new_height = m_display ? m_display->GetWindowHeight() : 0; const u32 new_height = m_display ? m_display->GetWindowHeight() : 0;
const float new_scale = m_display ? m_display->GetWindowScale() : 1.0f; const float new_scale = m_display ? m_display->GetWindowScale() : 1.0f;
HostInterface::OnHostDisplayResized();
ImGui::GetIO().DisplaySize.x = static_cast<float>(new_width); ImGui::GetIO().DisplaySize.x = static_cast<float>(new_width);
ImGui::GetIO().DisplaySize.y = static_cast<float>(new_height); ImGui::GetIO().DisplaySize.y = static_cast<float>(new_height);

View File

@ -412,13 +412,13 @@ protected:
void UpdateSpeedLimiterState(); void UpdateSpeedLimiterState();
void RecreateSystem() override; void RecreateSystem() override;
void OnHostDisplayResized() override;
void ApplyGameSettings(bool display_osd_messages); void ApplyGameSettings(bool display_osd_messages);
void ApplyControllerCompatibilitySettings(u64 controller_mask, bool display_osd_messages); void ApplyControllerCompatibilitySettings(u64 controller_mask, bool display_osd_messages);
bool CreateHostDisplayResources(); bool CreateHostDisplayResources();
void ReleaseHostDisplayResources(); void ReleaseHostDisplayResources();
void OnHostDisplayResized();
virtual void DrawImGuiWindows(); virtual void DrawImGuiWindows();