Chad Vernon
  • Home
  • Reel/Resume
  • Work
  • Resources
  • About
  • Contact
sideBar

Search

Categories

  • CG
  • cvxporter
  • Maya
    • API
    • Plug-ins
  • Personal

Archives

  • September 2011
  • June 2011
  • March 2011
  • December 2010
  • November 2010
  • September 2010
  • August 2010
  • July 2010
  • May 2010
  • April 2010
  • March 2010
  • December 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007

Rss

  • Main Entries RSS
  • Comments RSS
Home » Resources » DirectX 9 » Timing and Frames Per Second

Timing and Frames Per Second

  CU_Timing.zip (27.5 KiB, 2,309 hits)

If you tried running the Transformation Tutorial on different computers, or if you resized the window, the objects may have moved at different speeds. This is because faster computers can process more game loops than slower computers. We can prevent this by updating our game based on how much time has passed since we rendered the last frame. This will create a constant experience over multiple systems. We can also use our timing information to calculate the framerate of our demos, which gives us a good performance rating. To manage all the timing functionality, we’ll create a new class, CTimer. The calculations in CTimer use the high performance hardware counter found in most modern computers. Older computers may not support the high performance counter but I’m assuming that the people reading this tutorial have a fairly decent computer (heck, mines from 2001). If you want to support older computers, you would want to use the Windows timer function, timeGetTime(), if there was no hardware support. However, I don’t do that in this tutorial.

#ifndef CTIMER_H
#define CTIMER_H
#include "stdafx.h" 

class CTimer
{
public:
    CTimer();
    void Start();
    void Stop();
    void Update(); 

    BOOL IsStopped() { return m_timerStopped; }
    float GetFPS() { return m_fps; }
    float GetRunningTime() { return m_runningTime; }
    float GetElapsedTime() { return m_timerStopped ? 0.0f : m_timeElapsed; } 

private:
    INT64 m_ticksPerSecond;
    INT64 m_currentTime;
    INT64 m_lastTime;
    INT64 m_lastFPSUpdate;
    INT64 m_FPSUpdateInterval;
    UINT m_numFrames;
    float m_runningTime;
    float m_timeElapsed;
    float m_fps;
    BOOL m_timerStopped;
};
#endif

The CTimer class has methods to Start, Stop, and Update to the counter. CTimer will also keep track of the total running time, the time elapsed between Update calls, and the application’s framerate. Some of the variables are of type INT64 because we’ll be needing 64 bits for those values.

#include “..\include\stdafx.h”
#include “..\include\CTimer.h”

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Default constructor.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
CTimer::CTimer() Toggle

{

QueryPerformanceFrequency( (LARGE_INTEGER *)&m_ticksPerSecond );

m_currentTime = m_lastTime = m_lastFPSUpdate = 0;
m_numFrames = 0;
m_runningTime = m_timeElapsed = m_fps = 0.0f;
m_FPSUpdateInterval = m_ticksPerSecond >> 1;
m_timerStopped = TRUE;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Starts the timer.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CTimer::Start() Toggle

{

if ( !m_timerStopped )
{

// Already started
return;

}
QueryPerformanceCounter( (LARGE_INTEGER *)&m_lastTime );
m_timerStopped = FALSE;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Stops the timer.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CTimer::Stop() Toggle

{

if ( m_timerStopped )
{

// Already stopped
return;

}
INT64 stopTime = 0;
QueryPerformanceCounter( (LARGE_INTEGER *)&stopTime );
m_runningTime += (float)(stopTime – m_lastTime) / (float)m_ticksPerSecond;
m_timerStopped = TRUE;

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Updates the timer. Calculates the time elapsed since the last Update call.
Updates the frames per second and updates the total running time.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CTimer::Update() Toggle

{

if ( m_timerStopped )
{

return;

}

// Get the current time
QueryPerformanceCounter( (LARGE_INTEGER *)&m_currentTime );

m_timeElapsed = (float)(m_currentTime – m_lastTime) / (float)m_ticksPerSecond;
m_runningTime += m_timeElapsed;

// Update FPS
m_numFrames++;
if ( m_currentTime – m_lastFPSUpdate >= m_FPSUpdateInterval )
{

float currentTime = (float)m_currentTime / (float)m_ticksPerSecond;
float lastTime = (float)m_lastFPSUpdate / (float)m_ticksPerSecond;
m_fps = (float)m_numFrames / (currentTime – lastTime);

m_lastFPSUpdate = m_currentTime;
m_numFrames = 0;

}

m_lastTime = m_currentTime;

}

To create our timer, we will use a couple of Windows methods: QueryPerformanceFrequency and QueryPerformanceCounter. The first function determines how many times per second your system’s counter fires. We need this value to calculate all of our timing values such as the time passed between frames and the frames per second. The second function determines what the counter’s value is currently set to.

The CTimer class include methods to Start, Stop, and Update the counter. Most of the code is pretty self-explanatory. To calculate the elapsed time since the last update, we need to get the difference between the current counter value and the counter value from the last update. To convert the result into seconds, we divide it by the number of ticks the counter fires per second. The total running time is simply updated each frame with the current elapsed time value.

Calculating the frames per second involves a few steps. First, to prevent the FPS from updating every frame, we need to store an FPS update interval. If we updated the FPS every frame, it would change too fast for us to see any single value. The update interval is set to half the counter frequency. This means the timer will perform the FPS calculation every half second. Second, we need a variable that counts the number of times the Update method is called. If we call Update every frame, it will represent the number of frames rendered. To calculate the FPS, we divide this frame counter by the time passed since the last time the FPS was calculated. Once the FPS is calculated, we reset the frame counter to 0 and repeat.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Updates the current frame.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CFramework::OnUpdateFrame()
{

if ( m_pTimer != NULL )
{

m_pTimer->Update();

}
if ( m_pGameApp != NULL && m_pGraphics != NULL && m_pTimer != NULL )
{

m_pGameApp->OnUpdateFrame( m_pGraphics->GetDevice(), m_pTimer->GetElapsedTime() );

}

}

With CTimer implemented, we can update our CFramework class to integrate our new timer class. We’ll need to access the timer when we update frames and when we render frames. As a result, we need to update the OnUpdateFrame and OnRenderFrame method definitions in the CBaseApp class to include a float that will hold the elapsed time from_ the timer. Shown above is the updated OnUpdateFrame method of the CFramework class. This method updates the timer and then calls the OnUpdateFrame method of its member CBaseApp instance. With the elapsed time passed through, our application-specific class, CGameApp, will be able to take advantage of this value. The OnRenderFrame is updated in much the same way.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Summary: Updates the current frame.
Parameters:
[in] pDevice – Pointer to a DIRECT3DDEVICE9 instance
[in] elapsedTime – Time elapsed since last frame
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CGameApp::OnUpdateFrame( LPDIRECT3DDEVICE9 pDevice, float elapsedTime )
{

// Rotate
m_transform.RotateRel( 0.0f, 3.14f * elapsedTime, 0.0f );

}

In the OnUpdateFrame and OnRenderFrame methods of CGameApp, we now have access to the elapsed time between frames. We will use this value to control how much our geometry should animate. By multiplying the animation value by the elapsed time, the animation will be scaled depending on how much time has passed since the last frame update. With this in mind, we now specify our animation values in terms of units per second. In the above example, I rotate the geometry 3.14 radians (360 degrees) per second.

Having this elapsed time value will be crucial when working with keyframe and skeletal animations.

Laters, C

No Responses to “Timing and Frames Per Second”

Subscribes to this topic Comment RSS or TrackBack URL

Leave A Reply

Allowed tag : <blockquote>, <p>, <code>, <em>, <small>, <ul>, <li>, <ol>, <a href=>..

 Username

 Email Address

 Website

Sticky: Always double check your comment before posting Please Note: Comment Moderation Maybe Active So There Is No Need To Resubmit Your Comments
Home » Resources » DirectX 9 » Timing and Frames Per Second

© 2011 Chad Vernon