0

what I want to do is:

start a timer;
calculate and render stuff;
wait until time==enough;

First of all; I heard that the GetTickCount function from windows has low accuracy. Is this true?

Secondly; If it isn't accurate. what should i use instead?

Thirdly; Is there another way to limit the frames in a blitting based game?

luddbro
  • 85
  • 13
  • 1
    Given a quality implementation, http://en.cppreference.com/w/cpp/chrono/steady_clock – chris Mar 20 '15 at 14:46
  • 1
    Perhaps not a duplicate, but the heart of the question is covered here: http://stackoverflow.com/questions/1825720/c-high-precision-time-measurement-in-windows – Adrian McCarthy Mar 20 '15 at 18:13

1 Answers1

1

Assuming this is for windows, note that Visual Studio 2012 and 2013 only use the standard ticker for std::chrono::high_resolution_clock (64hz default, 1000hz optional with BeginTimePeriod()) ), so it's best to use the performance counter, which runs at about 3mhz on Vista and later (or cpu clock rate on XP). Example of a thread running at a fixed frequency, and Windows XP compatable, where a Sleep(1) can take up to 2 ms. dwLateStep is a debug aid, incremented every time a cycle takes too long (it will catch up if possible). The delays are based on an original reading of the counter (using uWait and uRem), so there's no drift over a long period of time.

typedef unsigned long long UI64;        /* unsigned 64 bit int */
#define FREQ    400                     /* frequency */
DWORD    dwLateStep;                    /* late step count */
LARGE_INTEGER liPerfFreq;               /* 64 bit frequency */
LARGE_INTEGER liPerfTemp;               /* used for query */
UI64 uFreq = FREQ;                      /* process frequency */
UI64 uOrig;                             /* original tick */
UI64 uWait;                             /* tick rate / freq */
UI64 uRem = 0;                          /* tick rate % freq */
UI64 uPrev;                             /* previous tick based on original tick */
UI64 uDelta;                            /* current tick - previous */
UI64 u2ms;                              /* 2ms of ticks */
UI64 i;

    /* ... */ /* wait for some event to start thread */
    QueryPerformanceFrequency(&liPerfFreq);
    u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);

    timeBeginPeriod(1);                 /* set period to 1ms */
    Sleep(128);                         /* wait for it to stabilize */

    QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
    uOrig = uPrev = liPerfTemp.QuadPart;

    for(i = 0; i < (uFreq*30); i++){
        /* update uWait and uRem based on uRem */
        uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
        uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
        /* wait for uWait ticks */
        while(1){
            QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
            uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
            if(uDelta >= uWait)
                break;
            if((uWait - uDelta) > u2ms)
                Sleep(1);
        }
        if(uDelta >= (uWait*2))
            dwLateStep += 1;
        uPrev += uWait;
        /* fixed frequency code goes here */
        /*  along with some type of break when done */
    }

    timeEndPeriod(1);                   /* restore period */
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • Please use timeBeginPeriod judiciously: https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/ – Adrian McCarthy Mar 20 '15 at 18:16
  • @AdrianMcCarthy - The example method is basically what some games use that need a physics engine that runs at a fixed frequency. Most games are going to consume continuous cpu and graphics power anyway, so setting the ticker to 1khz isn't going to affect things much. – rcgldr Mar 20 '15 at 20:23
  • Except the timeBeginPeriod affects the global timer, so every process might consume more resources, not just this one. For most modern machines, QueryPerformanceCounter will give you high precision results without increasing the base timer frequency, so the only thing you're buying is the ability to Sleep for approximately 1 ms. And since everything else is now waking up more often, your thread might not actually be scheduled right away after the Sleep anyway. I'd ditch the timeBeginPeriod, sleep only if the wait is > 16 ms, and just busy wait (as you're doing) for the remainder. – Adrian McCarthy Mar 20 '15 at 20:32
  • @AdrianMcCarthy - in a game situation, the physics thread's priority will be set to high, and the sleeps are there to keep from using 100% of a core and in the case of a single core, from locking out the normal priority threads also used by the game and the normal priority processes used by Windows. Note that the example frequency of 400hz translates into 2.5 ms. As an alternative, a [multi media timer](http://msdn.microsoft.com/en-us/library/windows/desktop/dd743609%28v=vs.85%29.aspx) could be used, but this still involves timeBeginPeriod(), so might as well use Sleep(). – rcgldr Mar 20 '15 at 21:05