diff --git a/engine/common/common.h b/engine/common/common.h index 36cdb234..447042fe 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -393,6 +393,11 @@ typedef struct host_parm_s // bug compatibility level, for very "special" games bugcomp_t bugcomp; + // measure time to first frame + double starttime; + + // count of sleeps can be inserted between frames + double pureframetime; } host_parm_t; extern host_parm_t host; diff --git a/engine/common/host.c b/engine/common/host.c index f7e91114..b129b92a 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -269,43 +269,35 @@ void Host_AbortCurrentFrame( void ) /* ================== -Host_CheckSleep +Host_CalcSleep ================== */ -void Host_CheckSleep( void ) +static int Host_CalcSleep( void ) { - int sleeptime = host_sleeptime->value; - #ifndef XASH_DEDICATED // never sleep in timedemo for benchmarking purposes // also don't sleep with vsync for less lag if( CL_IsTimeDemo( ) || CVAR_TO_BOOL( gl_vsync )) - return; + return 0; #endif if( Host_IsDedicated() ) { // let the dedicated server some sleep - Sys_Sleep( sleeptime ); + return host_sleeptime->value; } - else + else if( host.status == HOST_NOFOCUS ) { - if( host.status == HOST_NOFOCUS ) - { - if( SV_Active() && CL_IsInGame( )) - Sys_Sleep( sleeptime ); // listenserver - else Sys_Sleep( 20 ); // sleep 20 ms otherwise - } - else if( host.status == HOST_SLEEP ) - { - // completely sleep in minimized state - Sys_Sleep( 20 ); - } - else - { - Sys_Sleep( sleeptime ); - } + if( SV_Active() && CL_IsInGame( )) + return host_sleeptime->value; // listenserver + return 20; // sleep 20 ms otherwise } + else if( host.status == HOST_SLEEP ) + { + return 20; + } + + return host_sleeptime->value; } void Host_NewInstance( const char *name, const char *finalmsg ) @@ -631,27 +623,53 @@ Returns false if the time is too short to run a frame qboolean Host_FilterTime( float time ) { static double oldtime; - double fps; - double scale = sys_timescale.value; + double fps, scale = sys_timescale.value; host.realtime += time * scale; - fps = Host_CalcFPS( ); + fps = Host_CalcFPS(); // clamp the fps in multiplayer games if( fps != 0.0 ) { + static int sleeps; + double targetframetime; + int sleeptime = Host_CalcSleep(); + // limit fps to withing tolerable range fps = bound( MIN_FPS, fps, MAX_FPS ); - if( Host_IsDedicated() ) + if( Host_IsDedicated( )) + targetframetime = ( 1.0 / ( fps + 1.0 )); + else targetframetime = ( 1.0 / fps ); + + if(( host.realtime - oldtime ) < targetframetime * scale ) { - if(( host.realtime - oldtime ) < ( 1.0 / ( fps + 1.0 )) * scale) - return false; + if( sleeptime > 0 && sleeps > 0 ) + { + Sys_Sleep( sleeptime ); + sleeps--; + } + + return false; } - else + + if( sleeptime > 0 && sleeps <= 0 ) { - if(( host.realtime - oldtime ) < ( 1.0 / fps ) * scale ) - return false; + if( host.status == HOST_FRAME ) + { + // give few sleeps this frame with small margin + double targetsleeptime = targetframetime - host.pureframetime * 2; + + // don't sleep if we can't keep up with the framerate + if( targetsleeptime > 0 ) + sleeps = targetsleeptime / ( sleeptime * 0.001 ); + else sleeps = 0; + } + else + { + // always sleep at least once in minimized/nofocus state + sleeps = 1; + } } } @@ -674,19 +692,16 @@ Host_Frame */ void Host_Frame( float time ) { - static qboolean slept = false; + double t1, t2; // decide the simulation time if( !Host_FilterTime( time )) - { - if( !slept ) - { - Host_CheckSleep(); - slept = true; - } return; - } - slept = false; + + t1 = Sys_DoubleTime(); + + if( host.framecount == 0 ) + Con_DPrintf( "Time to first frame: %.3f seconds\n", t1 - host.starttime ); Host_InputFrame (); // input frame Host_ClientBegin (); // begin client @@ -695,6 +710,10 @@ void Host_Frame( float time ) Host_ClientFrame (); // client frame HTTP_Run(); // both server and client + t2 = Sys_DoubleTime(); + + host.pureframetime = t2 - t1; + host.framecount++; } @@ -1113,6 +1132,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa { static double oldtime, newtime; + host.starttime = Sys_DoubleTime(); + pChangeGame = func; // may be NULL Host_InitCommon( argc, argv, progname, bChangeGame );