9

I'm using FTGL library to render text in my C++, OpenGL application, but I find it terribly slow, even though it is said to be fast and efficient library for this.

Even for small amounts of text, performance drop is visible, but when I try to render few lines of text, FPS drops from 350~ to 30~:

enter image description here

Yes, I already know that FPS isn't a good way to check efficiency, yet in this case there shouldn't be so big difference.

I found a function which allows me to make FTGL use display lists internally in order to increase speed, but it appears to be turned on by default. Anyway I tried using it, but it gave me nothing. So I thought that maybe it's somehow corrupted, or I don't understand it quite well, so I decided to put rendering text into my own display lists, but difference is either so slight that I can't even see it, or there's no difference.

bool TFontManager::renderWrappedText(font_ptr font, int lineLength, const TPoint& position, const std::string& text) {
    if(font == nullptr) {
        return false;
    }

    string key = sizeToString(font->FaceSize());    // key to look for it in map
    key.append(TUtil::intToString(lineLength));
    key.append(text);
    GLuint displayListId = getDisplayListId(key);   // get display list id from internal map

    if(displayListId != 0) {                        // if display list id was found in map, i can call it
        glCallList(displayListId);
        return true;
    }

    // if id was not found, i'm creating new display list 

    FTSimpleLayout simpleLayout;
    simpleLayout.SetLineLength((float)lineLength);

    simpleLayout.SetFont(font.get());

    displayListId = glGenLists(1);
    glNewList(displayListId, GL_COMPILE);

    glPushMatrix();
    glTranslatef(position.x, position.y, 0.0f);
    simpleLayout.Render(TUtil::stringToWString(text).c_str(), -1, FTPoint(), FTGL::RENDER_FRONT | FTGL::RENDER_BACK);        // according to visual studio's profiler, bottleneck is inside this function. more exactly in drawing textured quads when i looked into FTGL code.
    glPopMatrix();

    glEndList();

    m_textDisplayLists[key] = displayListId;

    glCallList(displayListId);

    return true;
}

I checked with breakpoints in debug mode - it creates display list only once, later it only calls previously created one.

What might be the reason for such slow rendering? How may I speed it up?

Edit: I'm using FTTextureFont (which uses one texture per glyph). According to this FTGL tutorial, I should rather use FTBufferFont, because it uses only one texture per line. Buffer font should be faster, but after I tried it it's uglier and even slower (6 fps whereas texture font gave me 30 fps).

Edit2:

This is how I create my fonts:

font_ptr TFontManager::getFont(const std::string& filename, int size) {
    string fontKey = filename;
    fontKey.append(sizeToString(size));

    FontIter result = fonts.find(fontKey);
    if(result != fonts.end()) {
        return result->second;      // Found font in list
    }

    // If font wasn't found, create a new one and store it in list of fonts

    font_ptr font(new FTTextureFont(filename.c_str()));
    font->UseDisplayList(true);

    if(font->Error()) {
        string message = "Failed to open font";
        message.append(filename);
        TError::showMessage(message);
        return nullptr;
    }

    if(!font->FaceSize(size)) {
        string message = "Failed to set font size";
        TError::showMessage(message);
        return nullptr;
    }

    fonts[fontKey] = font;

    return font;
}

Edit3:

This is function taken from FTGL library source code which renders glyph in FTTextureFont. It uses the same texture for separate glyphs, just with other coordinates, so this shouldn't be a problem.

const FTPoint& FTTextureGlyphImpl::RenderImpl(const FTPoint& pen,
                                              int renderMode)
{
    float dx, dy;

    if(activeTextureID != glTextureID)
    {
        glBindTexture(GL_TEXTURE_2D, (GLuint)glTextureID);
        activeTextureID = glTextureID;
    }

    dx = floor(pen.Xf() + corner.Xf());
    dy = floor(pen.Yf() + corner.Yf());

    glBegin(GL_QUADS);
        glTexCoord2f(uv[0].Xf(), uv[0].Yf());
        glVertex2f(dx, dy);

        glTexCoord2f(uv[0].Xf(), uv[1].Yf());
        glVertex2f(dx, dy - destHeight);

        glTexCoord2f(uv[1].Xf(), uv[1].Yf());
        glVertex2f(dx + destWidth, dy - destHeight);

        glTexCoord2f(uv[1].Xf(), uv[0].Yf());
        glVertex2f(dx + destWidth, dy);
    glEnd();

    return advance;
}
Piotr Chojnacki
  • 6,837
  • 5
  • 34
  • 65
  • you should probably render your text to a texture and only update the texture if the text changes. Of course this won't help if the text changes every frame. – didierc Mar 21 '13 at 10:29
  • @didierc I think that's what FTGL already does. – Piotr Chojnacki Mar 21 '13 at 11:20
  • We use FTGL and `FTTextureFont` and we get good performance. You must be doing something wrong. – Johan Råde Mar 21 '13 at 11:49
  • @user763305 Good to know that someone finds this library efficient. But what could be possibly wrong? I have no idea. I'm doing it everything as it was shown in tutorial. – Piotr Chojnacki Mar 21 '13 at 12:44
  • @user763305 Could you maybe show some of your code which you use for FTGL and post it as an answer? – Piotr Chojnacki Mar 21 '13 at 12:50
  • No, the code is not mine, it belongs to my employer. – Johan Råde Mar 21 '13 at 13:07
  • "*I'm using FTTextureFont (which uses one texture per glyph).*" Somehow, I rather doubt that. And if that's true, then no wonder you're getting poor performance. – Nicol Bolas Mar 21 '13 at 13:52
  • @NicolBolas You mean you doubt that I'm using `FTTextureFont` or that it uses one texture per glyph? This is what is written on FTGL's site, I'll quote: "Texture fonts use one texture per glyph. They are fast because glyphs are stored permanently in the video card's memory." And yet there are people like user763305, who admit that it works fast for them. I'll also include font creation code to my question. – Piotr Chojnacki Mar 21 '13 at 16:12
  • @Mosquito: It should use one *textured quad* per character of output, and individually map via texture coordinates to the right glyph. But the whole font should be packed into a single texture. – Ben Voigt Mar 21 '13 at 16:59
  • @BenVoigt what he said, but i'm assuming that it's just misunderstanding that FTTextureFont doesn't do that, I imagine it does. Loading a file in per glyph doesn't sound logical. I wonder if user763305 can remember if he had any troubles at all and if so, how did he overcome them? – Jimmyt1988 Mar 21 '13 at 17:07
  • @JamesT Yes, I just checked FTGL's code for rendering glyph and it uses the same texture, but with just other coordinates, I add this FTGL's function code to my edited question. – Piotr Chojnacki Mar 21 '13 at 18:36
  • I got about 3000 fps rendering text in FTGL. I'm using `Windows XP 64bit with an old graphics card and OpenGL v2.0`. I think there's something wrong in your code. – mr5 Mar 01 '14 at 06:59

1 Answers1

3

Rendering typography from normal typeface files is a pretty computationally intensive operation. The font glyphs are read as a set of splines that are used to generate character boundaries which are tessellated and fed into the graphics pipeline. I'm not highly familiar with FreeType2 but I have used FTGL. You should be using a FontAtlas to render type. A FontAtlas is a regular texture atlas (much like a sprite sheet) that is rendered once for each font size and then stored for future glyph renders.

Check out this link for more information on the process: http://antongerdelan.net/opengl4/freetypefonts.html

This should greatly improve performance. Although you may lose out on some font-rendering flexibility.

CJJ
  • 358
  • 1
  • 4
  • 12
  • Thank you very much for both answer and link - it seems to be very useful. It's definitely not the answer I wanted to hear, because I really liked FTGL functionality, but seems like I don't have any other option. – Piotr Chojnacki Mar 25 '13 at 06:31
  • the page at that link isn't there anymore. i am interested in this solution. – thang Nov 28 '21 at 11:42