diff --git a/src/common/frame.c b/src/common/frame.c index f780c8ca..700113c5 100644 --- a/src/common/frame.c +++ b/src/common/frame.c @@ -348,6 +348,16 @@ Qcommon_Frame(int msec) microseconds. */ qboolean renderframe = true; + // Average time needed to process a render frame. + static int avgrenderframetime; + static int renderframetimes[60]; + static qboolean last_was_renderframe; + + // Average time needed to process a packet frame. + static int avgpacketframetime; + static int packetframetimes[60]; + static qboolean last_was_packetframe; + /* In case of ERR_DROP we're jumping here. Don't know if that' really save but it seems to work. So leave @@ -446,7 +456,82 @@ Qcommon_Frame(int msec) rfps = (int)vid_maxfps->value; } - pfps = (cl_maxfps->value > rfps) ? rfps : cl_maxfps->value; + /* The target render frame rate may be too high. The current + scene may be more complex than the previous one and SDL + may give us a 1 or 2 frames too low display refresh rate. + Add a security magin of 5%, e.g. 60fps * 0.95 = 57fps. */ + pfps = (cl_maxfps->value > rfps) ? floor(rfps * 0.95) : cl_maxfps->value; + + + /* Calculate average time spend to process a render + frame. This is highly depended on the GPU and the + scenes complexity. Take the last 60 pure render + frames (frames that are only render frames and + nothing else) into account and add a security + margin of 2%. */ + if (last_was_renderframe && !last_was_packetframe) + { + int measuredframes = 0; + static int renderframenum; + + renderframetimes[renderframenum] = msec; + + for (int i = 0; i < 60; i++) + { + if (renderframetimes[i] != 0) + { + avgrenderframetime += renderframetimes[i]; + measuredframes++; + } + } + + avgrenderframetime /= measuredframes; + avgrenderframetime += (avgrenderframetime * 0.02f); + + renderframenum++; + + if (renderframenum > 59) + { + renderframenum = 0; + } + + last_was_renderframe = false; + } + + /* Calculate the average time spend to process a packet + frame. Packet frames are mostly dependend on the CPU + speed and the network delay. Take the last 60 pure + packet frames (frames that are only packet frames ans + nothing else) into account and add a security margin + of 2%. */ + if (last_was_packetframe && last_was_renderframe) + { + int measuredframes = 0; + static int packetframenum; + + packetframetimes[packetframenum] = msec; + + for (int i = 0; i < 60; i++) + { + if (packetframetimes[i] != 0) + { + avgpacketframetime += packetframetimes[i]; + measuredframes++; + } + } + + avgpacketframetime /= measuredframes; + avgpacketframetime += (avgpacketframetime * 0.02f); + + packetframenum++; + + if (packetframenum > 59) + { + packetframenum = 0; + } + + last_was_packetframe = false; + } // Calculate timings. @@ -458,12 +543,12 @@ Qcommon_Frame(int msec) if (!cl_timedemo->value) { if (cl_async->value) { // Network frames.. - if (packetdelta < (1000000.0f / pfps)) { + if (packetdelta < ((1000000.0f - avgpacketframetime) / pfps)) { packetframe = false; } // Render frames. - if (renderdelta < (1000000.0f / rfps)) { + if (renderdelta < ((1000000.0f - avgrenderframetime) / rfps)) { renderframe = false; } } else { @@ -535,13 +620,15 @@ Qcommon_Frame(int msec) } - // Reset deltas if necessary. + // Reset deltas and mark frame. if (packetframe) { packetdelta = 0; + last_was_packetframe = true; } if (renderframe) { renderdelta = 0; + last_was_renderframe = true; } } #else