Avoid frame pacing issues with SDL_GetPowerInfo on linux

SDL_GetPowerInfo on linux asks upower through dbus for power
information, which can block DrawFPS in UI/DebugOverlay.cpp and in
turn the main thread. Run SDL_GetPowerInfo on another thread
instead to avoid the issue.
This commit is contained in:
Katharine Chui committed 2026-08-19 01:33:56 +02:00
1 parent ac9ef58f96
commit 435033e439
1 file changed
+44 -6
+44 -6
View File
@@ -116,6 +116,10 @@ struct WindowState {
}; };
static WindowState g_windowState; static WindowState g_windowState;
#if !PPSSPP_PLATFORM(MAC)
static int g_batteryPercent = 0;
#endif
#if PPSSPP_PLATFORM(MAC) #if PPSSPP_PLATFORM(MAC)
// These are from MacCameraHelper.mm. // These are from MacCameraHelper.mm.
@@ -1132,12 +1136,7 @@ int64_t System_GetPropertyInt(SystemProperty prop) {
// Let's keep using the old code on Mac for safety. Evaluate later if to be deleted. // Let's keep using the old code on Mac for safety. Evaluate later if to be deleted.
return Apple_GetCurrentBatteryCapacity(); return Apple_GetCurrentBatteryCapacity();
#else #else
{ return g_batteryPercent;
int seconds = 0;
int percentage = 0;
SDL_GetPowerInfo(&seconds, &percentage);
return percentage;
}
#endif #endif
default: default:
return -1; return -1;
@@ -2119,6 +2118,33 @@ int main(int argc, char *argv[]) {
} }
} }
#if !PPSSPP_PLATFORM(MAC)
// linux SDL_GetPowerInfo asks upower on dbus for power information by default, can cause DrawFPS() in DebugOverlay.cpp to block and affect frame pacing
bool stop_battery_poll_thread = false;
double last_battery_poll = 0;
SDL_Semaphore *battery_poll_thread_sema = SDL_CreateSemaphore(0); // c++20 and onwards has semaphore
std::thread battery_poll_thread([&battery_poll_thread_sema, &stop_battery_poll_thread] {
while (!stop_battery_poll_thread) {
SDL_WaitSemaphore(battery_poll_thread_sema);
SDL_GetPowerInfo(nullptr, &g_batteryPercent);
}
});
auto kick_battery_poll_thread = [&last_battery_poll, &battery_poll_thread_sema] {
if (!(g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT)) {
return;
}
double now = time_now_d();
if (now - last_battery_poll >= 5.0) {
last_battery_poll = now;
SDL_SignalSemaphore(battery_poll_thread_sema);
}
};
kick_battery_poll_thread();
#endif
const bool needsSeparateEmuThread = graphicsContext->NeedsSeparateEmuThread(); const bool needsSeparateEmuThread = graphicsContext->NeedsSeparateEmuThread();
if (!needsSeparateEmuThread) { if (!needsSeparateEmuThread) {
// Vulkan mode uses this. // Vulkan mode uses this.
@@ -2152,6 +2178,9 @@ int main(int argc, char *argv[]) {
UpdateTextFocus(window); UpdateTextFocus(window);
UpdateSDLCursor(); UpdateSDLCursor();
#if !PPSSPP_PLATFORM(MAC)
kick_battery_poll_thread();
#endif
inputTracker.MouseCaptureControl(window); inputTracker.MouseCaptureControl(window);
@@ -2183,6 +2212,9 @@ int main(int argc, char *argv[]) {
UpdateTextFocus(window); UpdateTextFocus(window);
UpdateSDLCursor(); UpdateSDLCursor();
#if !PPSSPP_PLATFORM(MAC)
kick_battery_poll_thread();
#endif
inputTracker.MouseCaptureControl(window); inputTracker.MouseCaptureControl(window);
@@ -2208,6 +2240,12 @@ int main(int argc, char *argv[]) {
EmuThread_Join(graphicsContext, emuThread); EmuThread_Join(graphicsContext, emuThread);
} }
#if !PPSSPP_PLATFORM(MAC)
stop_battery_poll_thread = true;
SDL_SignalSemaphore(battery_poll_thread_sema);
battery_poll_thread.join();
SDL_DestroySemaphore(battery_poll_thread_sema);
#endif
delete joystick; delete joystick;