Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Question about Allegro timing and timing in general

This thread is locked; no one can reply to it. rss feed Print
Question about Allegro timing and timing in general
Locutus266
Member #7,638
August 2006

Hello Allegro communtiy!

I'd like some advice on timing. Recently, I developed a game using SDL (Simple DirectMedia Layer) which is another platform-independent C-library for game development. SDL incorporates a function called SDL_GetTicks() which has a similar functionality like the native Windows function "GetTickCount()". It returns the msecs since Windows was started.

Since I am now programming with Allegro, I have been missing such a function. I have installed the timer services and now use a callback function to control the speed of my game. This approach is actually a good thing and it works, but I don't want my game to consume 100% CPU load at any time. I'd rather limit the framerate to 85 fps for example and make the game sleep the rest of the time (using rest()). I could do this with vsync(), however this is not available with all graphics drivers, I guess and I want to be able to specify the desired framerate (and I mean framerate, not game speed).

Is there a way to implement this with timer interrupts?

Maybe a timer with BPS_TO_TIMER(1000) would simulate a counter like GetTickCount() but I don't think that would be good for performance.

I also thought about using the C-function "clock()", but I am not certain of its accuracy/granularity on different platforms.

Can you give me some advice on that?

Best regards,
Christoph

Elias
Member #358
May 2000

What works well is something like:

1#define FPS 100
2virtual int ticks;
3void ticker(void) {ticks++;}
4...
5install_int_ex(ticker, BPS_TO_TIMER(FPS));
6...
7frames = ticks
8while(1) {
9...
10 while (frames < ticks)
11 {
12 // put here what should be called FPS times per second
13 frames++;
14 }
15 if (gframe != frames)
16 {
17 gframe = frames;
18 // put here code to render current frame
19 }
20 rest(1) // This is all that will be executed in the loop until
21 // ticks gets increased, so there will be 0% CPU usage
22...
23}

The 4.3 branch of Allegro has a function al_get_ticks() like the SDL one, you could push for it getting backported into the Allegro 4.2.1 release.

--
"Either help out or stop whining" - Evert

Locutus266
Member #7,638
August 2006

Hello Elias,

thanks for your quick reply.

I think your approach is great. There's just one thing about it: I think, that one single call to rest() would be much more efficient than several calls with only one msec CPU time to yield.

Of course, that's the main problem, namely that without a function like al_get_ticks() you cannot calculate how much time to sleep until the next frame is to be drawn, or can you? I guess, in version 4.3.0 this portion of code would do:

1#define FPS 120
2 
3frame_time = 1000.0f / FPS; //How long a frame is displayed
4 
5while(!game_over)
6{
7now = al_get_ticks();
8next_frame = now + frame_time;
9 
10blit(screen_buffer, screen);
11 
12keyboard_polling();
13do_logic(); //Pending game logic updates for next frame.
14 
15if (next_frame > al_get_ticks()) //If current frame render didn't take longer than frame_time
16 rest(next_frame - al_get_ticks());
17}

Elias said:

The 4.3 branch of Allegro has a function al_get_ticks() like the SDL one

- I think that's one important function and I am glad that this is supported in newer versions. Unfortunately as of now I am bound to use Allegro 4.2.0 (since I am using a specialized version of Allegro for the Linux GP2X homebrew handheld), which isn't available to me as a newer version, yet. Thanks for the info, though.

Regards,
Christoph B.

P.S.: Sorry for posting in the wrong category in the first place. This wasn't meant as a feature request.

Kris Asick
Member #1,424
July 2001

What I do with my realtime engine is install a timer set to 2400 ticks a second, and the timer routine itself is just one simple addition command. I then have a sync command called every frame which resets the tick count and divides the ticks by a constant related to the 2400 ticks to get the amount of time passed, as a floating point number, in seconds, since the last time my sync command was called.

This is probably similar to how al_get_ticks() works.

I chose 2400 because it's the easiest number to match to a wide variety of fixed framerates based on monitor refresh rates, without going too fast for Allegro to handle. It fits perfectly with refresh rates of 60, 75, 100, and 120, which are some of the most common refresh rates monitors run at.

And before anyone questions the sanity of having a timer routine called 2400 times a second, it works very well and very smoothly, even on my P120, so clearly I'm doing it right. ;D

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Kitty Cat
Member #2,815
October 2002
avatar

Quote:

And before anyone questions the sanity of having a timer routine called 2400 times a second, it works very well and very smoothly, even on my P120, so clearly I'm doing it right.

FYI, a timer at that speed won't be any better than one at 70~100 times a second. Whenever the timer thread rests to save cpu usage, it'll take about 5~10ms to wake up again (limiting to approx. 100 runs a second), and after doing some stuff, call your routine about 24 times in a row. Unless you're using DOS, you won't get any benefit over a ~100hz timer.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Locutus266
Member #7,638
August 2006

Is that al_get_ticks() function documented somewhere? I cannot find it in the documentation, provided in the Files section of this page.

George Foot
Member #669
September 2000

Locutus, I'm not that much in contact with the Allegro community lately but from what I've seen Allegro 4.3 isn't ready for general use anyway. It is the unstable development branch, though, so when I have some time I'm planning to look again at my GP2X port of Allegro 4.2 and see how best to fit it into the official distribution. After that, it shouldn't be an issue any more that the GP2X version is a fork.

For now, I'm just about finding enough spare time to fix the hardware acceleration, but I will have a lot more time on my hands next month so that'll be the most likely time for integrating GP2X support into the 4.3 branch.

On a tangent, but more related to the thread topic, I'm pretty sure Allegro internally does what you say - working out how long it can afford to sleep before it needs to wake up and call a timer callback. It might be interesting to expose that, so you could query how long it will be before a particular timer fires.

Locutus266
Member #7,638
August 2006

Hello Mr. Foot,

Interesting to see you post here, since I first came back to Allegro when I saw your GP2X port. I liked the thought that I can develop games for DOS, Windows, Linux and the GP2X at the same time. And vsync() works, one thing I couldn't get to work with SDL.

I have taken a look at the Allegro internals and discovered that it uses clock() in some timer-related functions. What is your opinion on that? Is clock() a relieable timer to determine framerate and the time how long to sleep until the next blit?

Regards,
Christoph B.

Kitty Cat
Member #2,815
October 2002
avatar

Quote:

Is clock() a relieable timer to determine framerate and the time how long to sleep until the next blit?

No. The clock function doesn't necesarilly track the physical system time. It can only report the number of clocks your process uses (and thus doesn't increment when sleeping/preempted). It's granularity is also completely undefined.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

George Foot
Member #669
September 2000

Last time I checked, clock() on Linux only had about 17Hz granularity, so it's not a great choice. It also only measures processor time (theoretically), not real time - so if you sleep, the value returned won't increase. I'd be quite surprised if Allegro really uses it for this kind of thing.

gettimeofday is generally preferable - it's a system call and it only returns a couple of ints, so it's not as inefficient as it might sound.

I guess you're probably most interested in what would work best on the GP2X - we could probably provide a more precise timer system closer to the hardware, but currently it just uses Allegro's generic Unix timer code. I think that's based around calculating how long until the next tick, sleeping for a bit less, calling gettimeofday, and figuring out whether to sleep a bit longer or call the callback. There's also a non-threaded version which uses alarm() instead of sleeping, but the principle is probably similar.

Locutus266
Member #7,638
August 2006

George Foot said:

I guess you're probably most interested in what would work best on the GP2X

Actually, I am looking for a more platform-independent approach, e.g. code which works on Windows/Linux/GP2X. I'd like a function that gives me a millisecond-exact (~10 ms granularity) time value, which I can use for timing framerate and sleeping. On SDL, it's SDL_GetTicks(), but as of now, I figure, there is no way to do that in Allegro.

You can do it with timers, but then you get absolutely nothing in return, you can use as a parameter for rest().

Regards,
Christoph B.

George Foot
Member #669
September 2000

Sure - I just thought maybe you were leaning more towards the GP2X. For a cross-platform solution I'd ifdef it, using gettimeofday on Unix and GetTickCount on Windows, if the granularity is good enough for you.

Timing accurately on Windows is a black art, though. GetTickCount is OK, but the granularity might be too poor for you (1/60th of a second is only 17ms after all; also note that the granularity isn't necessarily 1ms, that's just the units it returns the time in). You can use QueryPerformanceCounter instead, which is very high resolution (nominally), but apparently has a lot of problems of its own... http://www.virtualdub.org/blog/pivot/entry.php?id=106

Locutus266
Member #7,638
August 2006

Maybe

extern volatile int retrace_count;

is another way to control the speed of a game without using timer functions. Is that a reliable timer or does it behave differently with different graphics drivers?

Best regards,
Christoph

gnolam
Member #2,030
March 2002
avatar

The entire retrace simulator doesn't work at all except in DOS, AFAIK.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Tobias Dammers
Member #2,604
August 2002
avatar

Here are your weapons:
Linux: gettimeofday()
Windows: QueryPerformaceCounter()
Mac: I don't have the faintest idea, but since OS X is basically a Unix-lookalike, I suppose something similar to gettimeofday() exists.
Fallback for all other systems, or when the above fail (QPC is documented not to be available on all systems): Allegro timers.
Write a wrapper around these, automatically selecting whatever is available. All timing methods can be abstracted into a "initialize - start - read delta - stop - shutdown" sequence, so that's what you need to implement for each. Reuse code in all future projects.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Michael Jensen
Member #2,870
October 2002
avatar

Correct me if I'm wrong but it's my understanding that the GP2X is not running your allegro apps on a multithreaded OS (does it run an actual OS at all or do the programs get full control of the device?) -- why would the processor being at 99% be a problem?

Also -- I'm not sure about the specific GP2X allegro port, but:

Allegro Manual on rest said:

Passing 0 as parameter will not wait, but just yield. This can be useful in order to "play nice" with other processes.

spellcaster
Member #1,493
September 2001
avatar

The problem with the 99% cpu is the battery drain. If you don't have to use a resource, not using it would be a good idea.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

Evert
Member #794
November 2000
avatar

Quote:

you could push for it getting backported into the Allegro 4.2.1 release.

Oh no you don't! Not when I've finally found some time to work on the release.
Besides, we could go on indefinately backporting 4.3 features to 4.2...

Quote:

when I have some time I'm planning to look again at my GP2X port of Allegro 4.2 and see how best to fit it into the official distribution. After that, it shouldn't be an issue any more that the GP2X version is a fork.

George, could you have a look at the 4.2.1 archives I've put up for testing? I'm curious to know what changes you would recommend to make it work well on the GP2X. If it's nothing too dramatic, I'm all for a 4.2.2 that has GP2X support out of the box. :)

gnolam
Member #2,030
March 2002
avatar

Quote:

Oh no you don't! Not when I've finally found some time to work on the release.
Besides, we could go on indefinately backporting 4.3 features to 4.2...

4.3 still lies somewhere in the dark, unknown future; 4.2.x is what people are going to be using for the next couple of years. I agree that 4.2.1 isn't a good target for it (we need a fast bugfix release), but 4.2.2 sure is.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

George Foot
Member #669
September 2000

Quote:

Correct me if I'm wrong but it's my understanding that the GP2X is not running your allegro apps on a multithreaded OS (does it run an actual OS at all or do the programs get full control of the device?) -- why would the processor being at 99% be a problem?

It runs Linux, out of the box.

Quote:

George, could you have a look at the 4.2.1 archives I've put up for testing? I'm curious to know what changes you would recommend to make it work well on the GP2X. If it's nothing too dramatic, I'm all for a 4.2.2 that has GP2X support out of the box. :)

I'll see how well my patch applies, and whether anything in the patch is unsuitable for rolling back into the core library.

Go to: