ui: Make aspect ratio config independent, add autodetect

This commit is contained in:
Matt Borgerson 2023-06-17 23:32:18 -07:00 committed by mborgerson
parent 129c48dd6e
commit 0ee7502c23
11 changed files with 151 additions and 25 deletions

View File

@ -138,8 +138,12 @@ display:
default: true default: true
fit: fit:
type: enum type: enum
values: [center, scale, scale_16_9, scale_4_3, stretch] values: [center, scale, stretch]
default: scale default: scale
aspect_ratio:
type: enum
values: [native, auto, 4x3, 16x9]
default: auto
scale: scale:
type: integer type: integer
default: 1 default: 1

2
dtc

@ -1 +1 @@
Subproject commit 85e5d839847af54efab170f2b1331b2a6421e647 Subproject commit b6910bec11614980a21e46fbccc35934b671bd81

View File

@ -30,6 +30,7 @@
#include "hw/xbox/xbox_pci.h" #include "hw/xbox/xbox_pci.h"
#include "hw/xbox/acpi_xbox.h" #include "hw/xbox/acpi_xbox.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "ui/xemu-widescreen.h"
// #define DEBUG // #define DEBUG
#ifdef DEBUG #ifdef DEBUG
@ -44,6 +45,8 @@
#define XBOX_PM_GPIO_BASE 0xC0 #define XBOX_PM_GPIO_BASE 0xC0
#define XBOX_PM_GPIO_LEN 26 #define XBOX_PM_GPIO_LEN 26
#define XBOX_PM_GPIO_ASPECT_RATIO 0x16
static int field_pin; static int field_pin;
static uint64_t xbox_pm_gpio_read(void *opaque, hwaddr addr, unsigned width) static uint64_t xbox_pm_gpio_read(void *opaque, hwaddr addr, unsigned width)
@ -66,6 +69,12 @@ static void xbox_pm_gpio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned width) unsigned width)
{ {
XBOX_DPRINTF("pm gpio write [0x%llx] = 0x%llx\n", addr, val); XBOX_DPRINTF("pm gpio write [0x%llx] = 0x%llx\n", addr, val);
if (addr == XBOX_PM_GPIO_ASPECT_RATIO) {
xemu_set_widescreen(val == 5);
}
// FIXME: Add GPIO to VM state
} }
static const MemoryRegionOps xbox_pm_gpio_ops = { static const MemoryRegionOps xbox_pm_gpio_ops = {

2
meson

@ -1 +1 @@
Subproject commit 776acd2a805c9b42b4f0375150977df42130317f Subproject commit 3a9b285a55b91b53b2acda987192274352ecb5be

View File

@ -28,6 +28,7 @@ xemu_ss.add(files(
'xemu-data.c', 'xemu-data.c',
'xemu-snapshots.c', 'xemu-snapshots.c',
'xemu-thumbnail.cc', 'xemu-thumbnail.cc',
'xemu-widescreen.c',
)) ))
subdir('xui') subdir('xui')

37
ui/xemu-widescreen.c Normal file
View File

@ -0,0 +1,37 @@
/*
* xemu wide screen handler
*
* Copyright (c) 2023 Matt Borgerson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "xemu-widescreen.h"
static bool g_widescreen = false;
void xemu_set_widescreen(bool widescreen)
{
g_widescreen = widescreen;
}
bool xemu_get_widescreen(void)
{
return g_widescreen;
}

40
ui/xemu-widescreen.h Normal file
View File

@ -0,0 +1,40 @@
/*
* xemu wide screen handler
*
* Copyright (c) 2023 Matt Borgerson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XEMU_WIDESCREEN
#define XEMU_WIDESCREEN
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
void xemu_set_widescreen(bool widescreen);
bool xemu_get_widescreen(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -28,6 +28,7 @@
#include "ui/shader/xemu-logo-frag.h" #include "ui/shader/xemu-logo-frag.h"
#include "data/xemu_64x64.png.h" #include "data/xemu_64x64.png.h"
#include "notifications.hh" #include "notifications.hh"
#include "ui/xemu-widescreen.h"
Fbo *controller_fbo, Fbo *controller_fbo,
*logo_fbo; *logo_fbo;
@ -706,6 +707,21 @@ void RenderFramebuffer(GLint tex, int width, int height, bool flip, float scale[
} }
} }
float GetDisplayAspectRatio(int width, int height)
{
switch (g_config.display.ui.aspect_ratio) {
case CONFIG_DISPLAY_UI_ASPECT_RATIO_NATIVE:
return (float)width/(float)height;
case CONFIG_DISPLAY_UI_ASPECT_RATIO_16X9:
return 16.0f/9.0f;
case CONFIG_DISPLAY_UI_ASPECT_RATIO_4X3:
return 4.0f/3.0f;
case CONFIG_DISPLAY_UI_ASPECT_RATIO_AUTO:
default:
return xemu_get_widescreen() ? 16.0f/9.0f : 4.0f/3.0f;
}
}
void RenderFramebuffer(GLint tex, int width, int height, bool flip) void RenderFramebuffer(GLint tex, int width, int height, bool flip)
{ {
int tw, th; int tw, th;
@ -723,20 +739,11 @@ void RenderFramebuffer(GLint tex, int width, int height, bool flip)
scale[1] = 1.0; scale[1] = 1.0;
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_CENTER) { } else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_CENTER) {
// Centered // Centered
scale[0] = (float)tw/(float)width; float t_ratio = GetDisplayAspectRatio(tw, th);
scale[0] = t_ratio*(float)th/(float)width;
scale[1] = (float)th/(float)height; scale[1] = (float)th/(float)height;
} else { } else {
float t_ratio; float t_ratio = GetDisplayAspectRatio(tw, th);
if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_16_9) {
// Scale to fit window using a fixed 16:9 aspect ratio
t_ratio = 16.0f/9.0f;
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_4_3) {
t_ratio = 4.0f/3.0f;
} else {
// Scale to fit, preserving framebuffer aspect ratio
t_ratio = (float)tw/(float)th;
}
float w_ratio = (float)width/(float)height; float w_ratio = (float)width/(float)height;
if (w_ratio >= t_ratio) { if (w_ratio >= t_ratio) {
scale[0] = t_ratio/w_ratio; scale[0] = t_ratio/w_ratio;
@ -759,11 +766,7 @@ bool RenderFramebufferToPng(GLuint tex, bool flip, std::vector<uint8_t> &png, in
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_16_9) { width = height * GetDisplayAspectRatio(width, height);
width = height * (16.0f / 9.0f);
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_4_3) {
width = height * (4.0f / 3.0f);
}
if (!max_width) max_width = width; if (!max_width) max_width = width;
if (!max_height) max_height = height; if (!max_height) max_height = height;

View File

@ -340,10 +340,14 @@ void MainMenuDisplayView::Draw()
ChevronCombo("Display mode", &g_config.display.ui.fit, ChevronCombo("Display mode", &g_config.display.ui.fit,
"Center\0" "Center\0"
"Scale\0" "Scale\0"
"Scale (Widescreen 16:9)\0"
"Scale (4:3)\0"
"Stretch\0", "Stretch\0",
"Select how the framebuffer should fit or scale into the window"); "Select how the framebuffer should fit or scale into the window");
ChevronCombo("Aspect ratio", &g_config.display.ui.aspect_ratio,
"Native\0"
"Auto (Default)\0"
"4:3\0"
"16:9\0",
"Select the displayed aspect ratio");
} }
void MainMenuAudioView::Draw() void MainMenuAudioView::Draw()

View File

@ -191,11 +191,12 @@ void ShowMainMenu()
} }
ImGui::Combo("Display Mode", &g_config.display.ui.fit, ImGui::Combo("Display Mode", &g_config.display.ui.fit,
"Center\0Scale\0Scale (Widescreen 16:9)\0Scale " "Center\0Scale\0Stretch\0");
"(4:3)\0Stretch\0");
ImGui::SameLine(); ImGui::SameLine();
HelpMarker("Controls how the rendered content should be scaled " HelpMarker("Controls how the rendered content should be scaled "
"into the window"); "into the window");
ImGui::Combo("Aspect Ratio", &g_config.display.ui.aspect_ratio,
"Native\0Auto\0""4:3\0""16:9\0");
if (ImGui::MenuItem("Fullscreen", SHORTCUT_MENU_TEXT(Alt + F), if (ImGui::MenuItem("Fullscreen", SHORTCUT_MENU_TEXT(Alt + F),
xemu_is_fullscreen(), true)) { xemu_is_fullscreen(), true)) {
xemu_toggle_fullscreen(); xemu_toggle_fullscreen();

View File

@ -258,7 +258,7 @@ public:
bool DrawItems(PopupMenuItemDelegate &nav) override bool DrawItems(PopupMenuItemDelegate &nav) override
{ {
const char *values[] = { const char *values[] = {
"Center", "Scale", "Scale (Widescreen 16:9)", "Scale (4:3)", "Stretch" "Center", "Scale", "Stretch"
}; };
for (int i = 0; i < CONFIG_DISPLAY_UI_FIT__COUNT; i++) { for (int i = 0; i < CONFIG_DISPLAY_UI_FIT__COUNT; i++) {
@ -272,11 +272,34 @@ public:
} }
}; };
class AspectRatioPopupMenu : public virtual PopupMenu {
public:
bool DrawItems(PopupMenuItemDelegate &nav) override
{
const char *values[] = {
"Native",
"Auto (Default)",
"4:3",
"16:9"
};
for (int i = 0; i < CONFIG_DISPLAY_UI_ASPECT_RATIO__COUNT; i++) {
bool selected = g_config.display.ui.aspect_ratio == i;
if (m_focus && selected) ImGui::SetKeyboardFocusHere();
if (PopupMenuCheck(values[i], "", selected))
g_config.display.ui.aspect_ratio = i;
}
return false;
}
};
extern MainMenuScene g_main_menu; extern MainMenuScene g_main_menu;
class SettingsPopupMenu : public virtual PopupMenu { class SettingsPopupMenu : public virtual PopupMenu {
protected: protected:
DisplayModePopupMenu display_mode; DisplayModePopupMenu display_mode;
AspectRatioPopupMenu aspect_ratio;
public: public:
bool DrawItems(PopupMenuItemDelegate &nav) override bool DrawItems(PopupMenuItemDelegate &nav) override
@ -295,6 +318,10 @@ public:
nav.PushFocus(); nav.PushFocus();
nav.PushMenu(display_mode); nav.PushMenu(display_mode);
} }
if (PopupMenuSubmenuButton("Aspect Ratio", ICON_FA_EXPAND)) {
nav.PushFocus();
nav.PushMenu(aspect_ratio);
}
if (PopupMenuButton("Snapshots...", ICON_FA_CLOCK_ROTATE_LEFT)) { if (PopupMenuButton("Snapshots...", ICON_FA_CLOCK_ROTATE_LEFT)) {
nav.ClearMenuStack(); nav.ClearMenuStack();
g_scene_mgr.PushScene(g_main_menu); g_scene_mgr.PushScene(g_main_menu);