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:
Spidy123222 2023-06-29 10:12:51 -07:00 committed by Hugo Locurcio
parent a00820746f
commit aae8b2e096
No known key found for this signature in database
GPG Key ID: 39E8F8BE30B0A49C
7 changed files with 81 additions and 16 deletions

View File

@ -265,3 +265,15 @@ perf:
cache_shaders:
type: bool
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

View File

@ -31,11 +31,19 @@
#include "hw/irq.h"
#include "sysemu/kvm.h"
#ifdef XBOX
#include "ui/xemu-settings.h"
#endif
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
#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);
#else
return cpus_get_elapsed_ticks();

View File

@ -318,7 +318,7 @@ static void handle_keydown(SDL_Event *ev)
{
int win;
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_keysym = 0;
@ -1079,10 +1079,14 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
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;
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
int64_t sleep_acc = 0;

View File

@ -203,6 +203,14 @@ void CompatibilityReporter::Draw()
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::SetItemDefaultFocus();
@ -213,7 +221,10 @@ void CompatibilityReporter::Draw()
is_open = false;
}
}
if (g_config.perf.override_clockspeed) {
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
ImGui::End();
}

View File

@ -66,6 +66,30 @@ void MainMenuGeneralView::Draw()
Toggle("Cache shaders to disk", &g_config.perf.cache_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");
Toggle("Skip startup animation", &g_config.general.skip_boot_anim,
"Skip the full Xbox boot animation sequence");
@ -172,14 +196,14 @@ void MainMenuInputView::Draw()
driver = DRIVER_DUKE_DISPLAY_NAME;
else if (strcmp(driver, DRIVER_S) == 0)
driver = DRIVER_S_DISPLAY_NAME;
ImGui::SetNextItemWidth(-FLT_MIN);
if (ImGui::BeginCombo("###InputDrivers", driver,
ImGuiComboFlags_NoArrowButton)) {
const char *available_drivers[] = { DRIVER_DUKE, DRIVER_S };
const char *driver_display_names[] = {
DRIVER_DUKE_DISPLAY_NAME,
DRIVER_S_DISPLAY_NAME
const char *driver_display_names[] = {
DRIVER_DUKE_DISPLAY_NAME,
DRIVER_S_DISPLAY_NAME
};
bool is_selected = false;
int num_drivers = sizeof(driver_display_names) / sizeof(driver_display_names[0]);

View File

@ -22,6 +22,7 @@
#include "viewport-manager.hh"
#include "ui/xemu-os-utils.h"
#include "gl-helpers.hh"
#include <algorithm>
void Separator()
{
@ -222,8 +223,9 @@ bool Toggle(const char *str_id, bool *v, const char *description)
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);
ImGuiStyle &style = ImGui::GetStyle();
@ -238,6 +240,8 @@ void Slider(const char *str_id, float *v, const char *description)
GetWidgetTitleDescriptionHeight(str_id, description));
WidgetTitleDescription(str_id, description, p);
ImGui::PushID(str_id);
// XXX: Internal API
ImVec2 wpos = ImGui::GetCursorPos();
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_GamepadLStickLeft) ||
ImGui::IsKeyPressed(ImGuiKey_GamepadRStickLeft)) {
*v -= 0.05;
x -= increment / max;
}
if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) ||
ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight) ||
ImGui::IsKeyPressed(ImGuiKey_GamepadLStickRight) ||
ImGui::IsKeyPressed(ImGuiKey_GamepadRStickRight)) {
*v += 0.05;
x += increment / max;
}
if (
@ -286,15 +290,17 @@ void Slider(const char *str_id, float *v, const char *description)
if (ImGui::IsItemActive()) {
ImVec2 mouse = ImGui::GetMousePos();
*v = GetSliderValueForMousePos(mouse, slider_pos, slider_size);
x = GetSliderValueForMousePos(mouse, slider_pos, slider_size);
}
*v = fmax(0, fmin(*v, 1));
DrawSlider(*v, ImGui::IsItemHovered() || ImGui::IsItemActive(), slider_pos,
x = std::clamp(x, 0.f, 1.f);
*v = x * (max - min) + min;
DrawSlider(x, ImGui::IsItemHovered() || ImGui::IsItemActive(), slider_pos,
slider_size);
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::PopID();
ImGui::PopStyleColor();
}

View File

@ -34,7 +34,7 @@ float GetSliderValueForMousePos(ImVec2 mouse, ImVec2 pos, ImVec2 size);
void DrawSlider(float v, 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);
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 dir = false);
void DrawComboChevron();