diff --git a/src/engine/qcommon/common.cpp b/src/engine/qcommon/common.cpp index 680f4f8ced..b969b9c0c1 100644 --- a/src/engine/qcommon/common.cpp +++ b/src/engine/qcommon/common.cpp @@ -861,26 +861,49 @@ void Com_Frame() minMsec = 1; } + int beforeProcessing = Sys::Milliseconds(); + Com_EventLoop(); - com_frameTime = Sys::Milliseconds(); - if ( lastTime > com_frameTime ) - { - lastTime = com_frameTime; // possible on first frame - } + // It must be called at least once. + IN_Frame(); - msec = com_frameTime - lastTime; + int afterProcessing = Sys::Milliseconds(); + + com_frameTime = afterProcessing; - IN_Frame(); // must be called at least once + // lastTime can be greater than com_frameTime on first frame. + lastTime = std::min( lastTime, com_frameTime ); + + msec = com_frameTime - lastTime; while ( msec < minMsec ) { - //give cycles back to the OS - Sys::SleepFor(std::chrono::milliseconds(std::min(minMsec - msec, 50))); - IN_Frame(); + int processingTime = afterProcessing - beforeProcessing; + + /* Fill as much as input frames as possible within this timeframe to not + let the game process events in a way it would last longer than that. */ + int jamTime = std::max( afterProcessing, 50 ); + + int sleep = minMsec - msec; + + // Let enough time to process events and jam frames after sleeping. + if ( sleep > jamTime * 2 ) + { + // Give cycles back to the OS. + Sys::SleepFor( std::chrono::milliseconds( processingTime ) ); + } + + beforeProcessing = Sys::Milliseconds(); Com_EventLoop(); - com_frameTime = Sys::Milliseconds(); + + IN_Frame(); + + afterProcessing = Sys::Milliseconds(); + + com_frameTime = afterProcessing; + msec = com_frameTime - lastTime; }