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

@ -161,11 +161,12 @@ const std::string kRecentlyPlayedTitlesFilename = "recent.toml";
const std::string kBaseTitle = "Xenia-canary";
EmulatorWindow::EmulatorWindow(Emulator* emulator,
ui::WindowedAppContext& app_context)
ui::WindowedAppContext& app_context,
uint32_t width, uint32_t height)
: emulator_(emulator),
app_context_(app_context),
window_listener_(*this),
window_(ui::Window::Create(app_context, kBaseTitle, 1280, 720)),
window_(ui::Window::Create(app_context, kBaseTitle, width, height)),
imgui_drawer_(
std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)),
display_config_game_config_load_callback_(
@ -190,10 +191,11 @@ EmulatorWindow::EmulatorWindow(Emulator* emulator,
}
std::unique_ptr<EmulatorWindow> EmulatorWindow::Create(
Emulator* emulator, ui::WindowedAppContext& app_context) {
Emulator* emulator, ui::WindowedAppContext& app_context, uint32_t width,
uint32_t height) {
assert_true(app_context.IsInUIThread());
std::unique_ptr<EmulatorWindow> emulator_window(
new EmulatorWindow(emulator, app_context));
new EmulatorWindow(emulator, app_context, width, height));
if (!emulator_window->Initialize()) {
return nullptr;
}

View File

@ -54,7 +54,8 @@ class EmulatorWindow {
virtual ~EmulatorWindow();
static std::unique_ptr<EmulatorWindow> Create(
Emulator* emulator, ui::WindowedAppContext& app_context);
Emulator* emulator, ui::WindowedAppContext& app_context, uint32_t width,
uint32_t height);
std::unique_ptr<xe::threading::Thread> Gamepad_HotKeys_Listener;
@ -183,7 +184,8 @@ class EmulatorWindow {
};
explicit EmulatorWindow(Emulator* emulator,
ui::WindowedAppContext& app_context);
ui::WindowedAppContext& app_context, uint32_t width,
uint32_t height);
bool Initialize();

View File

@ -103,6 +103,8 @@ DECLARE_bool(debug);
DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
DECLARE_bool(widescreen);
namespace xe {
namespace app {
@ -445,8 +447,17 @@ bool EmulatorApp::OnInitialize() {
emulator_ =
std::make_unique<Emulator>("", storage_root, content_root, cache_root);
// Determine window size based on user widescreen setting.
uint32_t window_w = 1280;
uint32_t window_h = 720;
if (!cvars::widescreen) {
window_w = 1024;
window_h = 768;
}
// Main emulator display window.
emulator_window_ = EmulatorWindow::Create(emulator_.get(), app_context());
emulator_window_ = EmulatorWindow::Create(emulator_.get(), app_context(),
window_w, window_h);
if (!emulator_window_) {
XELOGE("Failed to create the main emulator window");
return false;

View File

@ -2205,9 +2205,11 @@ void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
}
D3D12_RESOURCE_DESC swap_texture_desc = swap_texture_resource->GetDesc();
auto aspect = graphics_system_->GetScaledAspectRatio();
presenter->RefreshGuestOutput(
uint32_t(swap_texture_desc.Width), uint32_t(swap_texture_desc.Height),
1280, 720,
aspect.first, aspect.second,
[this, &swap_texture_srv_desc, frontbuffer_format, swap_texture_resource,
&swap_texture_desc](
ui::Presenter::GuestOutputRefreshContext& context) -> bool {

View File

@ -67,6 +67,9 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
kernel_state_ = kernel_state;
app_context_ = app_context;
scaled_aspect_x_ = 16;
scaled_aspect_y_ = 9;
if (provider_) {
// Safe if either the UI thread call or the presenter creation fails.
if (app_context_) {

View File

@ -86,6 +86,14 @@ class GraphicsSystem {
bool Save(ByteStream* stream);
bool Restore(ByteStream* stream);
std::pair<uint32_t, uint32_t> GetScaledAspectRatio() const {
return {scaled_aspect_x_, scaled_aspect_y_};
};
void SetScaledAspectRatio(uint32_t x, uint32_t y) {
scaled_aspect_x_ = x;
scaled_aspect_y_ = y;
};
protected:
GraphicsSystem();
@ -117,6 +125,9 @@ class GraphicsSystem {
bool paused_ = false;
uint32_t scaled_aspect_x_ = 0;
uint32_t scaled_aspect_y_ = 0;
private:
std::unique_ptr<ui::Presenter> presenter_;

View File

@ -1286,8 +1286,11 @@ void VulkanCommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
return;
}
auto aspect = graphics_system_->GetScaledAspectRatio();
presenter->RefreshGuestOutput(
frontbuffer_width_scaled, frontbuffer_height_scaled, 1280, 720,
frontbuffer_width_scaled, frontbuffer_height_scaled, aspect.first,
aspect.second,
[this, frontbuffer_width_scaled, frontbuffer_height_scaled,
frontbuffer_format, swap_texture_view](
ui::Presenter::GuestOutputRefreshContext& context) -> bool {

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,