]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
new cl_minfps logic that seems a lot more successful at attaining target fps
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 3 Dec 2011 08:53:50 +0000 (08:53 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 3 Dec 2011 08:53:50 +0000 (08:53 +0000)
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

cl_screen.c
host.c

index 7724b5ce28c0a54a8e62a87a6ee61049062476da..a9a088c5b22e163fe9b792ccb0817ba5a7bbaa7f 100644 (file)
@@ -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 d08795a24aaef8665a50f2ba294e3f70361d287f..60db8ba1b1fa896a144e3f4cd028430f350444a4 100644 (file)
--- 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);