From 7cc4a0f3a383f430a1e312fb77edfdd92b31dd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 May 2024 16:34:56 +0200 Subject: [PATCH] Add more accurate sleep function (well, not more accurate on Windows unfortunately) --- Common/GPU/OpenGL/GLRenderManager.h | 2 -- Common/TimeUtil.cpp | 31 +++++++++++++++++++++++++---- Common/TimeUtil.h | 9 +++++---- Core/FrameTiming.cpp | 2 +- Core/Util/PortManager.cpp | 2 +- UI/NativeApp.cpp | 6 +++--- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 6f7b843a4e..442b74bb2c 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -882,8 +882,6 @@ private: std::mutex syncMutex_; std::condition_variable syncCondVar_; - bool firstFrame_ = true; - bool vrRenderStarted_ = false; bool syncDone_ = false; GLDeleter deleter_; diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp index 5169f71afc..71800658d9 100644 --- a/Common/TimeUtil.cpp +++ b/Common/TimeUtil.cpp @@ -253,8 +253,12 @@ double Instant::ElapsedSeconds() const { #endif +#define SLEEP_LOG_ENABLED 0 + void sleep_ms(int ms, const char *reason) { - // INFO_LOG(Log::System, "Sleep %d ms: %s", ms, reason); +#if SLEEP_LOG_ENABLED + INFO_LOG(Log::System, "Sleep %d ms: %s", ms, reason); +#endif #ifdef _WIN32 Sleep(ms); #elif defined(HAVE_LIBNX) @@ -266,10 +270,29 @@ void sleep_ms(int ms, const char *reason) { #endif } -void sleep_precise(double seconds) { +void sleep_us(int us, const char *reason) { +#if SLEEP_LOG_ENABLED + INFO_LOG(Log::System, "Sleep %d us: %s", us, reason); +#endif +#ifdef _WIN32 + Sleep(us / 1000); +#elif defined(HAVE_LIBNX) + svcSleepThread(us * 1000); +#elif defined(__EMSCRIPTEN__) + emscripten_sleep(us / 1000); +#else + usleep(us); +#endif +} + +// This can be a little more expensive in some circumstances, so only use when necessary. +void sleep_precise(double seconds, const char *reason) { if (seconds <= 0.0) { return; } +#if SLEEP_LOG_ENABLED + INFO_LOG(Log::System, "Sleep precise %f s: %s", seconds, reason); +#endif #ifdef _WIN32 // Precise Windows sleep function from: https://github.com/blat-blatnik/Snippets/blob/main/precise_sleep.c // Described in: https://blog.bearcats.nl/perfect-sleep-function/ @@ -347,7 +370,7 @@ void GetCurrentTimeFormatted(char formattedTime[13]) { // We don't even bother synchronizing this, it's fine if threads stomp a bit. static GMRng g_sleepRandom; -void sleep_random(double minSeconds, double maxSeconds) { +void sleep_random(double minSeconds, double maxSeconds, const char *reason) { const double waitSeconds = minSeconds + (maxSeconds - minSeconds) * g_sleepRandom.F(); - sleep_precise(waitSeconds); + sleep_precise(waitSeconds, reason); } diff --git a/Common/TimeUtil.h b/Common/TimeUtil.h index caa44b8d73..3a4ba44afe 100644 --- a/Common/TimeUtil.h +++ b/Common/TimeUtil.h @@ -17,16 +17,17 @@ double from_time_raw_relative(uint64_t raw_time); // Seconds, Unix UTC time double time_now_unix_utc(); -// Sleep. Does not necessarily have millisecond granularity, especially on Windows. +// Sleep for milliseconds. Does not necessarily have millisecond granularity, especially on Windows. // Requires a "reason" since sleeping generally should be very sparingly used. This // can be logged if desired to figure out where we're wasting time. void sleep_ms(int ms, const char *reason); - +// Sleep for microseconds. Does not necessarily have microsecond granularity, especially on Windows. +void sleep_us(int us, const char *reason); // Precise sleep. Can consume a little bit of CPU on Windows at least. -void sleep_precise(double seconds); +void sleep_precise(double seconds, const char *reason); // Random sleep, used for debugging. -void sleep_random(double minSeconds, double maxSeconds); +void sleep_random(double minSeconds, double maxSeconds, const char *reason); // Yield. Signals that this thread is busy-waiting but wants to allow other hyperthreads to run. void yield(); diff --git a/Core/FrameTiming.cpp b/Core/FrameTiming.cpp index 731bee82ce..3bdbe4c157 100644 --- a/Core/FrameTiming.cpp +++ b/Core/FrameTiming.cpp @@ -39,7 +39,7 @@ FrameTiming g_frameTiming; void WaitUntil(double now, double timestamp, const char *reason) { #if 1 // Use precise timing. - sleep_precise(timestamp - now); + sleep_precise(timestamp - now, reason); #else #if PPSSPP_PLATFORM(WINDOWS) diff --git a/Core/Util/PortManager.cpp b/Core/Util/PortManager.cpp index db92446a22..0b963a9c09 100644 --- a/Core/Util/PortManager.cpp +++ b/Core/Util/PortManager.cpp @@ -477,7 +477,7 @@ int upnpService(const unsigned int timeout) { // Service Loop while (upnpServiceRunning) { // Sleep for 1ms for faster response if active, otherwise sleep longer (TODO: Improve on this). - sleep_ms(g_Config.bEnableUPnP ? 1 : 100, "upnp-poll"); + sleep_ms(g_Config.bEnableUPnP ? 1 : 500, "upnp-poll"); // Attempts to reconnect if not connected yet or got disconnected if (g_Config.bEnableUPnP && g_PortManager.GetInitState() == UPNP_INITSTATE_NONE) { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 10788b0b85..bf6ea41af6 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1251,9 +1251,9 @@ void NativeFrame(GraphicsContext *graphicsContext) { // Simple throttling to not burn the GPU in the menu. // TODO: This is only necessary in MAILBOX or IMMEDIATE presentation modes. double diffTime = time_now_d() - startTime; - int sleepTime = (int)(1000.0 / refreshRate) - (int)(diffTime * 1000.0); - if (sleepTime > 0) - sleep_ms(sleepTime, "fallback-throttle"); + int sleepTimeUs = (int)(1000000 * ((1.0 / refreshRate) - diffTime)); + if (sleepTimeUs > 0) + sleep_us(sleepTimeUs, "fallback-throttle"); } }