Advertisement

FPS

Started by December 21, 2000 07:06 PM
4 comments, last by alex mcandrew 24 years, 1 month ago
I''ve seen so many people''s demos with a FPS counter. Any idea on how I can implement one in my program?
--------------------Help Needed!Turn-based 20th century strategy wargameTitle still to be determined

// very simple really!


// ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
// FUNCTION NAME: ShowFrameRate ()
// FUNCTION DESCRIPTION: Shows frame rate
VOID ShowFrameRate ( int x, int y, COLORREF color)
{
static float fFPS = 0.0f;
static float fLastTime = 0.0f;
static DWORD dwFrames = 0L;

// Keep track of the time lapse and frame count
FLOAT fTime = timeGetTime() * 0.001f;
++dwFrames;

// Update the frame rate once per second
if( fTime - fLastTime > 1.0f )
{
fFPS = dwFrames / (fTime - fLastTime);
fLastTime = fTime;
dwFrames = 0L;
}

// Setup the text buffer to write out dimensions
TCHAR buffer[80];
sprintf( buffer, "Frames per second %7.02f fps ", fFPS );
DDTextOut ( m_pDDBackBuffer, buffer, x,y, color);

} //-------------------------------------------------------------







VOID DDTextOut ( LPDIRECTDRAWSURFACE7 lpdds, char* text, int x,
int y,
COLORREF textcolor )
{
HDC hdc;
HRESULT hRet;
char buffer[256];

hRet = lpdds->GetDC ( &hdc );

sprintf ( buffer, text );
SetBkMode ( hdc, TRANSPARENT );
SetTextColor ( hdc, textcolor );
TextOut ( hdc, x, y, buffer, strlen ( buffer ));

hRet = lpdds->ReleaseDC ( hdc );

}





if ( there''''s a will )
return ( there''''s a way );
Advertisement
Search this forum for FPS, I posted a digitally filtered framerate algo a month or so ago.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
I spent some time recently looking at the best timing method to use for calculating FPS and making my animation/sprite updates last-frame-time-dependent (sorry - I'm sure there's a proper phrase for this, but I don't know what it is!)

I searched Gamedev for 'FPS' and there is a lot of information out there. Unfortunately a lot of it is confusing or contradictory. After reading through it all and consulting MSDN I've got my timing routines working nicely. I'll attempt to explain the different methods used and what I see as the strengths and weaknesses of each, along with my code. I must point out that i'm very new to c++/DirectX/game programming, so if anyone spots a glaring error/bad code please point it out to me. I won't be offended.

The three methods I commonly see used to measure frame rate:

1. GetTickCount()
2. Multimedia Timer ( timeGetTime() )
3. High-Resolution Timer ( QueryPerformanceFrequency()/QueryPerformanceCounter() )

1. GetTickCount() - This function returns a DWORD containg the number of milliseconds since the system was started. It's ok for calculating FPS, but is crap for doing any kind of frame-by-frame timing because it has a very low resolution.

2. Multimedia Timer - I've seen a lot of people using timeGetTime() in place of GetTickCount(). It also returns a DWORD containing the number of milliseconds since the system was started. However, I found that the resolution is just as bad as GetTickCount() unless you change the frequency of the timer, which is something I've never seen mentioned elsewhere. To change the resolution you use:
MMRESULT timeBeginPeriod(UINT uPeriod);
before you start using the timer and then, when you're finished you use:
MMRESULT timeEndPeriod(UINT uPeriod);
I tried timeBeginPeriod(1) to set the resolution of the timer to 1 millisecond and it seemed to work ok. The resolution definitely improved. However, I think it's bad practice to just pass a constant like that. I think you are supposed to check the machine's device caps first (See MSDN for more info) I'm also guessing that the multimedia timers use the High Res timer mentioned next, but I could be wrong about that.

3. High-Resolution Timer - This is the method that I've chosen to use. It requires that the hardware supports a high-resolution performance counter, but it works fine on an old P166 so I don't think you'll have any compatibility problems. The other problem is that you need to use 64-bit integers, but MSVC has built-in support for them and they're easy enough to understand (again, check MSDN for details)
The High-Res timer requires the use of the following two functions:

BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

QueryPerformanceFrequency returns the number of counts per second for the system. Get the current count using QueryPerformanceCounter and then divide this result by the Frequency to get the result in seconds.

_______________________________________________________________


I now use the high-res performance counter and everything works very well. Below is my timer class (don't worry if you don't use classes, you can easily adapt the code), along with the code I use to calculate the FPS. This code is actually part of my DirectDraw class. I call it whenever I Flip(), so it's called once per frame. Again, you could easily adapt the code for your own needs:

        // This is the timer .h file#ifndef M_HIGH_PERFORMANCE_TIMER#define M_HIGH_PERFORMANCE_TIMERclass cMTimer{public:	cMTimer();	double	GetTime(void);private:	double	Frequency;};#endif// This is the timer .cpp file#define WIN32_LEAN_AND_MEAN#include <windows.h>#include "m_Timer.h"cMTimer::cMTimer(){	LARGE_INTEGER	TempFreq; // 64-bit integer	// Get the high-resolution performance timer frequency	QueryPerformanceFrequency(&TempFreq); 	// Convert to double and divide by 1000 so that GetTime() returns milliseconds	Frequency = (double)TempFreq.QuadPart / 1000.0;}double cMTimer::GetTime(void){	LARGE_INTEGER	TempCount; // 64-bit integer	// Get the high-res performance timer count	if (QueryPerformanceCounter(&TempCount))	{		// Divide by frequency to return time in milliseconds		return ((double)TempCount.QuadPart/Frequency);	} else {		// False return from QueryPerformance counter means no high res performance timer		//  support, so resort to GetTickCount() instead		return ((double)GetTickCount());	}}/*Here's how I calculate the FPS.  All variables starting withDD_ are members of the class, so just think of them as globalvariables.DD_Timer is my Timer class object.  The other variable namesshould be logical enough for you to work out what's going on.This method is just called once every frame.  When I want to getthe FPS I just get the value in DD_FramesLastSec.  The onlyother thing I do is initialise DD_TimerLastFrame to the currentGetTime() value, so that the program doesn't start off with amassive "frame tick" due to DD_TimerLastFrame being 0.*/void cMDirectDraw::UpdateTimer(void){	double CurrentTimer;		CurrentTimer = DD_Timer.GetTime();	// Number of ticks since the last Flip()	DD_TicksLastFrame = CurrentTimer - DD_TimerLastFrame;	DD_TimerLastFrame = CurrentTimer;	// has a second elapsed?	if (CurrentTimer - DD_TimerLastSec > 1000)	{		// if so, save the number of frames and reset counter		DD_FramesLastSec = DD_FramesSoFarThisSec;		DD_FramesSoFarThisSec = 0;		DD_TimerLastSec = CurrentTimer;	} else {		DD_FramesSoFarThisSec++;	}}        


Phew, this has been one hell of a post. I hope this helps fellow newbies. If anyone out there sees something wrong with my code/approach please let me know.

EDIT: Oops, forgot to mention that if you want to use timeGetTime and the other multimedia timer functions then you'll have to #include <mmsystem.h>. You can just #include <windows.h> if you like, but make sure that you don't have WIN32_LEAN_AND_MEAN defined because otherwise the compiler will skip the mulitmedia stuff when it compiles the windows header.

Moot


Edited by - Moot on December 22, 2000 8:35:20 AM
Thanks again Myself. You have once again solved my problem. Magmai, thanks but Myself''s code works well enough for me, so I don''t really need anything else.

Moot...wow! That''s a bit too complex for me. Thank you though.
--------------------Help Needed!Turn-based 20th century strategy wargameTitle still to be determined
And it was a lot less complicated than Moot's :p

    DWORD CGameEngine::CalcFrameRate(LARGE_INTEGER Now_us, float* FrameRate)	{	static float e = 2.718281828f;	static float filter = (float)pow(e, -2.0f * 0.5f / 1000.0f); //0.5Hz filter, time in ms, so /1000.0	static LARGE_INTEGER timesnap_us;	static float framerate= 33.3f;//guess at initial framerate, so it doesn't lag so bad on init	DWORD elapsed_ms = (Now_us.QuadPart - timesnap_us.QuadPart) /1000;	timesnap_us = Now_us;	float factor = (float)pow(filter, (float)elapsed_ms);	float ifactor = 1.0f - factor;	if(elapsed_ms==0.0f)		framerate = 33.0f;	else		framerate = framerate * factor + ifactor * 1000.0f / (float)elapsed_ms;//filter, *1000.0f to convert ms to sec (again)		//framerate = 1000.0f /(float)elapsed; //crappy twiddle		if(FrameRate)		*FrameRate = framerate;	return(elapsed_ms);	}    


Edited by - Magmai Kai Holmlor on December 24, 2000 1:33:50 AM

Edited by - Magmai Kai Holmlor on December 24, 2000 1:34:27 AM
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

This topic is closed to new replies.

Advertisement