Archived

This topic is now archived and is closed to further replies.

doogle

Jumpy FPS

Recommended Posts

My code to work out time between frames almost works... it's fine except for "jumps" every 10 or 20 seconds, where all movement advances about 10 times as quickly as it should (just for one frame) before returning to normal. For example, I'll be walking along and suddenly I'm about 100m ahead of where I should be. Heres the code for it:
LARGE_INTEGER start, end, freq;
 
QueryPerformanceFrequency(&freq);
 
const float dtime() {	
  double t = -(((double)end.QuadPart-(double)start.QuadPart) / (double)freq.QuadPart) * 200000.0f;
  return (float)t;
}
Any ideas as to what could be causing this? My best guess is a rounding error somewhere, so I tried changing the floats to doubles, but it didn't help. [edited by - doogle on October 5, 2003 10:33:20 PM]

Share this post


Link to post
Share on other sites
Ah yeah, my guess is to perform the subtraction befor you convert to doubles, as the 64 bit number is *HUGE*, and the subtraction will bring the numbers down to a size managable by us mere mortals and floating point representation. The frequency should allready be a nice managably low number, so its allright to convert it straight.

Note: I''m talking out my ass here, as I really don''t know how big a number a double could accuratly represent, I think it would get the magnitude right, but I don''t know if it would have enough significant digits to represent the 64 bit number in full.

Share this post


Link to post
Share on other sites
hmm my first thought was that its not your code causing this sort of error, i have the same behavior in battlefield (orginal without patches) when i enable tripplebuffer, disabling it by setting the prerender frames to 0 (nvidia driver option) i was able to remove it, but it could be offtopic in your case (i cant see how your code should cause it)


T2k

Share this post


Link to post
Share on other sites
I remember hearing of an old bug in QueryPerformanceXXX where the counter would jump by several seconds instead of msecs. The solution was to keep a low resolution timer also and if the two differed by too much, assume QueryPerformanceCounter() bugged out.

A quick search revealed this. They claimed it occurs under win2000 sp1 with certain motherboards.

EDIT:

double t = -(((double)end.QuadPart-(double)start.QuadPart) / (double)freq.QuadPart) * 200000.0f;


What's up with this equation? You seem to be getting times in increments of 5 microseconds, and returning a negative value at that.

Here is some code that measures time in milliseconds:

measuredTime = (unsigned int) ((double) ((curTime.QuadPart - startTime.QuadPart) * 1000) / (double) (freq.QuadPart) + 0.5);


[edited by - jermz on October 6, 2003 12:35:40 PM]

Share this post


Link to post
Share on other sites
Thanks for the replies

That equation was negivite as a quick fix for walking backwards instead of forwards... heh

I couldn''t get your equation to work jermz, it just gave 0. And I''m using Win XP, not 2000... hmmm

Share this post


Link to post
Share on other sites
Heres a basic timer class I''ve used. You start it and then read out the time since then...


#define MIL_FROM_100NAN_CONV 10000

/////////////////////////////////////////////////////////////////////

// WWSTPTimer - Class used to time events

/////////////////////////////////////////////////////////////////////

class WWSTPTimer
{
private:

LARGE_INTEGER startTime;
LARGE_INTEGER freq;
unsigned int measuredTime;
bool started;
bool HPT;

public:

WWSTPTimer();
void clearTimer();
void startTimer();
unsigned int getTime();

};

////////////////////////////////////////////////////////////////////

// Constructs a timer object, using high precision (~1ms) if

// available or more coarse (~10ms) if not

////////////////////////////////////////////////////////////////////

WWSTPTimer::WWSTPTimer()
{
// use high precision timer if available by checking that

// QueryPerformancCounter and QueryPerformanceFrequency are available

HPT = false;
if ( QueryPerformanceCounter( &freq ) )
if ( QueryPerformanceFrequency( &freq) )
HPT = true;

measuredTime = 0;
started = false;
}

////////////////////////////////////////////////////////////////////

// Stops a timer and clears measured time.

////////////////////////////////////////////////////////////////////

void WWSTPTimer::clearTimer()
{
measuredTime = 0;
started = false;
}

////////////////////////////////////////////////////////////////////

// Starts measuring a time period.

////////////////////////////////////////////////////////////////////

void WWSTPTimer::startTimer()
{
if (HPT)
{
// read in intial counter

QueryPerformanceCounter(&startTime);
}
else
{
// read in initial time

FILETIME fileTime;

GetSystemTimeAsFileTime(&fileTime);

startTime.QuadPart = fileTime.dwHighDateTime;
startTime.QuadPart = startTime.QuadPart << 32;
startTime.QuadPart += fileTime.dwLowDateTime;
}

started = true;
}

////////////////////////////////////////////////////////////////////

// Calculates the time in the interval since this timer was started.

// This can actually be called multiple times since a timer was

// started, each call would update the measured time.

////////////////////////////////////////////////////////////////////

unsigned int WWSTPTimer::getTime()
{
LARGE_INTEGER curTime;

if (!started) return 0;

if (HPT)
{
// read in current counter and calc measured time

QueryPerformanceCounter(&curTime);

// this would be ideal formula but integer division always truncates

// measuredTime = (unsigned int) ((curTime.QuadPart - startTime.QuadPart) * 1000 / freq.QuadPart);


// this formula casts to double and adds 0.5 before dividing to overcome truncation

measuredTime = (unsigned int) ((double) ((curTime.QuadPart - startTime.QuadPart) * 1000) / (double) (freq.QuadPart) + 0.5);

// this formula should work solely using integer math, but its 64 bit!

// measuredTime = (unsigned int) ((1000 * (curTime.QuadPart-startTime.QuadPart) + (freq.QuadPart>>1)) / freq.QuadPart);

}
else
{
// read in current time and calculate measured time

FILETIME fileTime;

GetSystemTimeAsFileTime(&fileTime);

curTime.QuadPart = fileTime.dwHighDateTime;
curTime.QuadPart = curTime.QuadPart << 32;
curTime.QuadPart += fileTime.dwLowDateTime;

measuredTime = (unsigned int)((curTime.QuadPart - startTime.QuadPart) / (ULONGLONG) MIL_FROM_100NAN_CONV);
}

return measuredTime;
}

Share this post


Link to post
Share on other sites
Well, I found my problem


//main loop

while(running) {
QueryPerformanceCounter(&start);

//draw and update


QueryPerformanceCounter(&end);
}


Which is why I got a negitive time (and thus the - sign in there), and why I multiplied it by such a big number... hehe... annoying.

It looks way worse now though - time is either 1 or 0 by the looks of it. And my mouselook seems to stop time... crazah, but I'll work it out

EDIT: and just for the record... moving the mouse stopped time because the game isnt updated if win messages need dealling to.. fixed. Doogle out

[edited by - doogle on October 8, 2003 2:07:10 AM]

Share this post


Link to post
Share on other sites