Proper 4:3 support

This commit is contained in:
NicknineTheEagle
2024-06-28 21:27:44 +03:00
committed by Radosław Gliński
parent 49166f0bd1
commit c4e930ed4c
8 changed files with 105 additions and 12 deletions

View File

@@ -49,6 +49,12 @@ DEFINE_int32(
"Video");
DEFINE_bool(use_50Hz_mode, false, "Enables usage of PAL-50 mode.", "Video");
DEFINE_bool(interlaced, false, "Toggles interlaced mode.", "Video");
// TODO: This is stored in XConfig somewhere, probably in video flags.
DEFINE_bool(widescreen, true, "Toggles between 16:9 and 4:3 aspect ratio.",
"Video");
// BT.709 on modern monitors and TVs looks the closest to the Xbox 360 connected
// to an HDTV.
DEFINE_uint32(kernel_display_gamma_type, 2,
@@ -88,6 +94,51 @@ inline constexpr static float GetVideoRefreshRate() {
return cvars::use_50Hz_mode ? 50.0f : 60.0f;
}
inline constexpr static std::pair<uint16_t, uint16_t> GetDisplayAspectRatio() {
if (cvars::widescreen) {
return {16, 9};
}
return {4, 3};
}
static std::pair<uint32_t, uint32_t> CalculateScaledAspectRatio(uint32_t fb_x,
uint32_t fb_y) {
// Calculate the game's final aspect ratio as it would appear on a physical
// TV.
auto dar = GetDisplayAspectRatio();
uint32_t display_x = dar.first;
uint32_t display_y = dar.second;
auto res = GetInternalDisplayResolution();
uint32_t res_x = res.first;
uint32_t res_y = res.second;
uint32_t x_factor = std::gcd(fb_x, res_x);
res_x /= x_factor;
fb_x /= x_factor;
uint32_t y_factor = std::gcd(fb_y, res_y);
res_y /= y_factor;
fb_y /= y_factor;
display_x = display_x * res_x - display_x * (res_x - fb_x);
display_y *= res_x;
display_y = display_y * res_y - display_y * (res_y - fb_y);
display_x *= res_y;
uint32_t aspect_factor = std::gcd(display_x, display_y);
display_x /= aspect_factor;
display_y /= aspect_factor;
XELOGI(
"Hardware scaler: width ratio {}:{}, height ratio {}:{}, final aspect "
"ratio {}:{}",
fb_x, res_x, fb_y, res_y, display_x, display_y);
return {display_x, display_y};
}
namespace xe {
namespace kernel {
namespace xboxkrnl {
@@ -184,6 +235,7 @@ void VdGetCurrentDisplayInformation_entry(
display_info->display_width = (uint16_t)mode.display_width;
display_info->display_height = (uint16_t)mode.display_height;
display_info->display_refresh_rate = mode.refresh_rate;
display_info->display_interlaced = mode.is_interlaced;
display_info->actual_display_width = (uint16_t)mode.display_width;
}
DECLARE_XBOXKRNL_EXPORT1(VdGetCurrentDisplayInformation, kVideo, kStub);
@@ -196,9 +248,8 @@ void VdQueryVideoMode(X_VIDEO_MODE* video_mode) {
video_mode->display_width = display_res.first;
video_mode->display_height = display_res.second;
video_mode->is_interlaced = 0;
video_mode->is_widescreen =
((video_mode->display_width / 4) > (video_mode->display_height / 3));
video_mode->is_interlaced = cvars::interlaced;
video_mode->is_widescreen = cvars::widescreen;
video_mode->is_hi_def = video_mode->display_width >= 0x400;
video_mode->refresh_rate = GetVideoRefreshRate();
video_mode->video_standard = GetVideoStandard();
@@ -350,6 +401,14 @@ dword_result_t VdInitializeScalerCommandBuffer_entry(
for (size_t i = 0; i < dest_count; ++i) {
dest[i] = 0x80000000;
}
uint32_t fb_x = (scaled_output_wh >> 16) & 0xFFFF;
uint32_t fb_y = scaled_output_wh & 0xFFFF;
auto aspect = CalculateScaledAspectRatio(fb_x, fb_y);
auto graphics_system = kernel_state()->emulator()->graphics_system();
graphics_system->SetScaledAspectRatio(aspect.first, aspect.second);
return (uint32_t)dest_count;
}
DECLARE_XBOXKRNL_EXPORT2(VdInitializeScalerCommandBuffer, kVideo, kImplemented,