From 0dd49c45fd996d02cac11e9a9a0865db3239f21d Mon Sep 17 00:00:00 2001 From: cloudwalk Date: Sat, 18 Jul 2020 19:45:08 +0000 Subject: [PATCH] client: Implement CL_Frame. Move client cvars out of host to cl_main The client now performs its frame in its own side of the engine. This will make client/server separation easier later on. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12837 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ client.h | 2 + host.c | 168 +--------------------------------------------------- 3 files changed, 179 insertions(+), 165 deletions(-) diff --git a/cl_main.c b/cl_main.c index 7dc196eb..0e73b66d 100644 --- a/cl_main.c +++ b/cl_main.c @@ -95,6 +95,18 @@ cvar_t cl_deathnoviewmodel = {CVAR_CLIENT, "cl_deathnoviewmodel", "1", "hides gu cvar_t cl_locs_enable = {CVAR_CLIENT | CVAR_SAVE, "locs_enable", "1", "enables replacement of certain % codes in chat messages: %l (location), %d (last death location), %h (health), %a (armor), %x (rockets), %c (cells), %r (rocket launcher status), %p (powerup status), %w (weapon status), %t (current time in level)"}; cvar_t cl_locs_show = {CVAR_CLIENT, "locs_show", "0", "shows defined locations for editing purposes"}; +cvar_t cl_minfps = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps", "40", "minimum fps target - while the rendering performance is below this, it will drift toward lower quality"}; +cvar_t cl_minfps_fade = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_fade", "1", "how fast the quality adapts to varying framerate"}; +cvar_t cl_minfps_qualitymax = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"}; +cvar_t cl_minfps_qualitymin = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"}; +cvar_t cl_minfps_qualitymultiply = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitymultiply", "0.2", "multiplier for quality changes in quality change per second render time (1 assumes linearity of quality and render time)"}; +cvar_t cl_minfps_qualityhysteresis = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualityhysteresis", "0.05", "reduce all quality increments by this to reduce flickering"}; +cvar_t cl_minfps_qualitystepmax = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitystepmax", "0.1", "maximum quality change in a single frame"}; +cvar_t cl_minfps_force = {CVAR_CLIENT, "cl_minfps_force", "0", "also apply quality reductions in timedemo/capturevideo"}; +cvar_t cl_maxfps = {CVAR_CLIENT | CVAR_SAVE, "cl_maxfps", "0", "maximum fps cap, 0 = unlimited, if game is running faster than this it will wait before running another frame (useful to make cpu time available to other programs)"}; +cvar_t cl_maxfps_alwayssleep = {CVAR_CLIENT | CVAR_SAVE, "cl_maxfps_alwayssleep","1", "gives up some processing time to other applications each frame, value in milliseconds, disabled if cl_maxfps is 0"}; +cvar_t cl_maxidlefps = {CVAR_CLIENT | CVAR_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"}; + client_static_t cls; client_state_t cl; @@ -2698,6 +2710,156 @@ void CL_UpdateEntityShading(void) CL_UpdateEntityShading_Entity(r_refdef.scene.entities[i]); } +extern cvar_t host_framerate; +extern cvar_t host_speeds; + +double CL_Frame (double time) +{ + static double clframetime; + static double time1 = 0, time2 = 0, time3 = 0; + static double wait; + int pass1, pass2, pass3; + + // limit the frametime steps to no more than 100ms each + if (time > 0.1) + time = 0.1; + + // get new key events + Key_EventQueue_Unblock(); + SndSys_SendKeyEvents(); + Sys_SendKeyEvents(); + + if (cls.state != ca_dedicated && (time > 0 || cls.timedemo || ((vid_activewindow ? cl_maxfps : cl_maxidlefps).value < 1))) + { + R_TimeReport("---"); + Collision_Cache_NewFrame(); + R_TimeReport("photoncache"); +#ifdef CONFIG_VIDEO_CAPTURE + // decide the simulation time + if (cls.capturevideo.active) + { + //*** + if (cls.capturevideo.realtime) + clframetime = cl.realframetime = max(time, 1.0 / cls.capturevideo.framerate); + else + { + clframetime = 1.0 / cls.capturevideo.framerate; + cl.realframetime = max(time, clframetime); + } + } + else if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) + +#else + if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) +#endif + { + clframetime = cl.realframetime = max(time, 1.0 / cl_maxfps.value); + // when running slow, we need to sleep to keep input responsive + wait = bound(0, cl_maxfps_alwayssleep.value * 1000, 100000); + if (wait > 0) + Sys_Sleep((int)wait); + } + else if (!vid_activewindow && cl_maxidlefps.value >= 1 && !cls.timedemo) + clframetime = cl.realframetime = max(time, 1.0 / cl_maxidlefps.value); + else + clframetime = cl.realframetime = time; + + // apply slowmo scaling + clframetime *= cl.movevars_timescale; + // scale playback speed of demos by slowmo cvar + if (cls.demoplayback) + { + clframetime *= host_timescale.value; + // if demo playback is paused, don't advance time at all + if (cls.demopaused) + clframetime = 0; + } + else + { + // host_framerate overrides all else + if (host_framerate.value) + clframetime = host_framerate.value; + + if (cl.paused || host.paused) + clframetime = 0; + } + + if (cls.timedemo) + clframetime = cl.realframetime = time; + + // deduct the frame time from the accumulator + time -= cl.realframetime; + + cl.oldtime = cl.time; + cl.time += clframetime; + + // update video + if (host_speeds.integer) + time1 = Sys_DirtyTime(); + R_TimeReport("pre-input"); + + // Collect input into cmd + CL_Input(); + + R_TimeReport("input"); + + // check for new packets + NetConn_ClientFrame(); + + // read a new frame from a demo if needed + CL_ReadDemoMessage(); + R_TimeReport("clientnetwork"); + + // now that packets have been read, send input to server + CL_SendMove(); + R_TimeReport("sendmove"); + + // update client world (interpolate entities, create trails, etc) + CL_UpdateWorld(); + R_TimeReport("lerpworld"); + + CL_Video_Frame(); + + R_TimeReport("client"); + + CL_UpdateScreen(); + R_TimeReport("render"); + + if (host_speeds.integer) + time2 = Sys_DirtyTime(); + + // update audio + if(cl.csqc_usecsqclistener) + { + S_Update(&cl.csqc_listenermatrix); + cl.csqc_usecsqclistener = false; + } + else + S_Update(&r_refdef.view.matrix); + + CDAudio_Update(); + R_TimeReport("audio"); + + // reset gathering of mouse input + in_mouse_x = in_mouse_y = 0; + + if (host_speeds.integer) + { + pass1 = (int)((time1 - time3)*1000000); + time3 = Sys_DirtyTime(); + pass2 = (int)((time2 - time1)*1000000); + pass3 = (int)((time3 - time2)*1000000); + Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n", + pass1+pass2+pass3, pass1, pass2, pass3); + } + } + + // if there is some time remaining from this frame, reset the timer + if (time >= 0) + time = 0; + return time; +} + /* =========== CL_Shutdown @@ -2865,6 +3027,18 @@ void CL_Init (void) Cvar_RegisterVariable(&csqc_polygons_defaultmaterial_nocullface); + Cvar_RegisterVariable (&cl_minfps); + Cvar_RegisterVariable (&cl_minfps_fade); + Cvar_RegisterVariable (&cl_minfps_qualitymax); + Cvar_RegisterVariable (&cl_minfps_qualitymin); + Cvar_RegisterVariable (&cl_minfps_qualitystepmax); + Cvar_RegisterVariable (&cl_minfps_qualityhysteresis); + Cvar_RegisterVariable (&cl_minfps_qualitymultiply); + Cvar_RegisterVariable (&cl_minfps_force); + Cvar_RegisterVariable (&cl_maxfps); + Cvar_RegisterVariable (&cl_maxfps_alwayssleep); + Cvar_RegisterVariable (&cl_maxidlefps); + CL_Parse_Init(); CL_Particles_Init(); CL_Screen_Init(); diff --git a/client.h b/client.h index 7050932d..159d3233 100644 --- a/client.h +++ b/client.h @@ -1533,6 +1533,8 @@ void CL_Locs_FindLocationName(char *buffer, size_t buffersize, vec3_t point); // cl_main // +double CL_Frame(double time); + void CL_Shutdown (void); void CL_Init (void); diff --git a/host.c b/host.c index 3aa2b8db..6b3ba40e 100644 --- a/host.c +++ b/host.c @@ -52,17 +52,6 @@ cvar_t cl_maxphysicsframesperserverframe = {CVAR_CLIENT, "cl_maxphysicsframesper // shows time used by certain subsystems cvar_t host_speeds = {CVAR_CLIENT | CVAR_SERVER, "host_speeds","0", "reports how much time is used in server/graphics/sound"}; cvar_t host_maxwait = {CVAR_CLIENT | CVAR_SERVER, "host_maxwait","1000", "maximum sleep time requested from the operating system in millisecond. Larger sleeps will be done using multiple host_maxwait length sleeps. Lowering this value will increase CPU load, but may help working around problems with accuracy of sleep times."}; -cvar_t cl_minfps = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps", "40", "minimum fps target - while the rendering performance is below this, it will drift toward lower quality"}; -cvar_t cl_minfps_fade = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_fade", "1", "how fast the quality adapts to varying framerate"}; -cvar_t cl_minfps_qualitymax = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"}; -cvar_t cl_minfps_qualitymin = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"}; -cvar_t cl_minfps_qualitymultiply = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitymultiply", "0.2", "multiplier for quality changes in quality change per second render time (1 assumes linearity of quality and render time)"}; -cvar_t cl_minfps_qualityhysteresis = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualityhysteresis", "0.05", "reduce all quality increments by this to reduce flickering"}; -cvar_t cl_minfps_qualitystepmax = {CVAR_CLIENT | CVAR_SAVE, "cl_minfps_qualitystepmax", "0.1", "maximum quality change in a single frame"}; -cvar_t cl_minfps_force = {CVAR_CLIENT, "cl_minfps_force", "0", "also apply quality reductions in timedemo/capturevideo"}; -cvar_t cl_maxfps = {CVAR_CLIENT | CVAR_SAVE, "cl_maxfps", "0", "maximum fps cap, 0 = unlimited, if game is running faster than this it will wait before running another frame (useful to make cpu time available to other programs)"}; -cvar_t cl_maxfps_alwayssleep = {CVAR_CLIENT | CVAR_SAVE, "cl_maxfps_alwayssleep","1", "gives up some processing time to other applications each frame, value in milliseconds, disabled if cl_maxfps is 0"}; -cvar_t cl_maxidlefps = {CVAR_CLIENT | CVAR_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"}; cvar_t developer = {CVAR_CLIENT | CVAR_SERVER | CVAR_SAVE, "developer","0", "shows debugging messages and information (recommended for all developers and level designers); the value -1 also suppresses buffering and logging these messages"}; cvar_t developer_extra = {CVAR_CLIENT | CVAR_SERVER, "developer_extra", "0", "prints additional debugging messages, often very verbose!"}; @@ -247,17 +236,6 @@ static void Host_InitLocal (void) Cvar_RegisterVariable (&host_framerate); Cvar_RegisterVariable (&host_speeds); Cvar_RegisterVariable (&host_maxwait); - Cvar_RegisterVariable (&cl_minfps); - Cvar_RegisterVariable (&cl_minfps_fade); - Cvar_RegisterVariable (&cl_minfps_qualitymax); - Cvar_RegisterVariable (&cl_minfps_qualitymin); - Cvar_RegisterVariable (&cl_minfps_qualitystepmax); - Cvar_RegisterVariable (&cl_minfps_qualityhysteresis); - Cvar_RegisterVariable (&cl_minfps_qualitymultiply); - Cvar_RegisterVariable (&cl_minfps_force); - Cvar_RegisterVariable (&cl_maxfps); - Cvar_RegisterVariable (&cl_maxfps_alwayssleep); - Cvar_RegisterVariable (&cl_maxidlefps); Cvar_RegisterVariable (&developer); Cvar_RegisterVariable (&developer_extra); @@ -397,13 +375,10 @@ Runs all active servers static void Host_Init(void); void Host_Main(void) { - double time1 = 0; - double time2 = 0; - double time3 = 0; double cl_timer = 0, sv_timer = 0; - double clframetime, time, oldtime, newtime; + double time, oldtime, newtime; double wait; - int pass1, pass2, pass3, i; + int i; char vabuf[1024]; qboolean playing; @@ -625,144 +600,7 @@ void Host_Main(void) // //------------------- - // limit the frametime steps to no more than 100ms each - if (cl_timer > 0.1) - cl_timer = 0.1; - - // get new key events - Key_EventQueue_Unblock(); - SndSys_SendKeyEvents(); - Sys_SendKeyEvents(); - - if (cls.state != ca_dedicated && (cl_timer > 0 || cls.timedemo || ((vid_activewindow ? cl_maxfps : cl_maxidlefps).value < 1))) - { - R_TimeReport("---"); - Collision_Cache_NewFrame(); - R_TimeReport("photoncache"); -#ifdef CONFIG_VIDEO_CAPTURE - // decide the simulation time - if (cls.capturevideo.active) - { - //*** - if (cls.capturevideo.realtime) - clframetime = cl.realframetime = max(cl_timer, 1.0 / cls.capturevideo.framerate); - else - { - clframetime = 1.0 / cls.capturevideo.framerate; - cl.realframetime = max(cl_timer, clframetime); - } - } - else if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) - -#else - if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) -#endif - { - clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxfps.value); - // when running slow, we need to sleep to keep input responsive - wait = bound(0, cl_maxfps_alwayssleep.value * 1000, 100000); - if (wait > 0) - Sys_Sleep((int)wait); - } - else if (!vid_activewindow && cl_maxidlefps.value >= 1 && !cls.timedemo) - clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxidlefps.value); - else - clframetime = cl.realframetime = cl_timer; - - // apply slowmo scaling - clframetime *= cl.movevars_timescale; - // scale playback speed of demos by slowmo cvar - if (cls.demoplayback) - { - clframetime *= host_timescale.value; - // if demo playback is paused, don't advance time at all - if (cls.demopaused) - clframetime = 0; - } - else - { - // host_framerate overrides all else - if (host_framerate.value) - clframetime = host_framerate.value; - - if (cl.paused || host.paused) - clframetime = 0; - } - - if (cls.timedemo) - clframetime = cl.realframetime = cl_timer; - - // deduct the frame time from the accumulator - cl_timer -= cl.realframetime; - - cl.oldtime = cl.time; - cl.time += clframetime; - - // update video - if (host_speeds.integer) - time1 = Sys_DirtyTime(); - R_TimeReport("pre-input"); - - // Collect input into cmd - CL_Input(); - - R_TimeReport("input"); - - // check for new packets - NetConn_ClientFrame(); - - // read a new frame from a demo if needed - CL_ReadDemoMessage(); - R_TimeReport("clientnetwork"); - - // now that packets have been read, send input to server - CL_SendMove(); - R_TimeReport("sendmove"); - - // update client world (interpolate entities, create trails, etc) - CL_UpdateWorld(); - R_TimeReport("lerpworld"); - - CL_Video_Frame(); - - R_TimeReport("client"); - - CL_UpdateScreen(); - R_TimeReport("render"); - - if (host_speeds.integer) - time2 = Sys_DirtyTime(); - - // update audio - if(cl.csqc_usecsqclistener) - { - S_Update(&cl.csqc_listenermatrix); - cl.csqc_usecsqclistener = false; - } - else - S_Update(&r_refdef.view.matrix); - - CDAudio_Update(); - R_TimeReport("audio"); - - // reset gathering of mouse input - in_mouse_x = in_mouse_y = 0; - - if (host_speeds.integer) - { - pass1 = (int)((time1 - time3)*1000000); - time3 = Sys_DirtyTime(); - pass2 = (int)((time2 - time1)*1000000); - pass3 = (int)((time3 - time2)*1000000); - Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n", - pass1+pass2+pass3, pass1, pass2, pass3); - } - } - - // if there is some time remaining from this frame, reset the timer - if (cl_timer >= 0) - cl_timer = 0; - + cl_timer = CL_Frame(cl_timer); cl_timer += time; #if MEMPARANOIA -- 2.39.2