Archived

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

Vich

Optimizations?!

Recommended Posts

Hi, When I'm rendering my menu, the part of code that takes the heaviest load is the text rendering (because my windows contain lots of text). Does anyone have any idea how to optimize this? What does this code do? it prints a string character by character. Each of the characters is pulled out of a bitmap texture, that contains a grid of 16x16 characters (the whole ascii character set). glPrintChar() just prints 1 character at certain coordinates with a certain font and size. glBmpPrint() prints a string using glPrintChar(). Note: saving all positions from the glPrintChar bitmap (each letter has an x and y coordinate) in a table, doesn't speed up the process, I've tried that.
void glPrintChar(const int x, const int y, const char input, const int font=TEXTURE_FONT_MINI, const int width=16, const int height=16)
{
    int column = input % 16; // find the column in the bitmap
    int row = (input-column) >> 4; // and the row too
    float tx = ((float)column/16.0f); // convert to an opengl coordinate
    float ty = 1.0f - ((float)row/16.0f); // convert to an opengl coordinate
    textureManager.Get(font); // get the right texture
    glBegin(GL_QUADS);
        glTexCoord2f(tx,ty);
        glVertex2d(x,y);
        glTexCoord2f(tx+0.0625f,ty);
        glVertex2d(x+width,y);
        glTexCoord2f(tx+0.0625f,ty-0.0625f);
        glVertex2d(x+width,y+height);
        glTexCoord2f(tx,ty-0.0625f);
        glVertex2d(x,y+height);
    glEnd();
}

void glBmpText(const int x, const int y, const string input)
{
    for (int i=0; i<input.size(); i++)
        glPrintChar(x+(10*i), y, input);
}
   
"My basic needs in life are food, love and a C++ compiler" [Project AlterNova] [Novanet]
[edited by - Vich on September 3, 2003 1:27:26 PM] [edited by - Vich on September 3, 2003 1:29:00 PM]

Share this post


Link to post
Share on other sites
Without knowing too much about your design, you could write a gimp script-fu script to enumerate all the strings in your game and make a png for each one. This would be much easier with a string table.

Apart from that, are you sure the text rendering takes the heaviest load when rendering a menu? Have you profiled it? If not, I suggest doing that to make sure you are attacking the correct problem.

Share this post


Link to post
Share on other sites
one thing i notice that is definitely slowing you down is that you call this function once for every single character you print to the screen. firstly that's a lot of function overhead but the bigger problem is that you call a glBegin and a glEnd every function call. in general you want to avoid as many glBegin/glEng calls as you can. they are very expensive. a better way to write your program that should save lots of execution time would be to just take out the glBegin and glEnd calls from the function and call the function like this:

glBegin(GL_QUADS);

for (every character)
//call your function


glEnd();

that should give you a performance boost.

after that, if it's still slow, you'll want to group your characters by texture since switching textures is also an expensive process. then you'd end up with something like:
   
glBegin(GL_QUADS);

for (every texture)
for (each character of this texture)
//call your function


glEnd();

-me

[edited by - Palidine on September 3, 2003 1:43:13 PM]

Share this post


Link to post
Share on other sites
It''s better to combine the textures, yes, at least if you can be relatively assured of rendering multiple parts of the same combined texture in succession. Fonts are ideal for this; give each letter a small area of the font texture.


How appropriate. You fight like a cow.

Share this post


Link to post
Share on other sites
Thanks for the info. I smell a weekend of reworking coming on.

Other questions:

a.) Is 64x64 texels a guaranteed minimum support for texture size or can I pretty much ignore that for most/all graphics cards?

b.) Isn't it a bit wasteful to have a 2nx2n texture for a character set if it doesn't work out to be a square size fitting charset? (I'm going from memory here.. blue book is at home). What work arounds are accepted?

[edited by - flangazor on September 3, 2003 2:04:37 PM]

Share this post


Link to post
Share on other sites
You may also want to look up display lists. Look up NeHe''s tutorial #13. I''ve used something like that to display fps info and such and it works pretty fast. I can''t say for sure if it''s faster than rendering it yourself, but it works.

Share this post


Link to post
Share on other sites
NeHe 13 is the way to go here. You create an array of 256 display lists, one for each character, which simply draws a quad with the right portion of the texture on it. Then, when it comes to drawing, you can simply pass your char* straight into glCallLists, and it will draw them all for you.

Share this post


Link to post
Share on other sites
I would also come up with a way of storing all of the font table lookup values. What you''re doing now shouldn''t be a ton of overhead, but you could do the computation for column, row, tx, and ty one time at initialization and cache those values for future use. You''re only talking about ~100 or so entries, so the table will be small and it should help enough that it warrants the small investment in development time.

Share this post


Link to post
Share on other sites
quote:
Original post by flangazor
Without knowing too much about your design, you could write a gimp script-fu script to enumerate all the strings in your game and make a png for each one. This would be much easier with a string table.

Apart from that, are you sure the text rendering takes the heaviest load when rendering a menu? Have you profiled it? If not, I suggest doing that to make sure you are attacking the correct problem.


Yes, I profiled it The glPrintChar() is the heaviest function when viewing the menu.


quote:
Original post by Palidine
one thing i notice that is definitely slowing you down is that you call this function once for every single character you print to the screen. firstly that's a lot of function overhead but the bigger problem is that you call a glBegin and a glEnd every function call. in general you want to avoid as many glBegin/glEng calls as you can. they are very expensive. a better way to write your program that should save lots of execution time would be to just take out the glBegin and glEnd calls from the function and call the function like this:




That's a very good idea! I feel dumb that I didn't see that myself :$


quote:
Original post by Slickfty2
You may also want to look up display lists. Look up NeHe's tutorial #13. I've used something like that to display fps info and such and it works pretty fast. I can't say for sure if it's faster than rendering it yourself, but it works.


I think it's a lot of work in this case to make a display list, but i'll try. I could make a display list for every character and use the ascii value for the list number.


quote:
Original post by sbennett
NeHe 13 is the way to go here. You create an array of 256 display lists, one for each character, which simply draws a quad with the right portion of the texture on it. Then, when it comes to drawing, you can simply pass your char* straight into glCallLists, and it will draw them all for you.


... I've read your post too late ... that's what I meanth in the post above


quote:
Original post by JonStelly
I would also come up with a way of storing all of the font table lookup values. What you're doing now shouldn't be a ton of overhead, but you could do the computation for column, row, tx, and ty one time at initialization and cache those values for future use. You're only talking about ~100 or so entries, so the table will be small and it should help enough that it warrants the small investment in development time.


As I said (or meanth), I've tried that and it didn't give me any more speed. I also expected it to be a performance boost but it sadly isn't


[edited by - Vich on September 3, 2003 2:51:56 PM]

Share this post


Link to post
Share on other sites
Results:

Moving the glBegin, glEnd and the texture.get functions out of the loop boosted my fps from 404 to 420 when viewing a simple (pretty empty) menu with 1 window with some text in it.

Thanks a lot guys :D it works :D now I''m going to try the display list.

Share this post


Link to post
Share on other sites
Hah! I didn''t expect it but a display list actually makes my code as slow as it was before the previous optimisations! And I figured out why:

A glNewlist() requires every object to be between a glBegin() and glEnd() function to be displayed properly when calling glCallList(). This overhead was first placed out of the loop for optimisations (as you recommended me) and now had to be within that loop again. It''s probably because of that, that the calllist function isn''t fast anymore (for this case).

Thanks for your help, I know that the current optimizations are really good:


void glPrintChar(const int x, const int y, const char input, const int width=16, const int height=16)
{
const int column = input % 16;
const int row = (input-column) >> 4;
const float tx = ((float)column/16.0f);
const float ty = 1.0f - ((float)row/16.0f);
glTexCoord2f(tx,ty);
glVertex2d(x,y);
glTexCoord2f(tx+0.0625f,ty);
glVertex2d(x+width,y);
glTexCoord2f(tx+0.0625f,ty-0.0625f);
glVertex2d(x+width,y+height);
glTexCoord2f(tx,ty-0.0625f);
glVertex2d(x,y+height);
}

void glBmpText(int x, int y, const char *strString, ...)
{
char buffer[128];
va_list errmsg;
va_start (errmsg, strString);
vsprintf (buffer, strString, errmsg);
va_end (errmsg);
string input = buffer;
textureManager.Get(TEXTURE_FONT_MINI);
glBegin(GL_QUADS);
for (int i=0; i<input.size(); i++)
glPrintChar(x+(9*i), y, input);
glEnd();
}


Perhaps there are more ways to optimize?

Share this post


Link to post
Share on other sites