1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
// ldd libboost_chrono.so.* --> must be linked against librt (for nanosecond-precision timer) which must be present
// g++ -Wall -Wextra -Wno-unused -O2 -o tst TimerTest.cpp -I ../../../rts/ -lboost_system -lboost_thread -lboost_chrono {-lrt}
//
#include <cstdio>
#include <cstdlib>
#include <boost/thread.hpp>
#include "System/Misc/SpringTime.h"
#define GAME_SPEED_HZ 30
#define FRAME_TIME_MS (1000.0f / GAME_SPEED_HZ)
// #define SLEEP_DRAW
static unsigned int lastSimFrame = 0;
static unsigned int lastSimFrameRateUpdateFrame = 0;
static spring_time lastDrawFrameTime = spring_notime;
static spring_time lastSimFrameTime = spring_notime;
static spring_time lastSimFrameRateUpdateTime = spring_notime;
static float simFrameRate = 0.0f; // globalUnsynced->simFPS (undefined during first 30 sim-frames)
static float simFrameTimeOffset = 0.0f; // globalRendering->timeOffset
static float simSpeedFactor = 0.0f; // globalRendering->weightedSpeedFactor
static void NewSimFrame(unsigned int currSimFrame) {
if (currSimFrame > GAME_SPEED_HZ) {
printf("[%s] sf=%u fps=%f to=%f\n\n", __FUNCTION__, currSimFrame, simFrameRate, simFrameTimeOffset);
}
lastSimFrame = currSimFrame;
lastSimFrameTime = spring_gettime();
}
static void GameUpdateUnsynced(unsigned int currSimFrame, unsigned int currDrawFrame) {
const spring_time currentTime = spring_gettime();
const float dt = (currentTime - lastSimFrameRateUpdateTime).toSecsf();
// update simFPS counter
if (dt >= 1.0f) {
simFrameRate = (currSimFrame - lastSimFrameRateUpdateFrame) / dt;
lastSimFrameRateUpdateTime = currentTime;
lastSimFrameRateUpdateFrame = currSimFrame;
}
simSpeedFactor = 0.001f * simFrameRate;
simFrameTimeOffset = (currentTime - lastSimFrameTime).toMilliSecsf() * simSpeedFactor;
}
static void GameDraw(unsigned int currSimFrame, unsigned int currDrawFrame) {
// do something useful that takes non-trivial time, eg. sleeping
// at ~5 milliseconds per draw-frame, rFPS would be at most ~200
// wake-up can vary and affects FPS too much, busy-loop instead
{
#ifdef SLEEP_DRAW
boost::this_thread::sleep(boost::posix_time::milliseconds(1 + (random() % 5)));
#else
const spring_time currentTime = spring_gettime();
const spring_time wakeUpTime = currentTime + spring_time(1 + (random() % 5)); // MILLIseconds
while (spring_gettime() < wakeUpTime) {
}
#endif
}
const float currTimeOffset = simFrameTimeOffset;
static float lastTimeOffset = simFrameTimeOffset;
// do nothing first 30 frames
if (currSimFrame < GAME_SPEED_HZ)
return;
if (currTimeOffset < 0.0f)
printf("[%s] assert(timeOffset >= 0.0f) failed (SF=%u : DF=%u : TO=%f)\n", __FUNCTION__, currSimFrame, currDrawFrame, currTimeOffset);
if (currTimeOffset > 1.0f)
printf("[%s] assert(timeOffset <= 1.0f) failed (SF=%u : DF=%u : TO=%f)\n", __FUNCTION__, currSimFrame, currDrawFrame, currTimeOffset);
// test for monotonicity
if (currTimeOffset < lastTimeOffset)
printf("[%s] assert(timeOffset < lastTimeOffset) failed (SF=%u : DF=%u : CTO=%f LTO=%f)\n", __FUNCTION__, currSimFrame, currDrawFrame, currTimeOffset, lastTimeOffset);
lastTimeOffset = currTimeOffset;
}
static void NewDrawFrame(unsigned int currSimFrame, unsigned int currDrawFrame) {
lastDrawFrameTime = spring_gettime();
GameUpdateUnsynced(currSimFrame, currDrawFrame);
GameDraw(currSimFrame, currDrawFrame);
}
static void TimerFunc(unsigned int N) {
printf("[%s][N=%u]\n\n", __FUNCTION__, N);
lastDrawFrameTime = spring_gettime();
lastSimFrameTime = spring_gettime();
lastSimFrameRateUpdateTime = spring_gettime();
for (unsigned int sf = 0, df = 0; sf < N; /*no-op*/) {
NewDrawFrame(sf, df++);
if ((spring_gettime() - lastSimFrameTime).toMilliSecsf() > FRAME_TIME_MS) {
NewSimFrame(sf++);
}
}
}
int main(int argc, char** argv) {
srandom(time(NULL));
boost::thread timer = boost::thread(boost::bind(&TimerFunc, (argc >= 2)? atoi(argv[1]): (GAME_SPEED_HZ * 60 * 60)));
timer.join();
return 0;
}
|