Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Slowness when drawing fonts

This thread is locked; no one can reply to it. rss feed Print
 1   2   3   4 
Slowness when drawing fonts
Evert
Member #794
November 2000
avatar

I don't think I fully understand the problem.
The first time a glyph is used, it's cached for future use. That means that the first time you draw text, it's slower. On subsequent redraws, it should be (much) faster because the text is precached. Am I understanding this right? If so, I don't really understand why that's an issue. I mean, pre-caching wouldn't eally be faster, you'd just have to wait somewhere else for the cache to be built.

Elias said:

Caching whole words or lines would be in-between those two.

Perhaps Allegro could keep track of the most recently drawn 100 (say) strings (or words) in a cache in addition to caching glyphs?

Elias
Member #358
May 2000

have to agree with AMCerasoli, that there should be a mechanism during or after font loading that allows you to precache a range of glyphs.

al_get_text_width(font, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");

^ We already have it.

Evert said:

Perhaps Allegro could keep track of the most recently drawn 100 (say) strings (or words) in a cache in addition to caching glyphs?

Yes, but would have to test my assumption about it first. I wonder how e.g. Firefox or Chrome draw all their text - but I'd think they also use per-glyph caching. At least in Firefox text is 100% identical to Allegro 5... i.e. when I use the same font with the same size then all glyphs are at the exact same pixel positions (each separate glyph position rounded to a whole integer pixel position just like in A5).

What might be the real problem is how long one al_draw_bitmap() call takes. A specialized text drawer which uses al_hold_bitmap_drawing or even al_draw_prim is a lot faster (using the very same texture cache).

Also, the ttf addon isn't very clever about texture management right now. We should probably at least have an al_optimize_ttf_cache(ALLEGRO_FONT *) function which tries to combine all cached-so-far glyphs into a single texture.

In any case, I still have no idea how slow or fast font drawing is... if only the caching is a problem then my code snippet above fully solves the issue :)

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

AMCerasoli
Member #11,955
May 2010
avatar

Evert said:

The first time a glyph is used, it's cached for future use. That means that the first time you draw text, it's slower. On subsequent redraws, it should be (much) faster because the text is precached. Am I understanding this right?

More or less. Isn't that I completely understand the process, but as you have said "The first time a glyph is used, it's cached for future use" this is done by Allegro and not by FreeType, basically is a bad implementation when drawing fonts, because caching the glyphs immediately before draw them makes the program take the glyphs from a truetype font file,"prepare" them from a bunch of vectors depending on the size, all this on runtime.

Quote:

I don't really understand why that's an issue. I mean, pre-caching wouldn't really be faster, you'd just have to wait somewhere else for the cache to be built.

We're talking about pre-caching because Allegro isn't caching the glyphs before they are drawn at runtime. But actually we should be talking about caching the glyphs, just that, everyone knows that this should be done before we draw the text to the screen, and not at runtime.

Separating the caching from the drawing, has 2 very important advantages:

  1. It lets you create multi-thread applications, where you can load the font on a different thread and in which you cannot actually draw anything so you can't cache the glyphs. Therefore you rely on the main thread, which should be the UI thread, so when you draw the font you would be caching them too, stopping the animations or other stuffs (My case)

  2. You don't need to draw the alphabet outside of the screen to cache the fonts in a loading phase

Quote:

glyph caching
Each time you request a glyph image from a font, FT2 does it by parsing the relevant portion of the font file/stream and interpreting it according to its font format. This can be very slow for certain formats, including scalable ones like TrueType or Type 1.

Any decent text-rendering sub-system must thus be capable of caching glyph data in order to reach appropriate rendering speed

Note that we provide a beta caching sub-system with FreeType 2 since version 2.0.1. Even though you're free to write your own to suit your needs.

So I think the best solution is that one adopted by SFML where they have the extended ASCII range already cached on loading, and if you want you can select another fonts if you want. something like al_load_font(char const *filename, int size, char const*charset, int flags). That function should be caching the extended ASCII range of character, because it's illogical to be writing "abcdefg..." each time we load a font, or we could create another function to do the cache of estrange characters. Even the Spanish alphabet fits very well in the extended ASCII range, so would be a good idia having a separated function... It's the same though.

Edit: Again... reading Elias post... Just because my English isn't that well...

Edit2: That function actually cache those letters?... that might be something. I'll try it. :D

Edit3:
Aww... That it's worse :( . That reduce my FPS not only when I draw the font for first time... But also still slow for the rest of the game...

Maybe because I'm doing it on another thread:

     al_lock_mutex(p_dato->mutex);
     p_dato->font = al_load_font("font/consola.ttf",17, 0);
     al_get_text_width(p_dato->font, "abcdefghijklmnopqrstuvw...");
     al_unlock_mutex(p_dato->mutex);

I'm in checkmate... :-/

Slartibartfast
Member #8,789
June 2007
avatar

It lets you create multi-thread applications, where you can load the font on a different thread and in which you cannot actually draw anything so you can't cache the glyphs.

Not it does not because it is exactly as you say, if you load the font on a different thread you can't cache the glyphs, this is because the other thread does not have the proper context to create a video bitmap. (To effectively cache the font you draw the glyphs into a video bitmap and further use of those glyphs comes from that video bitmap.)
The best you can do from another thread is cache the font into a memory bitmap (not a video bitmap), which will give much worse performance when using that font. (video bitmaps can make use hardware accelerated drawing, memory bitmaps cannot)

Note that everything I just wrote I learned solely by reading this thread, as I didn't know about these things beforehand and it has all been explained to you in this thread numerous times.

EDIT:

Quote:

Maybe because I'm doing it on another thread:

Maybe because the glyphs are being cached to a memory bitmap? Because they are cached in a thread that can only create memory bitmaps?

Try caching the font from the "main" thread.

Evert
Member #794
November 2000
avatar

"The first time a glyph is used, it's cached for future use" this is done by Allegro and not by FreeType, basically is a bad implementation when drawing fonts, because caching the glyphs immediately before draw them makes the program take the glyphs from a truetype font file,"prepare" them from a bunch of vectors depending on the size, all this on runtime.

I still don't understand.
This work has to be done at least once, either when the font is loaded (but you can't do it for all glyphs in the font, there's potentially far too many of those) or on-demand when it turns out that those characters are actually needed.
The question is, do you do more work up front (at the risk of doing work that you don't need to do), or do you do work when it turns out that you have to? In general, especially when it comes to data processing, you're better off doing the latter.
Yes, it means that the first time you request the data (want to draw the glyph), it's slower because you first have to do extra work. But that overhead should be gone the next time you use the data, right? So what's the problem?

Is it really a problem if you get a small slow-down the first time you use a bit of data as long as it's gone when you re-use the data afterwards? Your runtime performance is not going to be determined by how fast things are the first time you draw them, but by how fast things are when you redraw them every frame.

EDIT

the other thread does not have the proper context to create a video bitmap.

Quoted for emphasis.

AMCerasoli
Member #11,955
May 2010
avatar

Elias said:

At least in Firefox text is 100% identical to Allegro 5... i.e. when I use the same font with the same size then all glyphs are at the exact same pixel positions (each separate glyph position rounded to a whole integer pixel position just like in A5).

Yes the same in PhotoShop, it's very precise.

Not it does not because it is exactly as you say, if you load the font on a different thread you can't cache the glyphs,

Have you run my example? even on a multi core computer I can notice the application getting stuck, there, I'm not using Multi-thread SO THAT ISN'T THE REASON.

Quote:

Note that everything I just wrote I learned solely by reading this thread, as I didn't know about these things beforehand and it has all been explained to you in this thread numerous times.

Nice!, I'm proud of you

Quote:

Try caching the font from the "main" thread.

That is what I did in my example, check it.
Edit:

Evert said:

This work has to be done at least once, either when the font is loaded (but you can't do it for all glyphs in the font, there's potentially far too many of those)

You can't do it for all Unicode character, TTF files not even has so many charter inside anyway. But you could do it for your alphabet.

What you're suggesting is that if for some reason I want to show text on my game in two idioms at the same time it's more logic to block out the entire UI while the process is caching the glyphs for first time when drawing, than doing that previously, even better in another thread?

You know what?, fine, there is no problem, everything is ok, I'll take this into account the next time I'm on a project, or the next time I find a bug or whatever.

Slartibartfast
Member #8,789
June 2007
avatar

That is what I did in my example, check it.

Actually, it isn't. The relevant glyphs are cached when first used, not when loaded.

Quote:

Have you run my example?

Yes. It runs blindingly fast. There is a tiny, insignificant slowdown when first writing with the font, and that insignificant slowdown disappears if I manually cache the font. (In this case by replicating the call to al_draw_text before entering the main loop)

Quote:

Have you run my example?

Did you read your own message that I was responding to? Allow me to quote it for you:

Separating the caching from the drawing, has 2 very important advantages:
1) It lets you create multi-thread applications, where you can load the font on a different thread and in which you cannot actually draw anything so you can't cache the glyphs. Therefore you rely on the main thread, which should be the UI thread, so when you draw the font you would be caching them too, stopping the animations or other stuffs (My case)

You claimed that separating caching from drawing will allow you to load the font from a different thread, and I explained to you that either way you cannot load the font from a different thread.

Matthew Leverton
Supreme Loser
January 1999
avatar

AMCerasoli, if you use a smaller font does it work? Maybe Allegro is creating a memory bitmap cache. (I don't know how it works...) Your example works fine for me.

Elias said:

So we can put things like the shaders addon into a 5.0 release?

Theoretically, yes. While it may seem more proper to put big new features into a 5.2 branch, it (in my opinion) isn't worth it because maintaining two major releases is a pain in the butt. People will expect the older 5.0 branch to be continued to be maintained (bug fixed), which is just a hassle when it comes to providing binaries.

I would leave 5.2 alone until we come up with things that either completely break backward compatibility or are major changes to the core or how things are done. I don't know what would fit in that latter category.

Peter W's opinion would be more useful than mine.

Thomas Fjellstrom
Member #476
June 2000
avatar

People will expect the older 5.0 branch to be continued to be maintained (bug fixed), which is just a hassle when it comes to providing binaries

I'm not sure why, it was never done for 3.x or 4.x. As soon as a new .x release is made, the last one is abandoned afaik.

I'm pretty sure 3.x was abandoned entirely when 4.x was released. So maintaining 4.x and 5.x right now is a bit of an aberration.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Elias
Member #358
May 2000

Indeed, when 5.2 gets out 5.0 is deprecated. Just like you had to upgrade from 4.0 to 4.2 if you still wanted to benefit from bug fixes. There also was no more 4.2.x releases after 4.4.0 got released (I think at least, didn't follow 4.x development so closely).

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

Matthew Leverton
Supreme Loser
January 1999
avatar

If 5.0 is abandoned the instant 5.2 comes out, then switching to 5.2 for any reason other than breaking backward compatibility is purely psychological. And since we aren't in a war with SDL (etc) to see who has the largest version number, then I'd stick with 5.0 as long as we aren't breaking things.

AMCerasoli
Member #11,955
May 2010
avatar

AMCerasoli, if you use a smaller font does it work? Maybe Allegro is creating a memory bitmap cache. (I don't know how it works...) Your example works fine for me.

My font is already very small (17):

{"name":"604230","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/9\/59e3b6697ce14975f343cf8476a526f7.png","w":805,"h":633,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/9\/59e3b6697ce14975f343cf8476a526f7"}604230

Maybe you have a 360 teraflops computer, but I have tasted the game on different computers and the fastest one still being slow, I'm doing a simple game I can't demand too much in the minimum requirements.

Elias said:

In any case, I still have no idea how slow or fast font drawing is... if only the caching is a problem then my code snippet above fully solves the issue

ehh... No it doesn't... I have test it using my example and the text still slow when it's drawn for first time.

I have modified the ex_ttf file to show you the problem, if you want I can send you the file, but I think the problem is very clear right now.

video

You can see the lot of FPS that are drooped the first time the text is loaded and that is just a small amount of text with an small size. I'm not a nit-picky guy, guys, but it's drooping my game frames very noticeable... I hope in future version of Allegro the glyph are cached on loading like SFML does.

Elias
Member #358
May 2000

ehh... No it doesn't... I have test it using my example and the text still slow when it's drawn for first time.

Are you sure that you:

- Included all glyphs in the cache?
- Do not do the caching from another thread/without a display?

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

Evert
Member #794
November 2000
avatar

What you're suggesting is that if for some reason I want to show text on my game in two idioms at the same time

"two idioms at the same time"???

Quote:

it's more logic to block out the entire UI while the process is caching the glyphs for first time when drawing, than doing that previously, even better in another thread?

No, I'm saying that if that's the issue that's being discussed, I don't really see why that's a problem. And the reason I was asking is because it wasn't entirely clear to me what the issue was/is.
And why bring up "another thread" if you find it necessary to reply to someone else in bold face that you're not using multiple threads?

Quote:

You know what?, fine, there is no problem, everything is ok, I'll take this into account the next time I'm on a project, or the next time I find a bug or whatever.

Count to ten first next time you feel the urge to post.

You can see the lot of FPS that are drooped the first time the text is loaded and that is just a small amount of text with an small size.

You're aware of course that your monitor is only able to display ~60fps, right?
Anyway, are you serious? You get a momentary blip going from ~580fps to ~520fps the first time the text is drawn. Is that really a big deal and what you call a "massive slowdown"?
I'm not saying there can't be an issue or things can't be improved, but if this is quantitatively what we're talking about, I really don't see where you're coming from. Sorry.

AMCerasoli
Member #11,955
May 2010
avatar

Evert said:

"two idioms at the same time"???

Yes Evert, two idioms at the same time... Draw two languages at the same time... You looks like a compiler...

To do something like that, I would have to 1) load a .ttf which has the letters for the two different idioms (Ex: German, Italian), or load two different .tff one for German and another for Italian... Anyway my point was that the more letter you want to draw the slower the process is going to be. Without a cache function if for some reason you want to do something like this:

Hello Evert
مرحبا ايفرت
прывітанне Эвэрт
喜埃弗特
היי Evert

Your game UI is going to get block for three weeks with the current implementation, at least with a cache function I could put a "Loading..." on the window and don't block the UI, while I'm processing the cache process on another thread, yes I know, "I cannot" load fonts on another thread. I'm going to reimplement my game structure to adjust to this conditions, I didn't know that loading things on another thread would be loaded as memory bitmaps, because I guess it's the same with normal bitmaps. For that reason a al_convert_bitmap function would be good. But I think I can fix the necessity to load the font on another thread with some changes, I can't fix the Super Extra Disproportionate time that it take to draw them for first time, though.

Quote:

No, I'm saying that if that's the issue that's being discussed, I don't really see why that's a problem. And the reason I was asking is because it wasn't entirely clear to me what the issue was/is.

Sorry... I didn't get that way... I use to simply say: "ohhh ok".

Quote:

And why bring up "another thread" if you find it necessary to reply to someone else in bold face that you're not using multiple threads?

I'm bringing up "another thread" because I want to make sure developers know what I'm doing in case I'm doing something wrong, which I'm actually doing (loading fonts in another thread) supposedly should fail, but it doesn't (so far).

If that "someone" had read the entire thread he would know that I'm using multi-thread but the example (which is presenting the same problem) isn't.

Quote:

You're aware of course that your monitor is only able to display ~60fps, right?

::)

Quote:

Anyway, are you serious? You get a momentary blip going from ~580fps to ~520fps the first time the text is drawn. Is that really a big deal and what you call a "massive slowdown"?
I'm not saying there can't be an issue or things can't be improved, but if this is quantitatively what we're talking about, I really don't see where you're coming from. Sorry.

I'm not a conformist, if I see that my application is getting stuck for 0.00001 seconds I want to know why, if isn't my fault, I want to know what is doing the library, and if I found there is a problem with the library, I will report it. But I just want to clarify that the stuck time isn't 0.00001 seconds it's much more, and this is an issue.

Edit:

Elias said:

- Included all glyphs in the cache?
- Do not do the caching from another thread/without a display

Yes and yes.

#SelectExpand
1#include <stdio.h> 2#include <list> 3 4#define ALLEGRO_STATICLINK 5#include "allegro5/allegro.h" 6#include "allegro5/allegro_font.h" 7#include "allegro5/allegro_ttf.h" 8#include "allegro5/allegro_image.h" 9#include <allegro5/allegro_audio.h> 10#include <allegro5/allegro_acodec.h> 11 12class SPOT { 13 14 private: 15 16 ALLEGRO_BITMAP *bmp; 17 float posi_X, posi_Y, vel; 18 19 public: 20 21 SPOT(ALLEGRO_BITMAP *T_bmp, float T_y, float T_vel) : 22 bmp (T_bmp), 23 posi_X (-100), 24 posi_Y (T_y), 25 vel (T_vel){} 26 27 ~SPOT(){ 28 29 al_destroy_bitmap(bmp); 30 31 } 32 33 void move(){ 34 35 al_draw_bitmap(bmp, posi_X, posi_Y, 0); 36 37 posi_X += vel; 38 39 if(posi_X>640) posi_X=-100; 40 41 } 42 43}; 44 45int main() 46{ 47 if(!al_init()) 48 { 49 fprintf(stderr, "Failed to initialize Allegro.\n"); 50 return -1; 51 } 52 53 al_init_font_addon(); 54 al_init_ttf_addon(); 55 al_init_image_addon(); 56 al_install_audio(); 57 al_init_acodec_addon(); 58 al_reserve_samples(1); 59 al_install_keyboard(); 60 61 ALLEGRO_DISPLAY *display = NULL; 62 display = al_create_display(640,480); 63 ALLEGRO_BITMAP *Obj_Bmp = al_load_bitmap("spot.png"); 64 ALLEGRO_BITMAP *Obj_Bmp2= al_load_bitmap("spot.png"); 65 ALLEGRO_FONT *font = al_load_ttf_font("consola.ttf",72,0 ); 66 ALLEGRO_FONT *font2 = al_load_ttf_font("consola.ttf",72,0 ); 67 ALLEGRO_FONT *font3 = al_load_ttf_font("consola.ttf",72,0 ); 68 ALLEGRO_FONT *font4 = al_load_ttf_font("consola.ttf",72,0 ); 69 ALLEGRO_FONT *font5 = al_load_ttf_font("consola.ttf",72,0 ); 70 ALLEGRO_KEYBOARD_STATE keyboard; 71 ALLEGRO_SAMPLE *beep = al_load_sample("beep.ogg"); 72 73 //Obj_Bmp = al_load_bitmap("spot.png"); 74 75 76 std::list<SPOT*> Spo_List; 77 78 for(int a=0; a<10; a++) 79 Spo_List.push_back(new SPOT(Obj_Bmp, rand()%480, rand()%10+1)); 80 81 al_get_text_width(font, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 82 al_get_text_width(font2, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 83 al_get_text_width(font3, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 84 al_get_text_width(font4, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 85 al_get_text_width(font5, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 86 87 while(1){ 88 al_get_keyboard_state(&keyboard); 89 90 al_clear_to_color(al_map_rgb(50,10,70)); 91 92 if(al_key_down(&keyboard, ALLEGRO_KEY_A)) 93 al_draw_text(font, al_map_rgba(255,255,255,255), 640/2, (480/4),ALLEGRO_ALIGN_CENTRE, "Slow Font : (!"); 94 95 else if(al_key_down(&keyboard, ALLEGRO_KEY_S)) 96 al_draw_text(font2, al_map_rgba(255,255,255,255), 640/2, 50+(480/4),ALLEGRO_ALIGN_CENTRE, "Slow Font : (!"); 97 98 else if(al_key_down(&keyboard, ALLEGRO_KEY_D)) 99 al_draw_text(font3, al_map_rgba(255,255,255,255), 640/2, 100+(480/4),ALLEGRO_ALIGN_CENTRE, "Slow Font : (!"); 100 101 else if(al_key_down(&keyboard, ALLEGRO_KEY_F)) 102 al_draw_text(font4, al_map_rgba(255,255,255,255), 640/2, 150+(480/4),ALLEGRO_ALIGN_CENTRE, "Slow Font : (!"); 103 104 else if(al_key_down(&keyboard, ALLEGRO_KEY_G)) 105 al_draw_text(font5, al_map_rgba(255,255,255,255), 640/2, 200+(480/4),ALLEGRO_ALIGN_CENTRE, "Slow Font : (!"); 106 107 else if(al_key_down(&keyboard, ALLEGRO_KEY_B)) 108 for(int a=0; a<10;a++) 109 al_draw_bitmap(Obj_Bmp2, 200+rand()%40, 200+rand()%40, 0); // This Bitmap haven't being drawn previusly. 110 111 else if(al_key_down(&keyboard, ALLEGRO_KEY_ESCAPE)) 112 break; 113 114 for(std::list<SPOT*>::iterator it = Spo_List.begin(); it != Spo_List.end(); it++) 115 (*it)->move(); 116 117 al_flip_display(); 118 119 al_rest(0.01); 120 //Beep(500,20); 121 al_play_sample(beep, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_ONCE, 0); 122 123 124 } 125 al_destroy_display(display); 126 return 0; 127}

Trent Gamblin
Member #261
April 2000
avatar

I hope in future version of Allegro the glyph are cached on loading like SFML does.

That's not going to happen. The fonts (2 of them) I'm using for my current game have over 30,000 characters each. If you need glyphs cached just draw them like a bunch of people have said. Caching glyphs is slow, there's no way around it, but dropping to 520 FPS is not even an issue.

Evert
Member #794
November 2000
avatar

Yes Evert, two idioms at the same time... Draw two languages at the same time... You looks like a compiler...

Look, I appreciate that your English is not very good and that we're all going to make an effort to understand what you mean, but "two idioms at the same time" just doesn't make sense as a sentence. It certainly doesn't mean "display two languages that require vastly different character sets".
If it's not clear what you mean, it's up to you to make the effort of being more clear.

Quote:

For that reason a al_convert_bitmap function would be good.

I think Elias committed that to SVN the other day, have a look.

Quote:

::)

What?
It doesn't, and if you lock to the update frequency of the screen (what used to be called "wait for vsync", not sure what the best phrase to use these days is) and/or only draw to the screen when you've actually changed something so you need to redraw, you're never going to get a bogus "500 fps".

Quote:

if I see that my application is getting stuck for 0.00001 seconds I want to know why,

Hyperbole can sometimes be very effective, but if you push it too far it just becomes ridiculous.

Quote:

if isn't my fault, I want to know what is doing the library, and if I found there is a problem with the library, I will report it.

Well, you know what it's doing and why the delay is there. It's not a "problem" in the sense that the behaviour is by design.
I'm not saying it's not nice to have a way to pre-cache data you already know you're going to need, but based on the numbers you've posted, I don't see there's a major problem with the current implementation.

Quote:

But I just want to clarify that the stuck time isn't 0.00001 seconds it's much more, and this is an issue.

The drop in framerate corresponds to a processing time of 0.2ms. You want to display a "loading..." message for that?

AMCerasoli
Member #11,955
May 2010
avatar

hahaha It's funny how all this reminds me when I was in the school... Now I could say something like:

Evert said:

Look, I appreciate that your English is not very good and that we're all going to make an effort to understand what you mean, but "two idioms at the same time" just doesn't make sense as a sentence. It certainly doesn't mean "display two languages that require vastly different character sets".
If it's not clear what you mean, it's up to you to make the effort of being more clear.

a word to the wise is sufficient...

Quote:

What?
It doesn't, and if you lock to the update frequency of the screen (what used to be called "wait for vsync", not sure what the best phrase to use these days is) and/or only draw to the screen when you've actually changed something so you need to redraw, you're never going to get a bogus "500 fps".

I know man, that's just an example, my current game is running at 30FPS logic and drawing, for that reason I can see it.

Quote:

Hyperbole can sometimes be very effective, but if you push it too far it just becomes ridiculous.

It's just an example

Quote:

Well, you know what it's doing and why the delay is there. It's not a "problem" in the sense that the behaviour is by design.

Of course it is!

Quote:

I'm not saying it's not nice to have a way to pre-cache data you already know you're going to need, but based on the numbers you've posted, I don't see there's a major problem with the current implementation.

The numbers that I'm posting are from an example!, I said "I have modified the ex_ttf file to show you the problem", if the FPS drooped were worse in that simple example, then there would have a really bad bad implementation.

Quote:

The drop in framerate corresponds to a processing time of 0.2ms. You want to display a "loading..." message for that?

That was just an example... I want to cry...

That's not going to happen. The fonts (2 of them) I'm using for my current game have over 30,000 characters each. If you need glyphs cached just draw them like a bunch of people have said. Caching glyphs is slow, there's no way around it, but dropping to 520 FPS is not even an issue.

Allegro would only cache the extended ANSCII range, and there would be another function for people which uses other glyphs... the 520 FPS was an example... I think I'm going to commit suicide.

But doesn't matter, if is not going to happen, isn't going to happen, it's fine, now depend on my which decision to take. Thanks to all.

Trent Gamblin
Member #261
April 2000
avatar

Why cache the extended ascii range? You have no idea what glyphs the user is going to use until they draw them. That's why you draw the glyphs you need yourself, they'll be cached, and you move on.

kazzmir
Member #1,786
December 2001
avatar

AMCerasoli can you be specific about the kind of slowdowns you are seeing? Exactly how much time does it take to render the font the first time? I took your original example and added some timing measurements to it. I see this:

14.090000 milliseconds
0.169000 milliseconds
0.159000 milliseconds
0.160000 milliseconds
0.163000 milliseconds
0.179000 milliseconds

So caching takes 2 orders of magnitude longer than drawing but still 14ms is insanely small. Are you seeing something on the order of seconds?

Attached is your main.cpp but with calls to gettimeofday (I only measured pressing the A key).

Evert
Member #794
November 2000
avatar

I know man, that's just an example, my current game is running at 30FPS logic and drawing, for that reason I can see it.

The problem is, you start out by saying "text is drawn slowly the first time round", which is true. There's a reason for why that is the case, and the reason is that the first time a character is used, Allegro caches the glyphs so that things are faster the next time they're used.
You then proceed to say that there's a horrible drop in FPS when text is drawn for the first time, and show an example that... doesn't show a horrible drop in FPS at all.

Quote:

It's just an example

Yes. A bad one, because your hyperbole was very over the top.
This is exactly the problem: you talk about horrible slow downs, weeks of rendering time, wanting to find out why your game takes 0.00001 seconds longer to do something and yet the only actual data you present don't show any indication of a problem that even remotely justifies that level of hyperbole.

Please try to be more clear about how big of a problem we're dealing with here.

Quote:

Allegro would only cache the extended ANSCII range, and there would be another function for people which uses other glyphs...

First of all, there's no such thing as "extended ASCII range", Allegro uses UTF-8 encoding. Allegro could precache the full standard Latin alphabet, but if I only intend to use the fint to display a score, that's wasting a LOT of cache for no gain (and if we're talking about slowdowns, that'll slow down font loading for no gain as well). That's what I meant earlier: don't do work now that you don't know you need to do later.

Quote:

the 520 FPS was an example...

Again, a bad example because it doesn't actually support your claim that there's a massive problem. Just quote numbers from your game.

Quote:

But doesn't matter, if is not going to happen, isn't going to happen, it's fine, now depend on my which decision to take. Thanks to all.

What isn't going to happen is us spending a lot of time trying to avoid a drop from 580 to 520 FPS. However, a drop from 30 to (say) 5 FPS is a very different story.
So once again, please try to be more clear and precise.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Elias said:

Edgar said:

have to agree with AMCerasoli, that there should be a mechanism during or after font loading that allows you to precache a range of glyphs.

al_get_text_width(font, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");

^ We already have it.

The manual says absolutely nothing about al_get_text_width caching glyphs. Are we supposed to be psychic?

I wrote up some test code. Pass the path to the font you want to test on the command line. It caches all the printable regular ascii characters and measures the time it takes to load, cache, and display them :

#SelectExpand
1 2#include <cstdio> 3 4#include "allegro5/allegro.h" 5#include "allegro5/allegro_font.h" 6#include "allegro5/allegro_ttf.h" 7 8 9class AllegroSetup { 10private : 11 ALLEGRO_DISPLAY* display; 12 ALLEGRO_TIMER* timer; 13 ALLEGRO_EVENT_QUEUE* event_queue; 14 bool ready; 15public : 16 AllegroSetup(int w , int h , double tick_time) : 17 display(0), 18 timer(0), 19 event_queue(0), 20 ready(false) 21 { 22 if (!al_init()) {printf("Failed to initialize Allegro.\n");return;} 23 if (!(display = al_create_display(w,h))) { 24 printf("Failed to create %i X %i display.\n" , w , h); 25 return; 26 } 27 if (!(timer = al_create_timer(tick_time))) { 28 printf("Failed to create %lg paced timer.\n" , tick_time); 29 return; 30 } 31 if (!al_install_keyboard()) { 32 printf("Failed to initialize keyboard.\n"); 33 return; 34 } 35 if (!al_install_mouse()) { 36 printf("Failed to install mouse.\n"); 37 return; 38 } 39 if (!(event_queue = al_create_event_queue())) { 40 printf("Failed to create event queue.\n"); 41 return; 42 } 43 al_register_event_source(event_queue , al_get_keyboard_event_source()); 44 al_register_event_source(event_queue , al_get_display_event_source(display)); 45 al_register_event_source(event_queue , al_get_mouse_event_source()); 46 al_register_event_source(event_queue , al_get_timer_event_source(timer)); 47 ready = true; 48 } 49 50 ~AllegroSetup() { 51 if (event_queue) {al_destroy_event_queue(event_queue);} 52 if (display) {al_destroy_display(display);} 53 } 54 55 bool Ready() {return ready;} 56 57 inline operator ALLEGRO_DISPLAY* () {return display;} 58 inline operator ALLEGRO_EVENT_QUEUE* () {return event_queue;} 59 inline operator ALLEGRO_TIMER* () {return timer;} 60}; 61 62 63int readkey(ALLEGRO_EVENT_QUEUE* eq) { 64 while (1) { 65 ALLEGRO_EVENT ev; 66 al_wait_for_event(eq , &ev); 67 if (ev.type == ALLEGRO_EVENT_KEY_CHAR) { 68 return ev.keyboard.keycode; 69 } 70 } 71 return 0; 72} 73 74 75 76int main(int argc , char** argv) { 77 78 const char* font_name = "verdana.ttf"; 79 80 if (argc > 1) { 81 font_name = argv[1]; 82 } 83 84 85 AllegroSetup allegro(800,600,1.0/60.0); 86 if (!allegro.Ready()) {return 1;} 87 88 al_init_font_addon(); 89 al_init_ttf_addon(); 90 91 double start = 0.0; 92 double stop = 0.0; 93 double load_time = 0.0; 94 double cache_time = 0.0; 95 double display_time = 0.0; 96 97 double total_load_time = 0.0; 98 double total_cache_time = 0.0; 99 double total_display_time = 0.0; 100 101 int count = 0; 102 103 const int NUM = 13; 104 const char* strs[NUM] = { 105 "abcde", 106 "fghij", 107 "klmno", 108 "pqrst", 109 "uvwxyz", 110 "01234", 111 "56789", 112 "!@#$%", 113 "^&*()", 114 "-=_+", 115 "[]{}\\|", 116 ",.<>/?", 117 ";:'\"" 118 }; 119 120 bool quit = false; 121 122 while (!quit) { 123 ALLEGRO_EVENT ev; 124 while (!al_is_event_queue_empty(allegro)) { 125 al_wait_for_event(allegro , &ev); 126 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 127 quit = true; 128 break; 129 } 130 else if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { 131 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { 132 quit = true; 133 break; 134 } 135 } 136 } 137 if (quit) { 138 if (!count) {count = 1;} 139 break; 140 } 141 142 // measure loading time 143 start = al_get_time(); 144 ALLEGRO_FONT* font = al_load_ttf_font(font_name , -20 , 0); 145 stop = al_get_time(); 146 load_time = stop - start; 147 total_load_time += load_time; 148 if (!font) { 149 printf("Font file %s failed to load!\n" , font_name); 150 if (!count) {count = 1;} 151 break; 152 } 153 154 al_clear_to_color(al_map_rgb(0,0,0)); 155 156 // measure caching time 157 start = al_get_time(); 158 for (int i = 0 ; i < NUM ; ++i) { 159 int x = al_get_text_width(font , strs[i]); 160 } 161 stop = al_get_time(); 162 cache_time = stop - start; 163 total_cache_time += cache_time; 164 165 ALLEGRO_COLOR white = al_map_rgb(255,255,255); 166 // measure drawing time 167 start = al_get_time(); 168 for (int i = 0 ; i < NUM ; ++i) { 169//void al_draw_text(const ALLEGRO_FONT *font , ALLEGRO_COLOR color, float x , float y , int flags , char const *text) 170 al_draw_text(font , white , 10 , 10 + 30*i , 0 , strs[i]); 171 } 172 stop = al_get_time(); 173 display_time = stop - start; 174 total_display_time += display_time; 175 176 ++count; 177//void al_draw_textf(const ALLEGRO_FONT *font, ALLEGRO_COLOR color , float x , float y , int flags , const char *format, ...) 178 al_draw_textf(font , white , 410 , 10 , 0 , "Average load time = %0.3f ms" , 1000.0f*((float)total_load_time / (float)count)); 179 al_draw_textf(font , white , 410 , 40 , 0 , "Average cache time = %0.3f ms" , 1000.0f*((float)total_cache_time / (float)count)); 180 al_draw_textf(font , white , 410 , 70 , 0 , "Average draw time = %0.3f ms" , 1000.0f*((float)total_display_time / (float)count)); 181 al_draw_textf(font , white , 410 , 100 , 0 , "Test count = %i tests" , count); 182 183 al_flip_display(); 184 185 al_destroy_font(font); 186 } 187 188 printf("Average load time = %0.3lf ms\n" , 1000.0*(total_load_time / (double)count)); 189 printf("Average cache time = %0.3lf ms\n" , 1000.0*(total_cache_time / (double)count)); 190 printf("Average display time = %0.3lf ms\n" , 1000.0*(total_display_time / (double)count)); 191 printf("Test count = %i\n" , count); 192 193 return 0; 194}

I ran it for about 10 minutes and here are my results :

c:\ctwoplus\progcode\allegro5\test>A5Bouncer.exe
Average load time     = 0.980 ms
Average cache time    = 305.909 ms
Average display time  = 0.368 ms
Test count = 2130

c:\ctwoplus\progcode\allegro5\test>

So there is definitely a noticeable delay when caching the glyphs - just over 3/10ths of a second.

I still think there should be an explicit function in Allegro 5 that will do this for you, and al_get_text_width is cumbersome to use when you have different languages and varied characters in use. It could be as simple as :

void al_cache_glyph_range(ALLEGRO_FONT* font , int start , int number);

Imagine the case where users wish to display Kanji - they will almost always be caching new glyphs, and there will be noticeable slowdowns during their program every time they draw new text.

PS. Why does verdana.ttf look like shit (some characters are noticeably lighter or darker than others) ?
{"name":"604233","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/1\/a1a1d12e510134d770d50f9f39bc9134.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/1\/a1a1d12e510134d770d50f9f39bc9134"}604233

Arthur Kalliokoski
Second in Command
February 2005
avatar

PS. Why does verdana.ttf look like (some characters are noticeably lighter or darker than others) ?

It seems to me that the anti aliasing isn't allowing any pixels in the thinnest parts to be drawn full white. I've tried forcing pixels to be all white past a certain threshold, but then they have the jaggies, looking even worse. If you want a small font to look good, choose a font that cooperates.

They all watch too much MSNBC... they get ideas.

Thomas Fjellstrom
Member #476
June 2000
avatar

The manual says absolutely nothing about al_get_text_width caching glyphs. Are we supposed to be psychic?

No, but it has to render the characters to be able to measure the length a given string will be when drawn. I was kinda surprised at that too the first time I heard about it.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

It seems to me that the anti aliasing isn't allowing any pixels in the thinnest parts to be drawn full white. I've tried forcing pixels to be all white past a certain threshold, but then they have the jaggies, looking even worse. If you want a small font to look good, choose a font that cooperates.

You're right, it was just a shitty font. I tried using AMCerasoli's consola.ttf font, and it looks a 1000 times better with the same dimensions.

No, but it has to render the characters to be able to measure the length a given string will be when drawn. I was kinda surprised at that too the first time I heard about it.

That doesn't make much sense - what do you do, test pixel colors? Can't you calculate the width given the information in the font? Why does it have to be drawn first?

 1   2   3   4 


Go to: