Timing and Frames Per Second

  CU_MDX_Timer.zip (63.5 KiB, 2,620 hits)


  CUnitFramework.zip (101.1 KiB, 20,514 hits)

Extract the C-Unit Framework
inside the project (not solution) directory.

The C-Unit Framework provides a high resolution timer for use in you applications. Timing is necessary because faster computers can process more game loops than slower computers. Therefore, we should update_ 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 frame rate of our demos, which gives us a good performance rating. To manage all the timing functionality, the C-Unit Framework has a timing class called, Timer. The calculations in Timer 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, mine’s an old Pentium 4 1.8 GHz and I still have support for the timer). If you want to support older computers, you would want to fallback on the Windows timer function, timeGetTime, if there was no hardware support. However, I don’t do that in this tutorial.

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport(“kernel32”)]
public static extern bool QueryPerformanceFrequency( ref long PerformanceFrequency );

[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport(“kernel32”)]
public static extern bool QueryPerformanceCounter( ref long PerformanceCount );

To create_ our timer, we will need access to a couple of native 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 current value is set to.

To gain access to these functions, we need to add them to our NativeMethods class.

namespace CUnit
{
/// Timing and frames per second class
public class Timer
{
private long m_ticksPerSecond;
private long m_currentTime;
private long m_lastTime;
private long m_lastFPSUpdate;
private long m_FPSUpdateInterval;
private uint m_numFrames;
private float m_runningTime;
private float m_timeElapsed;
private float m_fps;
private bool m_timerStopped;

/// Creates a new Timer
public Timer() Toggle
{
// Find the frequency, or amount of ticks per second
NativeMethods.QueryPerformanceFrequency( ref m_ticksPerSecond );

m_timerStopped = true;
// Update the FPS every half second.
m_FPSUpdateInterval = m_ticksPerSecond >> 1;
}


/// Starts the timer.
public void Start() Toggle
{
if ( !Stopped )
{
return;
}
NativeMethods.QueryPerformanceCounter( ref m_lastTime );
m_timerStopped = false;
}


/// Stops the timer.
public void Stop() Toggle
{
if ( Stopped )
{
return;
}
long stopTime = 0;
NativeMethods.QueryPerformanceCounter( ref stopTime );
m_runningTime += (float)(stopTime – m_lastTime) / (float)m_ticksPerSecond;
m_timerStopped = true;
}


/// Updates the timer.
public void Update() Toggle
{
if ( Stopped )
{
return;
}

// Get the current time
NativeMethods.QueryPerformanceCounter( ref m_currentTime );

// Update time elapsed since last frame
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;
}


/// Is the timer stopped?
public bool Stopped Toggle
{
get { return m_timerStopped; }
}


/// Frames per second
public float FPS Toggle
{
get { return m_fps; }
}


/// Elapsed time since last update. If the timer is stopped, returns 0.
public float ElapsedTime Toggle
{
get
{
if ( Stopped )
{
return 0;
}
return m_timeElapsed;
}
}


/// Total running time.
public float RunningTime Toggle
{
get { return m_runningTime; }
}

}
}

The Timer 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 Timer.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.

m_gameStates.OnUpdateFrame( m_graphics.Device, m_timer.ElapsedTime );
m_gameStates.OnRenderFrame( m_graphics.Device, m_timer.ElapsedTime );

When the Framework updates and renders a frame, it sends the elapsed time to the executing GameState, which allows us to keep a consistant animation speed.