From 052ea6a8bd39d9570e69bb14558a08f92cd95518 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Tue, 11 Feb 2025 22:57:37 +0300 Subject: [PATCH] engine: platform: introduce for Platform_NanoSleep, to be used for better sleeping in between frames for lowering CPU usage --- engine/common/host.c | 6 +++--- engine/common/net_ws.c | 2 +- engine/platform/platform.h | 35 +++++++++++++++++++++++++++++++++ engine/platform/win32/sys_win.c | 29 +++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/engine/common/host.c b/engine/common/host.c index b30063ff..2f2ada49 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -698,17 +698,17 @@ static qboolean Host_Autosleep( double dt, double scale ) static double timewindow; // allocate a time window for sleeps static int counter; // for debug static double realsleeptime; - const double sleeptime = sleep * 0.001; + const double sleeptime = sleep * 0.000001; if( dt < targetframetime * scale ) { // if we have allocated time window, try to sleep if( timewindow > realsleeptime ) { - // Platform_Sleep isn't guaranteed to sleep an exact amount of milliseconds + // Platform_Sleep isn't guaranteed to sleep an exact amount of microseconds // so we measure the real sleep time and use it to decrease the window double t1 = Sys_DoubleTime(), t2; - Platform_Sleep( sleep ); // in msec! + Platform_NanoSleep( sleep * 1000 ); // in usec! t2 = Sys_DoubleTime(); realsleeptime = t2 - t1; diff --git a/engine/common/net_ws.c b/engine/common/net_ws.c index db74a595..52ffccf5 100644 --- a/engine/common/net_ws.c +++ b/engine/common/net_ws.c @@ -1512,7 +1512,7 @@ static int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, size_t total_sent += size; len -= size; packet_number++; - Platform_Sleep( 1 ); + Platform_NanoSleep( 100 * 1000 ); } return total_sent; diff --git a/engine/platform/platform.h b/engine/platform/platform.h index 5bc6b35a..0caa313b 100644 --- a/engine/platform/platform.h +++ b/engine/platform/platform.h @@ -70,6 +70,8 @@ void Android_Shutdown( void ); #endif #if XASH_WIN32 +void Win32_Init( void ); +void Win32_Shutdown( void ); void Wcon_CreateConsole( qboolean con_showalways ); void Wcon_DestroyConsole( void ); void Wcon_InitConsoleCommands( void ); @@ -124,6 +126,7 @@ static inline void Platform_Init( qboolean con_showalways, const char *basedir ) #elif XASH_DOS DOS_Init( ); #elif XASH_WIN32 + Win32_Init( ); Wcon_CreateConsole( con_showalways ); #elif XASH_LINUX Linux_Init( ); @@ -140,6 +143,7 @@ static inline void Platform_Shutdown( void ) DOS_Shutdown( ); #elif XASH_WIN32 Wcon_DestroyConsole( ); + Win32_Shutdown( ); #elif XASH_LINUX Linux_Shutdown( ); #endif @@ -178,6 +182,37 @@ static inline void Platform_Sleep( int msec ) #endif } +static inline qboolean Platform_NanoSleep( int nsec ) +{ + // SDL2 doesn't have nanosleep, so use low-level functions here + // When this code will be ported to SDL3, use SDL_DelayNS +#if XASH_POSIX + struct timespec ts = { + .tv_sec = 0, + .tv_nsec = nsec, // just don't put large numbers here + }; + return nanosleep( &ts, NULL ) == 0; +#elif XASH_WIN32 + extern HANDLE g_waitable_timer; + const LARGE_INTEGER ts = { -nsec }; + + if( !g_waitable_timer ) + return false; + + if( !SetWaitableTimer( g_waitable_timer, &ts, 0, NULL, NULL, FALSE )) + { + CloseHandle( g_waitable_timer ); + g_waitable_timer = 0; + return false; + } + + if( WaitForSingleObject( g_waitable_timer, 1000 ) != WAIT_OBJECT_0 ) + return false; + + return true; +#endif +} + #if XASH_WIN32 || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX || XASH_APPLE void Sys_SetupCrashHandler( const char *argv0 ); void Sys_RestoreCrashHandler( void ); diff --git a/engine/platform/win32/sys_win.c b/engine/platform/win32/sys_win.c index 41ea86c5..6f1dd547 100644 --- a/engine/platform/win32/sys_win.c +++ b/engine/platform/win32/sys_win.c @@ -18,6 +18,8 @@ GNU General Public License for more details. #include "server.h" #include +HANDLE g_waitable_timer; + #if XASH_TIMER == TIMER_WIN32 double Platform_DoubleTime( void ) { @@ -36,6 +38,33 @@ double Platform_DoubleTime( void ) } #endif // XASH_TIMER == TIMER_WIN32 +void Win32_Init( void ) +{ + HMODULE hModule = LoadLibrary( "kernel32.dll" ); + + if( hModule ) + { + HANDLE ( __stdcall *pfnCreateWaitableTimerExW)( LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess ); + + if(( pfnCreateWaitableTimerExW = GetProcAddress( hModule, "CreateWaitableTimerExW" ))) + { + // CREATE_WAITABLE_TIMER_MANUAL_RESET | CREATE_WAITABLE_TIMER_HIGH_RESOLUTION + g_waitable_timer = pfnCreateWaitableTimerExW( NULL, NULL, 0x1 | 0x2, 0 ); + } + + FreeLibrary( "kernel32.dll" ); + } + + if( !g_waitable_timer ) + g_waitable_timer = CreateWaitableTimer( NULL, TRUE, NULL ); +} + +void Win32_Shutdown( void ) +{ + if( g_waitable_timer ) + CloseHandle( g_waitable_timer ); +} + qboolean Platform_DebuggerPresent( void ) { return IsDebuggerPresent();