Introduce cl_maxfps -1 for "use optimal value based on render framerate"

(this is the default value of that cvar now)

In Qcommon_Frame(), if cl_async is 1, the packet framerate should
ideally be a fraction of the render framerate, and to avoid movement
glitches and such it should be between 45 and 90, ideally around 60.
With cl_maxfps set to -1, pfps now is set to such a value automatically.
This commit is contained in:
Daniel Gibson 2022-05-09 01:48:29 +02:00
parent 7cf1392765
commit 502ff345c3

View file

@ -342,7 +342,7 @@ Qcommon_Init(int argc, char **argv)
// cvars // cvars
cl_maxfps = Cvar_Get("cl_maxfps", "60", CVAR_ARCHIVE); cl_maxfps = Cvar_Get("cl_maxfps", "-1", CVAR_ARCHIVE);
developer = Cvar_Get("developer", "0", 0); developer = Cvar_Get("developer", "0", 0);
fixedtime = Cvar_Get("fixedtime", "0", 0); fixedtime = Cvar_Get("fixedtime", "0", 0);
@ -542,10 +542,6 @@ Qcommon_Frame(int usec)
{ {
Cvar_SetValue("cl_maxfps", 250); Cvar_SetValue("cl_maxfps", 250);
} }
else if (cl_maxfps->value < 1)
{
Cvar_SetValue("cl_maxfps", 60);
}
// Calculate target and renderframerate. // Calculate target and renderframerate.
if (R_IsVSyncActive()) if (R_IsVSyncActive())
@ -563,13 +559,13 @@ Qcommon_Frame(int usec)
} }
else // target refresh rate, not vid_maxfps else // target refresh rate, not vid_maxfps
{ {
// if vsync is active, we increase the target framerate a bit for two reasons /* if vsync is active, we increase the target framerate a bit for two reasons
// 1. On Windows, GLimp_GetFrefreshRate() (or the SDL counterpart, or even 1. On Windows, GLimp_GetFrefreshRate() (or the SDL counterpart, or even
// the underlying WinAPI function) often returns a too small value, the underlying WinAPI function) often returns a too small value,
// like 58 or 59 when it's really 59.95 and thus (as integer) should be 60 like 58 or 59 when it's really 59.95 and thus (as integer) should be 60
// 2. vsync will throttle us to refreshrate anyway, so there is no harm 2. vsync will throttle us to refreshrate anyway, so there is no harm
// in starting the frame *a bit* earlier, instead of risking starting in starting the frame *a bit* earlier, instead of risking starting
// it too late it too late */
rfps = refreshrate * 1.2f; rfps = refreshrate * 1.2f;
// we can't have more packet frames than render frames, so limit pfps to rfps // we can't have more packet frames than render frames, so limit pfps to rfps
// but in this case use tolerance for comparison and assign rfps with tolerance // but in this case use tolerance for comparison and assign rfps with tolerance
@ -583,6 +579,35 @@ Qcommon_Frame(int usec)
pfps = (cl_maxfps->value > rfps) ? rfps : cl_maxfps->value; pfps = (cl_maxfps->value > rfps) ? rfps : cl_maxfps->value;
} }
// cl_maxfps <= 0 means: automatically choose a packet framerate that should work
// well with the render framerate, which is the case if rfps is a multiple of pfps
if (cl_maxfps->value <= 0.0f && cl_async->value != 0.0f)
{
// packet framerates between about 45 and 90 should be ok,
// with other values the game (esp. movement/clipping) can become glitchy
// as pfps must be <= rfps, for rfps < 90 just use that as pfps
if (rfps < 90)
{
pfps = rfps;
}
else
{
/* we want an integer divider, so every div-th renderframe is a packetframe.
this formula gives nice dividers that keep pfps as close as possible
to 60 (which seems to be ideal):
- for < 150 rfps div will be 2, so pfps will be between 45 and ~75
=> exactly every second renderframe we also run a packetframe
- for < 210 rfps div will be 3, so pfps will be between 50 and ~70
=> exactly every third renderframe we also run a packetframe
- etc, the higher the rfps, the closer the pfps-range will be to 60
(and you probably get the very best results by running at a
render framerate that's a multiple of 60) */
// TODO: what happens if we can't reach rfps? probably a suboptimal pfps?
float div = round(rfps/60);
pfps = rfps/div;
}
}
// Calculate timings. // Calculate timings.
packetdelta += usec; packetdelta += usec;
renderdelta += usec; renderdelta += usec;