tags:

views:

155

answers:

2

What is a good way to get an accurate framerate (frames per second) in native windows opengl c++?

+2  A: 

Here's a timer class I used to use back in the day, in an ATL project. Haven't done C++ or opengl for awhile, but maybe this will give you some ideas:

Usage

// Put this in your class somewhere
CTimer m_timer;

// Initialize the timer using
m_timer.Init();

// Call this everytime you call draw your scene
m_timer.Update();

// Call this to get the frames/sec
m_timer.GetFPS();

Timer Class

// Timer.h: Timer class used for determining elapsed time and 
//              frames per second.
//
//////////////////////////////////////////////////////////////////////

#ifndef _E_TIMER_H
#define _E_TIMER_H

#pragma once

//////////////////////////////////////////////////////////////////////
// INCLUDES
//////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <stdio.h>
#include <math.h>

//////////////////////////////////////////////////////////////////////
// CLASSES
//////////////////////////////////////////////////////////////////////

class CTimer
{
private:
    //performance timer variables
    __int64       m_i64PerformanceTimerStart;
    __int64       m_i64PerformanceTimerElapsed;

    //multimedia timer variables
    unsigned long m_ulMMTimerElapsed;
    unsigned long m_ulMMTimerStart;

    //general timer variables
    __int64       m_i64Frequency;
    float         m_fResolution;
    bool          m_bPerformanceTimer;

    //FPS variables
    float m_fTime1;
    float m_fTime2;
    float m_fDiffTime;
    float m_fFPS;
    int m_iFramesElapsed;

public:

    //----------------------------------------------------------
    // Name:    CTimer::CTimer
    // Desc:    Default constructor
    // Args:    None
    // Rets:    None
    //----------------------------------------------------------
    CTimer( void )
        : m_fFPS(0.0f), m_fTime1(0.0f), m_fTime2(0.0f), m_fDiffTime(0.0f), m_iFramesElapsed(0)
    {   }

    //----------------------------------------------------------
    // Name:    CTimer::CTimer
    // Desc:    Default destructor
    // Args:    None
    // Rets:    None
    //----------------------------------------------------------
    virtual ~CTimer( void )
    {   }

    //----------------------------------------------------------
    // Name:    CTimer::Init - public
    // Desc:    Initiate the timer for the program
    // Args:    None
    // Rets:    bool:   -true: using performance timer
    //                  -false: using multimedia timer
    //----------------------------------------------------------
    bool Init( void )
    {
        //check to see if we are going to be using the performance counter
        if( QueryPerformanceFrequency( ( LARGE_INTEGER* )&m_i64Frequency ) )
        {
            //we are able to use the performance timer
            m_bPerformanceTimer= true;

            //get the current time and store it in m_i64PerformanceTimerStart
            QueryPerformanceCounter( ( LARGE_INTEGER* )&m_i64PerformanceTimerStart );

            //calculate the timer resolution
            m_fResolution= ( float )( ( ( double )1.0f )/( ( double )m_i64Frequency ) );

            //initialize the elapsed time variable
            m_i64PerformanceTimerElapsed= m_i64PerformanceTimerStart;
        }

        //we cannot use the performence counter, so we'll use the multimedia counter
        else
        {
            //we're using the multimedia counter
            m_bPerformanceTimer= false;

            m_ulMMTimerStart   = timeGetTime( );    //record the time the program started
            m_ulMMTimerElapsed = m_ulMMTimerStart;  //initialize the elapsed time variable
            m_fResolution      = 1.0f/1000.0f;
            m_i64Frequency     = 1000;
        }

        return m_bPerformanceTimer;
    }

    //----------------------------------------------------------
    // Name:    CTimer::Update - public
    // Desc:    Update the timer (perform FPS counter calculations)
    // Args:    None
    // Rets:    None
    //----------------------------------------------------------
    void Update( void )
    {
        //increase the number of frames that have passed
        m_iFramesElapsed++;

        if ( m_iFramesElapsed % 5 == 1 )
          m_fTime1 = GetTime( )/1000;

        else if ( m_iFramesElapsed % 5 == 0 ) 
        {
            m_fTime1 = m_fTime2;
            m_fTime2   = GetTime( )/1000;
            m_fDiffTime= ( float )fabs( m_fTime2-m_fTime1 );      
        }  

        m_fFPS= 5/( m_fDiffTime );



        /*m_fTime2   = GetTime( )/1000;
        m_fDiffTime= ( float )fabs( m_fTime2-m_fTime1 );
        if (m_fDiffTime > 1.0f)
        {
            m_fTime1 = m_fTime2;
            m_fFPS= m_iFramesElapsed / ( m_fDiffTime );
            m_iFramesElapsed = 0;
        }
        */
    }

    //----------------------------------------------------------
    // Name:    CTimer::GetTime - public
    // Desc:    Get the current time since the program started
    // Args:    None
    // Rets:    float: The time elapsed since the program started.
    //----------------------------------------------------------
    float GetTime( void )
    {
         __int64 i64Time;

        //check to see if we are using the performance counter
        if( m_bPerformanceTimer )
        {
            //get the current performance time
            QueryPerformanceCounter( ( LARGE_INTEGER* )&i64Time );

            //return the time since the program started
            return ( ( float )( i64Time - m_i64PerformanceTimerStart )*m_fResolution )*1000.0f;
        }

        //we are using the multimedia counter
        else
        {
            //return the time since the program started
            return ( ( float )( timeGetTime( ) - m_ulMMTimerStart )*m_fResolution )*1000.0f;
        }
    }

    //----------------------------------------------------------
    // Name:    CTimer::GetElapsedSeconds - public
    // Desc:    Get the elapsed seconds since the last frame was drawn.
    // Args:    elapsedFrames:
    // Rets:    float: The time elapsed since the program started.
    //----------------------------------------------------------
    float GetElapsedSeconds(unsigned long elapsedFrames = 1)
    {   return m_fDiffTime;     }

    //----------------------------------------------------------
    // Name:    CTimer::GetFPS - public
    // Desc:    Get the current number of frames per second
    // Args:    None
    // Rets:    float: the number of frames per second
    //----------------------------------------------------------
    inline float GetFPS( void )
    {   return m_fFPS;  }
};

#endif // _E_TIMER_H
Steve Echols
A: 

in c++, my favorite timer is the same as Steve suggests.

there may also be the issue of disabling vsync in your opengl app, for me it has always been on by default and you have to load some function to disable it.

as for a maybe more platform independent solution,

use time.h

I can't remember the function :( but it returns how long your app has been running in seconds, in that case just count the number of frames that have passed between seconds and that’s your fps (hypothetical function GetTime() )

// in your loop:

//////////

static int lastTime = GetTime();

static int framesDone = 0;

int currentTime = GetTime();

if(currentTime > lastTime)

{

     int fps = framesDone;

     framesDone = 0;

     lastTime = currentTime;

}

framesDone++;

/////////

but yeah, for windows the first answer is the best.

if you need help disabling vsync, let us know.

matt