GP2X Timing A Game Loop


RiX0R

Idler-Inside
Joined
Sep 20, 2005
Messages
294
Website
rix0r.nl
Hey all,

Here's another "What's the current best practice" question from me:

What's the best way to time a game loop? I'm looking for a call like Windows' timeGetTime: reasonably cheap (timeGetTime returns a DWORD, no fancy floats or int64s) and times accurately to the millisecond. Better resolution is also fine, but I don't really want to go lower than milliseconds (so time() is out of the question with its one-second resolution).

I'm looking for something similar on Linux, something that's also supported on the GP2X obviously, and something that's not too heavy-handed. There's gotta be a cheap tick-timer somewhere... I just don't know what it's called.

And in case you're wondering, sleeping won't cut it. I want to time my loop independently of how long a cycle takes, and skip frames if drawing is too slow. Plus, if you calculate your sleep for a certain framerate, your framerate will actually be lower because a cycle does not actually take (sleeptime) but (looptime + sleeptime).

So what are you using?
 
Use gettimeofday() or the gp2x's timer. There's plenty of information on how to use it in the docs, check out page 47 in MMSP2 Databook.
 
You could try ftime,
Code:
SYNOPSIS
       #include <sys/timeb.h>

       int ftime(struct timeb *tp);

DESCRIPTION
       Return current date and time in tp, which is declared as follows:

                 struct timeb {
                      time_t   time;
                      unsigned short millitm;
                      short    timezone;
                      short    dstflag;
                 };

       Here time is the number of seconds since the epoch, millitm is the num-
       ber of milliseconds since time seconds since the epoch, timezone is the
       local time zone measured in minutes of time west of Greenwich, and dst-
       flag is a flag that, if nonzero, indicates that  Daylight  Saving  time
       applies locally during the appropriate part of the year.


pertch: gettimeofday() is what I was originally thinking of - couldn't remember what it ws called.
 
What I'm worried about with gettimeofday, is if it isn't going to be too expensive to use in a XX fps gameloop.

It seems to have timezone calculation and microsecond resolution. Plus, it returns data in a struct, and not really in a readily usable format.

But I'll give it a try. Thanks.
 
gettimeofday isn't too slow - especially if the next thing you're going to do is sit and wait until the end of the frame!

At some point I'd like to look at getting access to the vsync interrupt. I'm not 100% sure, but it might be exposed by fbdev - I don't know which way fbdev went on this. In theory you ought to be able to sleep waiting for activity on a device, and get woken up pretty quickly on the interrupt.

Having a vblank counter would be useful too of course. If it's not available, and I make a kernel module to do it, I also thought of allowing you to get the kernel to call trivial user code without rescheduling threads - very much like servicing and interrupt, you'd be restricted (heavily) in what you could do from such code, but it could work well for trivial routines that urgently need to be called quickly (e.g. triple buffering, aka scroll-on-vblank).
 
At some point I'd like to look at getting access to the vsync interrupt. I'm not 100% sure, but it might be exposed by fbdev - I don't know which way fbdev went on this. In theory you ought to be able to sleep waiting for activity on a device, and get woken up pretty quickly on the interrupt.

Having a vblank counter would be useful too of course. If it's not available, and I make a kernel module to do it, I also thought of allowing you to get the kernel to call trivial user code without rescheduling threads - very much like servicing and interrupt, you'd be restricted (heavily) in what you could do from such code, but it could work well for trivial routines that urgently need to be called quickly (e.g. triple buffering, aka scroll-on-vblank).
It would be nice to have vsync on an interrupt. It isn't in the (currently) released fbdev - I hope they fix it, because as it stands fbdev is crippled beyond belief (it doesn't even support 8bit even though it's trivial to add). Adding a hsync interrupt would be nice too - just to count how many lines since the last vsync.
 
Last edited by a moderator:
The fbdev driver isn't compiled as a module, so it's untouchable unless you're using a custom kernel. At this point I'm not sure that it's worth improving the fbdev driver anyway, as nobody is using it any more. I mean, SDL and Allegro are better off knowing exactly what the GP2X is capable of, so they wouldn't benefit from better kernel support for things they can already do - we wouldn't want to revert back to plain fbdev code now that we have something better.

Other libraries would benefit, but until any come along there's not much point in doing anything to fbdev. Even then, whoever wants to port a new library is unlikely to touch fbdev - like all of us, they'd probably just bin it and write their own mode setting code, it's not that hard and there are plenty of references now.
 
gettimeofday isn't too slow - especially if the next thing you're going to do is sit and wait until the end of the frame!

I'm not. I'm going to draw as many FPS as I can, and interpolate based on time delta. So the most efficient call would be best, as it gives the smoothest animation.
 
Last edited by a moderator:
Personally, I'm partial to just having the main program loop function not do anything unless a certain # of ticks have not passed since the last time it was allowed to fully run. You can grab the time the program's been running in milliseconds with SDL_GetTicks ();

e.g.:

long int gLastFrameTime = 0;

void MainLoop()
{
if (SDL_GetTicks() > (gLastFrameTime + 16.667))
{
gLastFrameTime = SDL_GetTicks ();
// do stuff
}
}

EDIT: fixed a mistake.
 
Personally, I'm partial to just having the main program loop function not do anything unless a certain # of ticks have not passed since the last time it was allowed to fully run.

So you don't not want it to do nothing after the first frame? :p

SDL_GetTicks ();

Hey, I guess that's exactly what I was looking for! Thanks!


On a PC I would never do that because it would eat CPU cycles without actually doing anything useful (not even rendering a frame), but you're right: the GP2X is mostly singletasking so we can get away with it.

Still, I want to get as high a framerate as possible, so I think I'll go for something like this:

Code:
unsigned long oldTime = SDL_GetTicks();

while (true) {
    unsigned long newTime = SDL_GetTicks();
    unsigned long delta   = newTime - oldTime;
    oldTime = newTime;
    
    int x = x0 + speed * delta;
    int y = y0 + speed * delta;
    drawObject(x, y);
}


Edit: fix.
 
Last edited by a moderator:
Back
Top