Proper 4:3 support
This commit is contained in:
parent
49166f0bd1
commit
c4e930ed4c
|
@ -161,11 +161,12 @@ const std::string kRecentlyPlayedTitlesFilename = "recent.toml";
|
||||||
const std::string kBaseTitle = "Xenia-canary";
|
const std::string kBaseTitle = "Xenia-canary";
|
||||||
|
|
||||||
EmulatorWindow::EmulatorWindow(Emulator* emulator,
|
EmulatorWindow::EmulatorWindow(Emulator* emulator,
|
||||||
ui::WindowedAppContext& app_context)
|
ui::WindowedAppContext& app_context,
|
||||||
|
uint32_t width, uint32_t height)
|
||||||
: emulator_(emulator),
|
: emulator_(emulator),
|
||||||
app_context_(app_context),
|
app_context_(app_context),
|
||||||
window_listener_(*this),
|
window_listener_(*this),
|
||||||
window_(ui::Window::Create(app_context, kBaseTitle, 1280, 720)),
|
window_(ui::Window::Create(app_context, kBaseTitle, width, height)),
|
||||||
imgui_drawer_(
|
imgui_drawer_(
|
||||||
std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)),
|
std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)),
|
||||||
display_config_game_config_load_callback_(
|
display_config_game_config_load_callback_(
|
||||||
|
@ -190,10 +191,11 @@ EmulatorWindow::EmulatorWindow(Emulator* emulator,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<EmulatorWindow> EmulatorWindow::Create(
|
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());
|
assert_true(app_context.IsInUIThread());
|
||||||
std::unique_ptr<EmulatorWindow> emulator_window(
|
std::unique_ptr<EmulatorWindow> emulator_window(
|
||||||
new EmulatorWindow(emulator, app_context));
|
new EmulatorWindow(emulator, app_context, width, height));
|
||||||
if (!emulator_window->Initialize()) {
|
if (!emulator_window->Initialize()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ class EmulatorWindow {
|
||||||
virtual ~EmulatorWindow();
|
virtual ~EmulatorWindow();
|
||||||
|
|
||||||
static std::unique_ptr<EmulatorWindow> Create(
|
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;
|
std::unique_ptr<xe::threading::Thread> Gamepad_HotKeys_Listener;
|
||||||
|
|
||||||
|
@ -183,7 +184,8 @@ class EmulatorWindow {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit EmulatorWindow(Emulator* emulator,
|
explicit EmulatorWindow(Emulator* emulator,
|
||||||
ui::WindowedAppContext& app_context);
|
ui::WindowedAppContext& app_context, uint32_t width,
|
||||||
|
uint32_t height);
|
||||||
|
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,8 @@ DECLARE_bool(debug);
|
||||||
|
|
||||||
DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
|
DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
|
||||||
|
|
||||||
|
DECLARE_bool(widescreen);
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
|
@ -445,8 +447,17 @@ bool EmulatorApp::OnInitialize() {
|
||||||
emulator_ =
|
emulator_ =
|
||||||
std::make_unique<Emulator>("", storage_root, content_root, cache_root);
|
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.
|
// 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_) {
|
if (!emulator_window_) {
|
||||||
XELOGE("Failed to create the main emulator window");
|
XELOGE("Failed to create the main emulator window");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2205,9 +2205,11 @@ void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
|
||||||
}
|
}
|
||||||
D3D12_RESOURCE_DESC swap_texture_desc = swap_texture_resource->GetDesc();
|
D3D12_RESOURCE_DESC swap_texture_desc = swap_texture_resource->GetDesc();
|
||||||
|
|
||||||
|
auto aspect = graphics_system_->GetScaledAspectRatio();
|
||||||
|
|
||||||
presenter->RefreshGuestOutput(
|
presenter->RefreshGuestOutput(
|
||||||
uint32_t(swap_texture_desc.Width), uint32_t(swap_texture_desc.Height),
|
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,
|
[this, &swap_texture_srv_desc, frontbuffer_format, swap_texture_resource,
|
||||||
&swap_texture_desc](
|
&swap_texture_desc](
|
||||||
ui::Presenter::GuestOutputRefreshContext& context) -> bool {
|
ui::Presenter::GuestOutputRefreshContext& context) -> bool {
|
||||||
|
|
|
@ -67,6 +67,9 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
|
||||||
kernel_state_ = kernel_state;
|
kernel_state_ = kernel_state;
|
||||||
app_context_ = app_context;
|
app_context_ = app_context;
|
||||||
|
|
||||||
|
scaled_aspect_x_ = 16;
|
||||||
|
scaled_aspect_y_ = 9;
|
||||||
|
|
||||||
if (provider_) {
|
if (provider_) {
|
||||||
// Safe if either the UI thread call or the presenter creation fails.
|
// Safe if either the UI thread call or the presenter creation fails.
|
||||||
if (app_context_) {
|
if (app_context_) {
|
||||||
|
|
|
@ -86,6 +86,14 @@ class GraphicsSystem {
|
||||||
bool Save(ByteStream* stream);
|
bool Save(ByteStream* stream);
|
||||||
bool Restore(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:
|
protected:
|
||||||
GraphicsSystem();
|
GraphicsSystem();
|
||||||
|
|
||||||
|
@ -117,6 +125,9 @@ class GraphicsSystem {
|
||||||
|
|
||||||
bool paused_ = false;
|
bool paused_ = false;
|
||||||
|
|
||||||
|
uint32_t scaled_aspect_x_ = 0;
|
||||||
|
uint32_t scaled_aspect_y_ = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ui::Presenter> presenter_;
|
std::unique_ptr<ui::Presenter> presenter_;
|
||||||
|
|
||||||
|
|
|
@ -1286,8 +1286,11 @@ void VulkanCommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto aspect = graphics_system_->GetScaledAspectRatio();
|
||||||
|
|
||||||
presenter->RefreshGuestOutput(
|
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,
|
[this, frontbuffer_width_scaled, frontbuffer_height_scaled,
|
||||||
frontbuffer_format, swap_texture_view](
|
frontbuffer_format, swap_texture_view](
|
||||||
ui::Presenter::GuestOutputRefreshContext& context) -> bool {
|
ui::Presenter::GuestOutputRefreshContext& context) -> bool {
|
||||||
|
|
|
@ -49,6 +49,12 @@ DEFINE_int32(
|
||||||
"Video");
|
"Video");
|
||||||
|
|
||||||
DEFINE_bool(use_50Hz_mode, false, "Enables usage of PAL-50 mode.", "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
|
// BT.709 on modern monitors and TVs looks the closest to the Xbox 360 connected
|
||||||
// to an HDTV.
|
// to an HDTV.
|
||||||
DEFINE_uint32(kernel_display_gamma_type, 2,
|
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;
|
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 xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xboxkrnl {
|
namespace xboxkrnl {
|
||||||
|
@ -184,6 +235,7 @@ void VdGetCurrentDisplayInformation_entry(
|
||||||
display_info->display_width = (uint16_t)mode.display_width;
|
display_info->display_width = (uint16_t)mode.display_width;
|
||||||
display_info->display_height = (uint16_t)mode.display_height;
|
display_info->display_height = (uint16_t)mode.display_height;
|
||||||
display_info->display_refresh_rate = mode.refresh_rate;
|
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;
|
display_info->actual_display_width = (uint16_t)mode.display_width;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(VdGetCurrentDisplayInformation, kVideo, kStub);
|
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_width = display_res.first;
|
||||||
video_mode->display_height = display_res.second;
|
video_mode->display_height = display_res.second;
|
||||||
video_mode->is_interlaced = 0;
|
video_mode->is_interlaced = cvars::interlaced;
|
||||||
video_mode->is_widescreen =
|
video_mode->is_widescreen = cvars::widescreen;
|
||||||
((video_mode->display_width / 4) > (video_mode->display_height / 3));
|
|
||||||
video_mode->is_hi_def = video_mode->display_width >= 0x400;
|
video_mode->is_hi_def = video_mode->display_width >= 0x400;
|
||||||
video_mode->refresh_rate = GetVideoRefreshRate();
|
video_mode->refresh_rate = GetVideoRefreshRate();
|
||||||
video_mode->video_standard = GetVideoStandard();
|
video_mode->video_standard = GetVideoStandard();
|
||||||
|
@ -350,6 +401,14 @@ dword_result_t VdInitializeScalerCommandBuffer_entry(
|
||||||
for (size_t i = 0; i < dest_count; ++i) {
|
for (size_t i = 0; i < dest_count; ++i) {
|
||||||
dest[i] = 0x80000000;
|
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;
|
return (uint32_t)dest_count;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(VdInitializeScalerCommandBuffer, kVideo, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT2(VdInitializeScalerCommandBuffer, kVideo, kImplemented,
|
||||||
|
|
Loading…
Reference in New Issue