Search code examples
c++windowsogre

timeGetTime() start variable is bigger than end variable


I am using timeGetTime() to limit the framerate to 60 frames per second. The way i intend to do that is get the time it takes to render said 60 frames and then use Sleep to wait the remainder of the second. But for some reason timeGetTime() is returning a way bigger number the first time i call it than when i call it after the 60 frames are rendered.

Here is the code:

Header

#ifndef __TesteMapa_h_
#define __TesteMapa_h_
#include "BaseApplication.h"
#include "Mundo.h"

class TesteMapa : public BaseApplication{
public:
    TesteMapa()
    virtual ~TesteMapa();

protected:
    virtual void createScene();

    virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
    virtual bool frameEnded(const Ogre::FrameEvent& evt);

    virtual bool keyPressed(const OIS::KeyEvent &evt);
    virtual bool keyReleased(const OIS::KeyEvent &evt);

private:
    Mundo mundo = Mundo(3,3,3);
    short altura, largura, passos, balanca, framesNoSegundo=0;
    Ogre::SceneNode *noSol, *noSolFilho, *noCamera;
    DWORD inicioSegundo = 0, finala;//inicioSegundo is the start variable and finala the ending variable
};
#endif 

CPP relevant function

bool TesteMapa::frameEnded(const Ogre::FrameEvent& evt){
    framesNoSegundo++;

    if (inicioSegundo == 0)
        inicioSegundo = timeGetTime();
    else{
        if (framesNoSegundo == 60){
            finala = timeGetTime(); //getting this just to see the value being returned
            Sleep(1000UL - (timeGetTime() - inicioSegundo));
            inicioSegundo = 0;
            framesNoSegundo = 0;
        }
    }
    return true;
}

I am using timeBeginPeriod(1) and timeEndPeriod(1) in the main function.


Solution

  • If you're using Visual Studio 2013 or older, std::chrono uses the 64hz ticker (15.625 ms per tick), which is slow. VS 2015 is supposed to fix this. You can use QueryPerformanceCounter instead. Here is example code that runs at a fixed frequency with no drift, since delays are based off an original reading of the counter. dwLateStep is a debugging aid that gets incremented if one or more steps took too long. The code is Windows XP compatible, where Sleep(1) can take up to 2 ms, which is why the code only does a sleep if there is 2 ms or more of time to delay.

    typedef unsigned long long UI64;        /* unsigned 64 bit int */
    #define FREQ    60                      /* frequency */
    DWORD    dwLateStep;                    /* late step count */
    LARGE_INTEGER liPerfFreq;               /* 64 bit frequency */
    LARGE_INTEGER liPerfTemp;               /* used for query */
    UI64 uFreq = FREQ;                      /* thread 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(&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 */