Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Text rendering terribly slow

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;
}
like image 939
Piotr Chojnacki Avatar asked Mar 21 '13 10:03

Piotr Chojnacki


1 Answers

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.

like image 144
CJJ Avatar answered Oct 24 '22 23:10

CJJ