mirror of https://github.com/xemu-project/xemu.git
UX: Add CPU overclock and display rate override settings
These settings can be used to improve framerate or set a new framerate limit (different from the typical 30/60 FPS). Many games work well with this, but using overrides will break games that are not designed around FPS-independent physics. Therefore, submitting compatibility reports is disabled if either of the overrides are active. Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
parent
a00820746f
commit
aae8b2e096
|
@ -265,3 +265,15 @@ perf:
|
||||||
cache_shaders:
|
cache_shaders:
|
||||||
type: bool
|
type: bool
|
||||||
default: true
|
default: true
|
||||||
|
override_clockspeed:
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
cpu_clockspeed_scale:
|
||||||
|
type: number
|
||||||
|
default: 1
|
||||||
|
override_display_rate:
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
display_rate_scale:
|
||||||
|
type: number
|
||||||
|
default: 1
|
||||||
|
|
|
@ -31,11 +31,19 @@
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
|
||||||
|
#ifdef XBOX
|
||||||
|
#include "ui/xemu-settings.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* TSC handling */
|
/* TSC handling */
|
||||||
uint64_t cpu_get_tsc(CPUX86State *env)
|
uint64_t cpu_get_tsc(CPUX86State *env)
|
||||||
{
|
{
|
||||||
#ifdef XBOX
|
#ifdef XBOX
|
||||||
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 733333333,
|
float clockspeed_scale = 1.0f;
|
||||||
|
if (g_config.perf.override_clockspeed) {
|
||||||
|
clockspeed_scale = g_config.perf.cpu_clockspeed_scale;
|
||||||
|
}
|
||||||
|
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 733333333 * clockspeed_scale,
|
||||||
NANOSECONDS_PER_SECOND);
|
NANOSECONDS_PER_SECOND);
|
||||||
#else
|
#else
|
||||||
return cpus_get_elapsed_ticks();
|
return cpus_get_elapsed_ticks();
|
||||||
|
|
10
ui/xemu.c
10
ui/xemu.c
|
@ -318,7 +318,7 @@ static void handle_keydown(SDL_Event *ev)
|
||||||
{
|
{
|
||||||
int win;
|
int win;
|
||||||
struct sdl2_console *scon = get_scon_from_window(ev->key.windowID);
|
struct sdl2_console *scon = get_scon_from_window(ev->key.windowID);
|
||||||
if (scon == NULL) return;
|
if (scon == NULL) return;
|
||||||
int gui_key_modifier_pressed = get_mod_state();
|
int gui_key_modifier_pressed = get_mod_state();
|
||||||
int gui_keysym = 0;
|
int gui_keysym = 0;
|
||||||
|
|
||||||
|
@ -1079,10 +1079,14 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
|
||||||
qemu_mutex_unlock_main_loop();
|
qemu_mutex_unlock_main_loop();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Throttle to make sure swaps happen at 60Hz
|
* Throttle to make sure swaps happen at 60 Hz (divided by the display rate scale if overridden)
|
||||||
*/
|
*/
|
||||||
static int64_t last_update = 0;
|
static int64_t last_update = 0;
|
||||||
int64_t deadline = last_update + 16666666;
|
float display_rate_scale = 1.0f;
|
||||||
|
if (g_config.perf.override_display_rate) {
|
||||||
|
display_rate_scale /= g_config.perf.display_rate_scale;
|
||||||
|
}
|
||||||
|
int64_t deadline = last_update + 16666666 * display_rate_scale;
|
||||||
|
|
||||||
#ifdef DEBUG_XEMU_C
|
#ifdef DEBUG_XEMU_C
|
||||||
int64_t sleep_acc = 0;
|
int64_t sleep_acc = 0;
|
||||||
|
|
|
@ -203,6 +203,14 @@ void CompatibilityReporter::Draw()
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_config.perf.override_clockspeed || g_config.perf.override_display_rate) {
|
||||||
|
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
|
||||||
|
|
||||||
|
ImGui::Text("Reports cannot be made while using overridden CPU clock speed or display rate");
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth()-(120+10)*g_viewport_mgr.m_scale);
|
ImGui::SetCursorPosX(ImGui::GetWindowWidth()-(120+10)*g_viewport_mgr.m_scale);
|
||||||
|
|
||||||
ImGui::SetItemDefaultFocus();
|
ImGui::SetItemDefaultFocus();
|
||||||
|
@ -213,7 +221,10 @@ void CompatibilityReporter::Draw()
|
||||||
is_open = false;
|
is_open = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (g_config.perf.override_clockspeed) {
|
||||||
|
ImGui::PopItemFlag();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,30 @@ void MainMenuGeneralView::Draw()
|
||||||
Toggle("Cache shaders to disk", &g_config.perf.cache_shaders,
|
Toggle("Cache shaders to disk", &g_config.perf.cache_shaders,
|
||||||
"Reduce stutter in games by caching previously generated shaders");
|
"Reduce stutter in games by caching previously generated shaders");
|
||||||
|
|
||||||
|
SectionTitle("Tweaks");
|
||||||
|
Toggle("Emulated CPU clock override", &g_config.perf.override_clockspeed,
|
||||||
|
"Override default CPU clock speed (can break games)");
|
||||||
|
|
||||||
|
char cpu_clock_buf[32];
|
||||||
|
snprintf(cpu_clock_buf, sizeof(cpu_clock_buf), "Clock speed: %d%% (%.2f MHz)", (int)(g_config.perf.cpu_clockspeed_scale * 100), (733333333 * g_config.perf.cpu_clockspeed_scale) / 1000000);
|
||||||
|
Slider("Virtual CPU clock", &g_config.perf.cpu_clockspeed_scale, cpu_clock_buf, 0.25f, 4.f, 0.01f);
|
||||||
|
|
||||||
|
if (fabs(g_config.perf.cpu_clockspeed_scale - 1.f) <= 0.0099f) {
|
||||||
|
g_config.perf.cpu_clockspeed_scale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle("Display rate override", &g_config.perf.override_display_rate,
|
||||||
|
"Override default presentation frame rate (can break games)");
|
||||||
|
|
||||||
|
char display_rate_buf[35];
|
||||||
|
snprintf(display_rate_buf, sizeof(display_rate_buf), "Display rate: %d%% (%d / %d FPS)", (int)(g_config.perf.display_rate_scale * 100), (int)(30 * g_config.perf.display_rate_scale), (int)(60 * g_config.perf.display_rate_scale));
|
||||||
|
// Set slider increment so that 60 FPS games can be adjusted at a per-FPS level in terms of precision
|
||||||
|
Slider("Display rate", &g_config.perf.display_rate_scale, display_rate_buf, 0.3333333f, 4.f, 0.0166667f);
|
||||||
|
|
||||||
|
if (fabs(g_config.perf.display_rate_scale - 1.f) <= 0.0099f) {
|
||||||
|
g_config.perf.display_rate_scale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
SectionTitle("Miscellaneous");
|
SectionTitle("Miscellaneous");
|
||||||
Toggle("Skip startup animation", &g_config.general.skip_boot_anim,
|
Toggle("Skip startup animation", &g_config.general.skip_boot_anim,
|
||||||
"Skip the full Xbox boot animation sequence");
|
"Skip the full Xbox boot animation sequence");
|
||||||
|
@ -172,14 +196,14 @@ void MainMenuInputView::Draw()
|
||||||
driver = DRIVER_DUKE_DISPLAY_NAME;
|
driver = DRIVER_DUKE_DISPLAY_NAME;
|
||||||
else if (strcmp(driver, DRIVER_S) == 0)
|
else if (strcmp(driver, DRIVER_S) == 0)
|
||||||
driver = DRIVER_S_DISPLAY_NAME;
|
driver = DRIVER_S_DISPLAY_NAME;
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||||
if (ImGui::BeginCombo("###InputDrivers", driver,
|
if (ImGui::BeginCombo("###InputDrivers", driver,
|
||||||
ImGuiComboFlags_NoArrowButton)) {
|
ImGuiComboFlags_NoArrowButton)) {
|
||||||
const char *available_drivers[] = { DRIVER_DUKE, DRIVER_S };
|
const char *available_drivers[] = { DRIVER_DUKE, DRIVER_S };
|
||||||
const char *driver_display_names[] = {
|
const char *driver_display_names[] = {
|
||||||
DRIVER_DUKE_DISPLAY_NAME,
|
DRIVER_DUKE_DISPLAY_NAME,
|
||||||
DRIVER_S_DISPLAY_NAME
|
DRIVER_S_DISPLAY_NAME
|
||||||
};
|
};
|
||||||
bool is_selected = false;
|
bool is_selected = false;
|
||||||
int num_drivers = sizeof(driver_display_names) / sizeof(driver_display_names[0]);
|
int num_drivers = sizeof(driver_display_names) / sizeof(driver_display_names[0]);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "viewport-manager.hh"
|
#include "viewport-manager.hh"
|
||||||
#include "ui/xemu-os-utils.h"
|
#include "ui/xemu-os-utils.h"
|
||||||
#include "gl-helpers.hh"
|
#include "gl-helpers.hh"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
void Separator()
|
void Separator()
|
||||||
{
|
{
|
||||||
|
@ -222,8 +223,9 @@ bool Toggle(const char *str_id, bool *v, const char *description)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slider(const char *str_id, float *v, const char *description)
|
void Slider(const char *str_id, float *v, const char *description, float min, float max, float increment)
|
||||||
{
|
{
|
||||||
|
float x = (*v - min) / (max - min);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32_BLACK_TRANS);
|
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32_BLACK_TRANS);
|
||||||
|
|
||||||
ImGuiStyle &style = ImGui::GetStyle();
|
ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
@ -238,6 +240,8 @@ void Slider(const char *str_id, float *v, const char *description)
|
||||||
GetWidgetTitleDescriptionHeight(str_id, description));
|
GetWidgetTitleDescriptionHeight(str_id, description));
|
||||||
WidgetTitleDescription(str_id, description, p);
|
WidgetTitleDescription(str_id, description, p);
|
||||||
|
|
||||||
|
ImGui::PushID(str_id);
|
||||||
|
|
||||||
// XXX: Internal API
|
// XXX: Internal API
|
||||||
ImVec2 wpos = ImGui::GetCursorPos();
|
ImVec2 wpos = ImGui::GetCursorPos();
|
||||||
ImRect bb(p, ImVec2(p.x + size.x, p.y + size.y));
|
ImRect bb(p, ImVec2(p.x + size.x, p.y + size.y));
|
||||||
|
@ -261,13 +265,13 @@ void Slider(const char *str_id, float *v, const char *description)
|
||||||
ImGui::IsKeyPressed(ImGuiKey_GamepadDpadLeft) ||
|
ImGui::IsKeyPressed(ImGuiKey_GamepadDpadLeft) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_GamepadLStickLeft) ||
|
ImGui::IsKeyPressed(ImGuiKey_GamepadLStickLeft) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_GamepadRStickLeft)) {
|
ImGui::IsKeyPressed(ImGuiKey_GamepadRStickLeft)) {
|
||||||
*v -= 0.05;
|
x -= increment / max;
|
||||||
}
|
}
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) ||
|
if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight) ||
|
ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_GamepadLStickRight) ||
|
ImGui::IsKeyPressed(ImGuiKey_GamepadLStickRight) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_GamepadRStickRight)) {
|
ImGui::IsKeyPressed(ImGuiKey_GamepadRStickRight)) {
|
||||||
*v += 0.05;
|
x += increment / max;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -286,15 +290,17 @@ void Slider(const char *str_id, float *v, const char *description)
|
||||||
|
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
ImVec2 mouse = ImGui::GetMousePos();
|
ImVec2 mouse = ImGui::GetMousePos();
|
||||||
*v = GetSliderValueForMousePos(mouse, slider_pos, slider_size);
|
x = GetSliderValueForMousePos(mouse, slider_pos, slider_size);
|
||||||
}
|
}
|
||||||
*v = fmax(0, fmin(*v, 1));
|
x = std::clamp(x, 0.f, 1.f);
|
||||||
DrawSlider(*v, ImGui::IsItemHovered() || ImGui::IsItemActive(), slider_pos,
|
*v = x * (max - min) + min;
|
||||||
|
DrawSlider(x, ImGui::IsItemHovered() || ImGui::IsItemActive(), slider_pos,
|
||||||
slider_size);
|
slider_size);
|
||||||
|
|
||||||
ImVec2 slider_max = ImVec2(slider_pos.x + slider_size.x, slider_pos.y + slider_size.y);
|
ImVec2 slider_max = ImVec2(slider_pos.x + slider_size.x, slider_pos.y + slider_size.y);
|
||||||
ImGui::RenderNavHighlight(ImRect(slider_pos, slider_max), window->GetID("###slider"));
|
ImGui::RenderNavHighlight(ImRect(slider_pos, slider_max), window->GetID("###slider"));
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ float GetSliderValueForMousePos(ImVec2 mouse, ImVec2 pos, ImVec2 size);
|
||||||
void DrawSlider(float v, bool hovered, ImVec2 pos, ImVec2 size);
|
void DrawSlider(float v, bool hovered, ImVec2 pos, ImVec2 size);
|
||||||
void DrawToggle(bool enabled, bool hovered, ImVec2 pos, ImVec2 size);
|
void DrawToggle(bool enabled, bool hovered, ImVec2 pos, ImVec2 size);
|
||||||
bool Toggle(const char *str_id, bool *v, const char *description = nullptr);
|
bool Toggle(const char *str_id, bool *v, const char *description = nullptr);
|
||||||
void Slider(const char *str_id, float *v, const char *description = nullptr);
|
void Slider(const char *str_id, float *v, const char *description = nullptr, float min = 0, float max = 1, float increment = 0.05);
|
||||||
bool FilePicker(const char *str_id, const char **buf, const char *filters,
|
bool FilePicker(const char *str_id, const char **buf, const char *filters,
|
||||||
bool dir = false);
|
bool dir = false);
|
||||||
void DrawComboChevron();
|
void DrawComboChevron();
|
||||||
|
|
Loading…
Reference in New Issue