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";
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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_) {
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue