From 5fc3dcf704ad783f1991411e704bf5c607ed4cf4 Mon Sep 17 00:00:00 2001 From: divverent Date: Sat, 3 Dec 2011 08:53:50 +0000 Subject: [PATCH] new cl_minfps logic that seems a lot more successful at attaining target fps The new approach is quite similar to r_viewscale_fpsscaling; possibly, that logic then can be changed to use r_refdef.view.quality instead at a later time git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11590 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=70b6de8a98705a7d7097803a84bdd224b05103cc --- cl_screen.c | 98 ++++++++++++++++++++++++++++++++++++++++------------- host.c | 12 ++++--- 2 files changed, 81 insertions(+), 29 deletions(-) diff --git a/cl_screen.c b/cl_screen.c index 7724b5ce..a9a088c5 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -2205,20 +2205,84 @@ extern cvar_t cl_minfps; extern cvar_t cl_minfps_fade; extern cvar_t cl_minfps_qualitymax; extern cvar_t cl_minfps_qualitymin; -extern cvar_t cl_minfps_qualitypower; -extern cvar_t cl_minfps_qualityscale; -extern cvar_t r_viewscale_fpsscaling; -static double cl_updatescreen_rendertime = 0; +extern cvar_t cl_minfps_qualitymultiply; +extern cvar_t cl_minfps_qualityhysteresis; +extern cvar_t cl_minfps_qualitystepmax; static double cl_updatescreen_quality = 1; void CL_UpdateScreen(void) { vec3_t vieworigin; - double rendertime1; - double drawscreenstart; + static double drawscreenstart = 0.0; + double drawscreendelta; float conwidth, conheight; - float f; r_viewport_t viewport; + if(drawscreenstart) + { + drawscreendelta = Sys_DirtyTime() - drawscreenstart; + if (cl_minfps.value > 0 && !cls.timedemo && (!cls.capturevideo.active || cls.capturevideo.realtime) && drawscreendelta >= 0 && drawscreendelta < 60) + { + // quality adjustment according to render time + double actualframetime; + double targetframetime; + double adjust; + double f; + double h; + r_refdef.lastdrawscreentime += (drawscreendelta - r_refdef.lastdrawscreentime) * cl_minfps_fade.value; + actualframetime = r_refdef.lastdrawscreentime; + targetframetime = (1.0 / cl_minfps.value); + + // assume render time scales linearily / cl_minfps_qualitymultiply.value with quality... + f = cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value; + // we scale hysteresis by quality + h = cl_updatescreen_quality * cl_minfps_qualityhysteresis.value; + + targetframetime -= h / f; // this makes sure resulting fps is > minfps despite hysteresis + + adjust = (targetframetime - actualframetime) * f; + if(adjust > h) + adjust -= h; + else if(adjust > -h) + adjust = 0; + else + adjust += h; + + // adjust > 0 if: + // (targetframetime - actualframetime) * f > h + // (targetframetime - actualframetime) * (cl_updatescreen_quality / actualframetime * qualitymultiply) > h + // (1.0 / minfps - h / (quality / actualframetime * qualitymultiply) - actualframetime) * (quality / actualframetime * qualitymultiply) > h + // (1.0 / minfps - actualframetime) * (quality / actualframetime * qualitymultiply) > 2 * h + // actualframetime < quality qualitymultiply / (minfps quality qualitymultiply + 2 minfps h) + // actualframetime < 1.0 / minfps * (quality qualitymultiply) / (quality qualitymultiply + 2 h) + // actualframetime < 1.0 / minfps / (1 + 2 h / (quality qualitymultiply)) + // actualframetime < 1.0 / minfps / (1 + 2 qualityhysteresis / qualitymultiply) + + // adjust < 0 if: + // (targetframetime - actualframetime) * f < -h + // (targetframetime - actualframetime) * (cl_updatescreen_quality / actualframetime * qualitymultiply) < -h + // (1.0 / minfps - h / (quality / actualframetime * qualitymultiply) - actualframetime) * (quality / actualframetime * qualitymultiply) < -h + // (1.0 / minfps - actualframetime) * (quality / actualframetime * qualitymultiply) < 0 + // actualframetime > 1.0 / minfps + + /* + Con_Printf("adjust UP if fps > %f, adjust DOWN if fps < %f\n", + cl_minfps.value * (1.0 + 2.0 * cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value), + cl_minfps.value); + */ + + adjust = bound(-cl_minfps_qualitystepmax.value, adjust, cl_minfps_qualitystepmax.value); + cl_updatescreen_quality += adjust; + cl_updatescreen_quality = bound(max(0.01, cl_minfps_qualitymin.value), cl_updatescreen_quality, cl_minfps_qualitymax.value); + } + else + { + cl_updatescreen_quality = 1; + r_refdef.lastdrawscreentime = 0; + } + } + + drawscreenstart = Sys_DirtyTime(); + Sbar_ShowFPS_Update(); if (!scr_initialized || !con_initialized || !scr_refresh.integer) @@ -2245,8 +2309,6 @@ void CL_UpdateScreen(void) return; } - rendertime1 = Sys_DirtyTime(); - conwidth = bound(160, vid_conwidth.value, 32768); conheight = bound(90, vid_conheight.value, 24576); if (vid_conwidth.value != conwidth) @@ -2315,8 +2377,9 @@ void CL_UpdateScreen(void) R_ClearScreen(false); r_refdef.view.clear = false; r_refdef.view.isoverlay = false; - f = pow((float)cl_updatescreen_quality, cl_minfps_qualitypower.value) * cl_minfps_qualityscale.value; - r_refdef.view.quality = bound(cl_minfps_qualitymin.value, f, cl_minfps_qualitymax.value); + + // calculate r_refdef.view.quality + r_refdef.view.quality = cl_updatescreen_quality; #ifndef USE_GLES2 if (qglPolygonStipple) @@ -2347,9 +2410,6 @@ void CL_UpdateScreen(void) } #endif - if (r_viewscale_fpsscaling.integer) - GL_Finish(); - drawscreenstart = Sys_DirtyTime(); #ifndef USE_GLES2 if (R_Stereo_Active()) { @@ -2385,22 +2445,12 @@ void CL_UpdateScreen(void) else #endif SCR_DrawScreen(); - if (r_viewscale_fpsscaling.integer) - GL_Finish(); - r_refdef.lastdrawscreentime = Sys_DirtyTime() - drawscreenstart; SCR_CaptureVideo(); if (qglFlush) qglFlush(); // FIXME: should we really be using qglFlush here? - // quality adjustment according to render time - cl_updatescreen_rendertime += ((Sys_DirtyTime() - rendertime1) - cl_updatescreen_rendertime) * bound(0, cl_minfps_fade.value, 1); - if (cl_minfps.value > 0 && cl_updatescreen_rendertime > 0 && !cls.timedemo && (!cls.capturevideo.active || !cls.capturevideo.realtime)) - cl_updatescreen_quality = 1 / (cl_updatescreen_rendertime * cl_minfps.value); - else - cl_updatescreen_quality = 1; - if (!vid_activewindow) VID_SetMouse(false, false, false); else if (key_consoleactive) diff --git a/host.c b/host.c index d08795a2..60db8ba1 100644 --- a/host.c +++ b/host.c @@ -66,11 +66,12 @@ cvar_t cl_maxphysicsframesperserverframe = {0, "cl_maxphysicsframesperserverfram cvar_t host_speeds = {0, "host_speeds","0", "reports how much time is used in server/graphics/sound"}; cvar_t host_maxwait = {0, "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_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_SAVE, "cl_minfps_fade", "0.2", "how fast the quality adapts to varying framerate"}; +cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "1", "how fast the quality adapts to varying framerate"}; cvar_t cl_minfps_qualitymax = {CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"}; cvar_t cl_minfps_qualitymin = {CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"}; -cvar_t cl_minfps_qualitypower = {CVAR_SAVE, "cl_minfps_qualitypower", "4", "raises quality value to a power of itself, higher values make quality drop more sharply in relation to framerate"}; -cvar_t cl_minfps_qualityscale = {CVAR_SAVE, "cl_minfps_qualityscale", "0.5", "multiplier for quality"}; +cvar_t cl_minfps_qualitymultiply = {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_SAVE, "cl_minfps_qualityhysteresis", "0.025", "reduce all quality changes by this to reduce flickering"}; +cvar_t cl_minfps_qualitystepmax = {CVAR_SAVE, "cl_minfps_qualitystepmax", "0.1", "maximum quality change in a single frame"}; cvar_t cl_maxfps = {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 = {0, "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_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"}; @@ -240,8 +241,9 @@ static void Host_InitLocal (void) Cvar_RegisterVariable (&cl_minfps_fade); Cvar_RegisterVariable (&cl_minfps_qualitymax); Cvar_RegisterVariable (&cl_minfps_qualitymin); - Cvar_RegisterVariable (&cl_minfps_qualitypower); - Cvar_RegisterVariable (&cl_minfps_qualityscale); + Cvar_RegisterVariable (&cl_minfps_qualitystepmax); + Cvar_RegisterVariable (&cl_minfps_qualityhysteresis); + Cvar_RegisterVariable (&cl_minfps_qualitymultiply); Cvar_RegisterVariable (&cl_maxfps); Cvar_RegisterVariable (&cl_maxfps_alwayssleep); Cvar_RegisterVariable (&cl_maxidlefps); -- 2.39.2