Possible bug with text outputs
Lucas Adami

Hello.

I'm developing my game with Allegro 4.9.8.
While programming, I realized that sometimes my program uses too much CPU processing.
Then, trying to find where it was the cause, I discovered that al_font_textout() was the answer. I made a test program to prove this, and I was right:

- I load a ttf font
- Use a color
- In a loop (with sleep()!) I use that function

When I remove the line of al_font_textout(), my CPU proccessment goes 2~ in max. With al_font_textout(), it reachs 30~35.

I attached my program files so you can test it too.

Does this only happens with me?
If not, isnt it a bug?
Is it a know bug that was solved on 4.9.9?

Thank you ;)

Christopher Bludau

I haven't tested the executable but I looked at the code. What I noticed was that you don't use a proper timing method.

You should have a look at this awesome allegro 5 tutorials and especially tutorial 3 which will explain how to use proper timing with allegro 5.

Maybe this will already solve your problem because the redrawing of your screen will only been done when necessary (so it will use less cpu).

Lucas Adami

Christopher, I dont use the sleep as it is on the test code on my project ;)

But, it has nothing to do with the CPU usage. If I change the text output to a bmp drawing ( I tested with a bmp of 1MB! -> al_draw_bitmap() ), the CPU usage does not pass 3~.

Todd Cope

Text output seems slow to me, too, but I hadn't done any testing to verify it. In one of my games the CPU usage jumps up when I display around 5 lines of text on the screen. My game is using bitmap fonts.

Peter Wang

I think there is some inefficiency there, but it would be nice if you guys tested with 4.9.9 or later, and preferably with the profiling builds. I didn't notice anything particularly wrong with Lucas' example on my machine (OpenGL on Linux).

Milan Mimica

Most functions you used in that example don't exist in SVN version.

Neil Walker

You should have a look at this awesome allegro 5 tutorials

Looking at the code I see this:

ALLEGRO_TIMER *timer = al_install_timer(1.0/refresh_rate);
  al_start_timer(timer);
  ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
  al_register_event_source(queue, (ALLEGRO_EVENT_SOURCE*)al_get_keyboard());
  al_register_event_source(queue, (ALLEGRO_EVENT_SOURCE*)timer);

Assuming this is the typical usage for timers, would it not be good to add an optional parameter to al_install_timer to flag whether to start it up on creation, thereby removing the need to temporary variables, additional function calls, etc. and making initialisation a quick and simple process and done in the same way (as per get mouse, get joystick, etc), e.g. the above code be reduced to:

  ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
  al_register_event_source(queue, (ALLEGRO_EVENT_SOURCE*)al_get_keyboard());
  al_register_event_source(queue, (ALLEGRO_EVENT_SOURCE*)al_install_timer(1.0/refresh_rate,true));

Elias

You should have a look at this awesome allegro 5 tutorials

Some of the examples coming with A5 also show a somewhat more robust way to handle updates by having optional frame skipping. If you redraw at each timer tick as in the tutorial you will run into problems on slow computers.

Assuming this is the typical usage for timers, would it not be good to add an optional parameter to al_install_timer to flag whether to start it up on creation

Sounds reasonable to me. Or maybe reduce it all even further to:

queue = al_init_simple(640, 480, 1.0 / 60);

with:

ALLEGRO_EVENT_QUEUE *al_init_simple(int width, int height, float frequency)
{
    ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
    al_create_display(width, height);
    al_install_keyboard();
    al_install_mouse();
    al_register_event_source(queue, al_get_keyboard());
    al_register_event_source(queue, al_get_mouse());
    al_register_event_source(queue, al_get_current_display());
    ALLEGRO_TIMER *timer = al_install_timer(1.0 / frequency);
    al_register_event_source(queue, timer);
    al_start_timer(timer);
    return queue;
}

I'm sure this would cover the usage in most A5 programs.

Milan Mimica

Or start_timer() could return ALLEGRO_TIMER* passed to it :)

Evert

You'll want to grab the timer handler to be able to stop/pause the timer (for instance).

Peter Wang

How do you know how long the stuff in between starting the timer and the start of your main loop will take? I presume you'd want to minimise that. I'd rather stick with explicitly starting the timer.

Neil Walker

How do you know how long the stuff in between starting the timer and the start of your main loop will take? I presume you'd want to minimise that. I'd rather stick with explicitly starting the timer.

That's why I offered a boolean start up flag, you can have two values: true and false ;)

I just see having to assign and not use objects as a waste, when function chaining is not available.

SiegeLord
Elias said:

Some of the examples coming with A5 also show a somewhat more robust way to handle updates by having optional frame skipping. If you redraw at each timer tick as in the tutorial you will run into problems on slow computers.

Which ones? The main loops should be standardized for the examples at some point. As is there are various combinations of rest(1) loops, timer loops, delta time loops etc etc.

Elias

Yeah, I meant what most use, like e.g. ex_bitmap or ex_blit. I also don't see why you would use variable frame length or redraw depending on whether enough time to the last update has passed.

SiegeLord
Elias said:

Yeah, I meant what most use, like e.g. ex_bitmap or ex_blit.

Most, but not all. IMHO they should all use it the system in ex_bitmap, or as outlined here. It is very flexible, and I like it.

I don't suppose there is a desire to introduce an al_game_loop(void (*logic)(), void (*input)(), void (*draw)(), ALLEGRO_EVENT_QUEUE *queue) function to the library?

Christopher Bludau

I probably don't get this completely.
Would you care to elaborate on this a little bit?

Elias said:

If you redraw at each timer tick as in the tutorial you will run into problems on slow computers.

Here is the problem I have. I don't see the real difference between the two solutions.
The tutorial I linked to does this:

#SelectExpand
1 case ALLEGRO_EVENT_TIMER: 2 { 3 // Determine the change in time between frames, in seconds 4 time = al_current_time(); 5 dt = time-old_time; 6 7 // If the computer lags for some reason, don't penalize the player 8 // Cap dt at 0.5 seconds 9 if(dt > 0.25) dt = 0.25; 10 11 // UPDATE 12
13 if(time - event.timer.timestamp <= 1.0/refresh_rate) {
14 // DRAWING 15 } 16 17 // Make the time at this frame the old time, for the next frame 18 old_time = time; 19 break; 20 }

So because of line 14 it doesn't draw on each tick. Or am I wrong?
Steve says on his site:

Each event is timestamped with the number of seconds since the program began. This conditional is checking that the tick event happened within the past frame. If the timer tick is from more than a frame ago, we disregard it and will not perform any drawing operatings.

The difference I see in this example is, that drawing is only done, when the queue is empty. Why is this a good thing?

Hope I don't bother you too much with this questions. :(

Elias

The al_event_queue_is_empty(queue) is only for the case when the game runs really slow (1 FPS or so, because neither DirectX nor OpenGL acceleration is available). Then the events queue would fill up and you'd have to wait a long time for something like pressing the Esc key or close button to register. The timestamp comparison might have the same effect though - we should make one of the examples use it to know.

SiegeLord

I don't see the real difference between the two solutions.

The wiki's method is fixed time step, and the tutorial's method is delta-time for one. Moreover, the tutorial's method doesn't really make sense to me, given that it is a delta time method... why would you call the update multiple times per frame? If you convert it to a fixed time method, then it should behave the same as the wiki's method, only be more complicated.

Elias said:

The al_event_queue_is_empty(queue) is only for the case when the game runs really slow (1 FPS or so, because neither DirectX nor OpenGL acceleration is available)

No, it isn't. It's for when the game runs at any speed lower than the set FPS. Whenever the drawing operation takes more than 1/FPS time, there are multiple timer ticks that happen during it. al_event_queue_is_empty(queue) makes sure we take care of all of them before drawing, the standard fixed time stepping tactic.

Elias

Ahh, makes sense. For me, the only time that could happen is when using software routines (as otherwise drawing is nearly instant and there would never be multiple timer ticks if they are as slow as 60 per second). But, I interpreted it completely wrong... have yet to get completely accustomed to the events-based mindset after using the A4 way for so long :)

Christopher Bludau
SiegeLord said:

Whenever the drawing operation takes more than 1/FPS time, there are multiple timer ticks that happen during it.

if(time - event.timer.timestamp <= 1.0/refresh_rate)

SiegeLord said:

If you convert it to a fixed time method, then it should behave the same as the wiki's method, only be more complicated.

Given this informations I guess that this is not true?

Elias said:

Some of the examples coming with A5 also show a somewhat more robust way to handle updates by having optional frame skipping. If you redraw at each timer tick as in the tutorial you will run into problems on slow computers.

Otherwise I still don't see what is the problem with the code in the tutorial.
(I don't mean the delta time vs fixed time but that it may run into problems on slow computers)

brunooo

I have problems with it too. When I start drawing too many texts, the game starts to lose too much performance! I also noticed that on slower computers, my games are not running as good as 4.2.2 runned :-/

I am using the software.skoobalon.com tutorials :-X

Elias

A5 uses Direct3D/OpenGL for all drawing operations and so the performance should only depend on your drivers (and usually it is a lot faster than A4 for everything you do).

However if for some reason you are using the software emulation of A5 it will be slow because unlike A4 alpha blending is on by default. You could try turning blending off and compare then, it will probably run at the same speed.

brunooo

I will try that! But text printing still bothers me :/

Milan Mimica

Text output is slow. ex_ttf runs at 80FPS here, and all it does it displaying dozen of lines on the screen.

brunooo

Yes, the ex_ttf here runs at 85 fps, but it uses 99% of cpu and when I open the Task Manager to see how much cpu % it uses, it crashes. I need to open the task manager first and then run it. :-/

Thread #599845. Printed from Allegro.cc