Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Optimizing dynamic text rendering  (Read 4537 times)

0 Members and 2 Guests are viewing this topic.

red1939

  • Newbie
  • *
  • Posts: 5
    • View Profile
Optimizing dynamic text rendering
« on: January 13, 2013, 05:55:10 pm »
Hello all!

I've been playing around with SFML and I have to say it's a neat little library. For debugging purposes I have several texts rendered on the screen, which (as I checked) quite drastically lowered my FPS. This is not the end of the world, but I would like to ask you several questions regarding this matter and how to make text rendering faster.

Specs
SFML: 2.0 custom built (527bb287a5538f547b5b29c464d22a0ebfa0baa2)
IDE: Visual Studio 2012 Professional
OS: Windows 7 x64
GPU: ATI Radeon HD 4850 (512 GDDR3) + Catalyst 12.4
CPU: Athlon Phenom X2 3.1GHz (2 cores)
RAM: 6GB DDR2

Splitting the loop

This is basically the main part of rendering which takes the most time (82%), while RenderWindow.clear() and RenderWindow.display() takes the rest (~18%).

void render(sf::RenderWindow& rw, const sf::Font& font)
{
        sf::ConcaveShape shape = ...;

        sf::Text t;
        t.setFont(font);

        for ( 100 ) {
                auto pos = ...;
                shape.setPosition(pos);
                rw.draw(shape);
#ifdef DRAW_TEXT
                const auto str = ...;
                t.setString(str);
                t.setPosition(pos);
                rw.draw(t);
#endif // DRAW_TEXT
        }
}
 

Text: 365 fps
No text: 1850 fps (!)

So I decided to check whether splitting the loop into 2 helps.

void render(sf::RenderWindow& rw, const sf::Font& font)
{
        sf::ConcaveShape shape = ...;

        sf::Text t;
        t.setFont(font);

        for ( 100 ) {
                auto pos = ...;
                shape.setPosition(pos);
                rw.draw(shape);
        }

#ifdef DRAW_TEXT
        for ( 100 ) {
                auto pos = ...;
                const auto str = ...;
                t.setString(str);
                t.setPosition(pos);
                rw.draw(t);
        }
#endif // DRAW_TEXT
}
 

Text: 640 fps
No text: 1850 fps

There is a huge (1.75x) increase in performance! I am assuming this is due to the fact that the render state is not swapped back and forth between shape and font?

Profiling

This is what VS2012 profiler shows:

void render(sf::RenderWindow& rw, const sf::Font& font)
{
        sf::ConcaveShape shape = ...;

        sf::Text t;
        t.setFont(font);

        for ( 100 ) {
                auto pos = ...;
                shape.setPosition(pos);
                rw.draw(shape); // 26.7%
        }

#ifdef DRAW_TEXT
        for ( 100 ) {
                auto pos = ...;
                const auto str = ...; // 13%
                t.setString(str); // 34.5%
                t.setPosition(pos);
                rw.draw(t); // 25.3%
        }
#endif // DRAW_TEXT
}
 

Percentage values describe how much of the whole time for this method was taken by the given line.

Optimization

Ok, so the question remains: how can I make it faster?
  • Precreation and caching of all texts (they are not that dynamic) in sf::Texts. It would take a lot of resources I assume.
  • Using bitmap fonts. I am not sure how this could help as the string would still have to be "parsed" and mapped to glyphs.
I would be glad for any other suggestions and comments.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Optimizing dynamic text rendering
« Reply #1 on: January 13, 2013, 06:03:54 pm »
Have you found out why sf::Text::setString() is so slow? Does it mostly need to load new glyphs?

On the other hand, 13% is also remarkable for a string initialisation. What type does the ... expression on the right hand side of const auto str = have?

And if you really only iterate 100 times, this is not an expressive measurement. Use far higher numbers.
« Last Edit: January 13, 2013, 06:05:40 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Optimizing dynamic text rendering
« Reply #2 on: January 13, 2013, 06:48:43 pm »
Quote
There is a huge (1.75x) increase in performance! I am assuming this is due to the fact that the render state is not swapped back and forth between shape and font?
Yes. More precisely, the renderer performs less texture switches.

Quote
how can I make it faster?
Pre-allocating them is the only solution.

Quote
Using bitmap fonts. I am not sure how this could help as the string would still have to be "parsed" and mapped to glyphs.
This is what sf::Text does ;)

Quote
Have you found out why sf::Text::setString() is so slow? Does it mostly need to load new glyphs?
Any modification on a sf::Text reconstructs its internal vertex array.

Quote
Use far higher numbers.
+1!
Laurent Gomila - SFML developer

red1939

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Optimizing dynamic text rendering
« Reply #3 on: January 13, 2013, 11:00:08 pm »
Quote
What type does the ... expression on the right hand side of const auto str = have?

const auto& str = std::to_string(a) + ":"
                                + std::to_string(b) + ":"
                                + std::to_string(c);

Where a, b and c are ints.

Quote
And if you really only iterate 100 times, this is not an expressive measurement. Use far higher numbers.

For 160k iterations the results are slightly different:
Operation% time taken
drawing shape22%
generating string11%
setting string43%
drawing text19%

Quote
Pre-allocating them is the only solution.

Before I play around with some pre-allocation prototype I would like to ask one question: what type memory does the sf::Text require? RAM (the glyph texture is stored in sf::Font), or VRAM (because it creates a texture instance of the mapped glyphs)?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Optimizing dynamic text rendering
« Reply #4 on: January 14, 2013, 07:48:40 am »
sf::Text requires RAM for its vertex array. sf::Font uses VRAM to store the glyph texture, but it doesn't depend on the number of sf::Text instances.
Laurent Gomila - SFML developer

red1939

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Optimizing dynamic text rendering
« Reply #5 on: January 14, 2013, 08:14:58 pm »
So I've implemented the prallocated solution. Results are as follows:

Unique sf::Text objects drawn every update: 160 801
Speed up of using preallocation: 240%
Average memory consumption per sf::Text: 1.261 kB

On one hand we have a nice gain, but I have to say that I am quite surprised because of the amount of memory that sf::Text is taking.

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Optimizing dynamic text rendering
« Reply #6 on: January 14, 2013, 08:22:34 pm »
1 quad(letter) is 80 bytes(4x color + position + tex coords) so it's normal.
Back to C++ gamedev with SFML in May 2023

red1939

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Optimizing dynamic text rendering
« Reply #7 on: January 15, 2013, 12:14:22 am »
1 quad(letter) is 80 bytes(4x color + position + tex coords) so it's normal.

Yeah, I just checked it.

DataSize (B)
Font pointer4
Character size4
Text style4
Color4
Bounds16
Vertex array (not counting underlines etc.)4 * 20 * glyphs
String24 + 4 * glyphs

Which gives us 56 + 84 * glyph, and for 13 character we get whooping 1148B. Hoped it will be less, but I won't cry :).
« Last Edit: January 15, 2013, 12:16:08 am by red1939 »