diff --git a/lib/gamelib/gtime.cpp b/lib/gamelib/gtime.cpp index 5ff715dc0aa..ef73f141d28 100644 --- a/lib/gamelib/gtime.cpp +++ b/lib/gamelib/gtime.cpp @@ -149,7 +149,7 @@ UDWORD getModularScaledRealTime(UDWORD timePeriod, UDWORD requiredRange) } /* Call this each loop to update the game timer */ -void gameTimeUpdate() +void gameTimeUpdate(unsigned renderAverage, unsigned stateAverage) { deltaGameTime = 0; deltaGraphicsTime = 0; @@ -171,8 +171,13 @@ void gameTimeUpdate() return; } + (void)stateAverage; // Don't need to know the average state update time. + // A bit arbitrary formula, but if the average time to render a frame is high compared to the time to update the + // state, then update multiple times per frame. Otherwise, update at least once per frame. + unsigned maximumTicksPerFrame = renderAverage*2 + GAME_TICKS_PER_UPDATE*modifier.d/std::max(modifier.n, 1) + 1; + // Make sure graphics updates fast enough. - prevRealTime = std::max(prevRealTime + MAXIMUM_TICKS_PER_FRAME, currTime) - MAXIMUM_TICKS_PER_FRAME; // Written this way to avoid unsigned underflow. + prevRealTime = std::max(prevRealTime + maximumTicksPerFrame, currTime) - maximumTicksPerFrame; // Written this way to avoid unsigned underflow. // Calculate the new game time int newDeltaGraphicsTime = quantiseFraction(modifier.n, modifier.d, currTime, prevRealTime); diff --git a/lib/gamelib/gtime.h b/lib/gamelib/gtime.h index b249cc37c35..05e364e4959 100644 --- a/lib/gamelib/gtime.h +++ b/lib/gamelib/gtime.h @@ -71,7 +71,7 @@ extern void setGameTime(uint32_t newGameTime); * The game time increases in GAME_UNITS_PER_TICK increments, and deltaGameTime is either 0 or GAME_UNITS_PER_TICK. * @returns true iff the game time ticked. */ -extern void gameTimeUpdate(void); +void gameTimeUpdate(unsigned renderAverage, unsigned stateAverage); /// Call after updating the state, and before processing any net messages that use deltaGameTime. (Sets deltaGameTime = 0.) void gameTimeUpdateEnd(void); diff --git a/src/loop.cpp b/src/loop.cpp index f313a75b79d..8176cd5aee4 100644 --- a/src/loop.cpp +++ b/src/loop.cpp @@ -93,6 +93,9 @@ #include "objmem.h" #endif +#include + + static void fireWaitingCallbacks(void); /* @@ -663,6 +666,10 @@ static void gameStateUpdate() GAMECODE gameLoop(void) { static uint32_t lastFlushTime = 0; + static unsigned stateTimes[8]; + static unsigned renderTimes[8]; + static int stateTimeIndex = 0; + static int renderTimeIndex = 0; bool didTick = false; while (true) @@ -671,8 +678,11 @@ GAMECODE gameLoop(void) // Receive GAME_BLAH messages, and if it's time, process exactly as many GAME_BLAH messages as required to be able to tick the gameTime. recvMessage(); + unsigned renderAverage = std::accumulate(renderTimes, renderTimes + ARRAY_SIZE(renderTimes), 0) / ARRAY_SIZE(renderTimes); + unsigned stateAverage = std::accumulate(stateTimes, stateTimes + ARRAY_SIZE(stateTimes), 0) / ARRAY_SIZE(stateTimes); + // Update gameTime and graphicsTime, and corresponding deltas. Note that gameTime and graphicsTime pause, if we aren't getting our GAME_GAME_TIME messages. - gameTimeUpdate(); + gameTimeUpdate(renderAverage, stateAverage); if (deltaGameTime == 0) { @@ -682,9 +692,14 @@ GAMECODE gameLoop(void) ASSERT(!paused && !gameUpdatePaused() && !editPaused(), "Nonsensical pause values."); + unsigned before = wzGetTicks(); syncDebug("Begin game state update, gameTime = %d", gameTime); gameStateUpdate(); syncDebug("End game state update, gameTime = %d", gameTime); + unsigned after = wzGetTicks(); + + stateTimes[stateTimeIndex] = after - before; + stateTimeIndex = (stateTimeIndex + 1)%ARRAY_SIZE(stateTimes); ASSERT(deltaGraphicsTime == 0, "Shouldn't update graphics and game state at once."); } @@ -695,7 +710,14 @@ GAMECODE gameLoop(void) NETflush(); // Make sure the game time tick message is really sent over the network, and that we aren't waiting too long to send data. } - return renderLoop(); + unsigned before = wzGetTicks(); + GAMECODE renderReturn = renderLoop(); + unsigned after = wzGetTicks(); + + renderTimes[renderTimeIndex] = after - before; + renderTimeIndex = (renderTimeIndex + 1)%ARRAY_SIZE(renderTimes); + + return renderReturn; } /* The video playback loop */