views:

249

answers:

5

I'm trying to track frames per second in my game. I don't want the fps to show as an average. I want to see how the frame rate is affected when I push keys and add models etc. So I am using a variable to store the current time and previous time, and when they differ by 1 second, then I update the fps.

My problem is that it is showing around 33fps but when I move the mouse around really fast, the fps jumps up to 49fps. Other times, if I change a simple line of code elsewhere not related to the frame counter, or close the project and open it later, the fps will be around 60. Vsync is on so I can't tell if the mouse is still effecting the fps.

Here is my code which is in an update function that happens every frame:

FrameCount++;
currentTime = timeGetTime ();
static unsigned long prevTime = currentTime;
TimeDelta = (currentTime - prevTime) / 1000;
if (TimeDelta > 1.0f)
{
 fps = FrameCount / TimeDelta;
 prevTime = currentTime;
 FrameCount = 0;
    TimeDelta = 0;
}

Here are the variable declarations:

int FrameCount;
double fps, currentTime, prevTime, TimeDelta, TimeElapsed;

Please let me know what is wrong here and how to fix it, or if you have a better way to count fps. Thanks!!!!!!

I am using DirectX 9 btw but I doubt that is relevant, and I am using PeekMessage. Should I be using an if else statement instead? Here is my message processing loop:

MSG msg;
ZeroMemory (&msg, sizeof (MSG));

while (msg.message != WM_QUIT)
{
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    Update ();
    RenderFrame ();
}
+1  A: 

This is a sign that your message processing loop is blocking instead of peeking or polling, as the fps increases as you receive more mouse messages. You should consider using PeekMessage instead of GetMessage.

EDIT: Also, if you feel like hogging the CPU, you can also add PM_NOYIELD so that the system won't allow other threads to execute during PeekMessage. From PeekMessage's documentation:

You can optionally combine the value PM_NOYIELD with either PM_NOREMOVE or PM_REMOVE. This flag prevents the system from releasing any thread that is waiting for the caller to go idle (see WaitForInputIdle).

MSN
I would like to post my message processing loop. But I can't get the code to format in these comment boxes. Do I have to format it differently than in the question boxes?
rmetzger
@rmetzger, just add it to the original question post.
MSN
A: 

More of a side note than an answer to your problem, but you say you don't want to average the framerate, however you're effectively averaging it over a second by calculating it like that. If you want to have the framerate updated every frame, you might want to try something like:

currentTime = timeGetTime();
fps = 1000.0f / (currentTime - prevTime);
prevTime = currentTime;

Though timeGetTime is going to start to be a bit inaccurate at this point, as the numbers are likely to be small. QueryPerformanceCounter might be a better timer to use.

James Sutherland
The 1 second average is so it doesn't update on the screen faster than I can read it. I just don't want to take the average fps since the start of the program, or multiply by some factor to scale it. For example, I saw this in another thread:"You need a smoothed average, the easiest way is to take the current answer (the time to draw the last frame) and combine it with the previous answer.time = time * 0.9 + last_frame * 0.1"Unless I am misunderstanding this, doesn't this combine the last fps with the average of all fps?
rmetzger
Sorry about the formatting above. I don't know why it won't let me do a block quote or code formatting.
rmetzger
The average you're describing there is a weighted average which will closely track the latest timings, but will also be always affected by spikes early on in the process. I wouldn't worry about your timing code though, as it's fine for your purposes. Perhaps increase the update rate to twice a second, or draw it as a bar graph to more easily see the effects.
Kylotan
A: 

Concerning your message processing loop, yes you should use an if-else statement like so.

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
    TranslateMessage (&msg);
    DispatchMessage (&msg);
} 
else
{
    Update ();
    RenderFrame ();
}

Otherwise only one message per frame would be processed, which would result in serious input-lag if the frame takes a long time to render.

Concerning your FPS readings it's not much to go on, any number of things could affect it. The fps counter code looks like it should be performing it's purpose (but with some loss of precision)..

Is the mouse controlling the camera? If so, are you sure it's the mouse input that cause the fps increase and not what direction you are facing?

Are you absolutely sure that your fps code is only run once per frame?

Do you handle input somewhere? If so what happens if you disable that code and move the mouse fast then? Still the same?

Daniel Dimovski
Well I am now using the if-else statement. I am positive I only update the fps counter once per frame. I was using the arrow keys to move my camera around before. I commented out the key processing code and the fps did not change. I do not get or handle mouse input in my program anywhere. My fps counter is showing between 31-34 fps. Yet when I move the mouse, it still jumps up to 48-50.I'm not sure if this is related, but when I draw a model, my fps is between 40-48 and is very inconsistent. And when I move the mouse, the fps goes to 48-50 again.
rmetzger
+1  A: 

timeGetTime() is inaccurate. Use the high performance counter instead.

bobobobo
A: 

About the message loop - I advise peeking for messages until you're not getting any and then rendering a frame.

Pseudo:

bool renderFrame = true; if (PeekMessage(...)) { // Handle it. renderFrame = false; }

if (renderFrame) render your frame

otherwise exit the message loop function (and enter it again, or solve it with a while, depends a bit on how you've structured the rest of your mainloop

nj