Optimization Suggestion for SDL_ttf on long paragraphs

When displaying text with SDL_ttf, the routine becomes rather slow if there are long paragraphs (“long” being more than one page of wrapped text, so about 500 words or something like that). With paragraph I mean one continues block of text without returns. The reason for this is the routine TTF_RenderUTF8_Blended_Wrapped() : when a wrapLength is given, the code will split the given text into lines (= separated by returns/newlines). Each line is then fitted in the given wrapLength, by walking backwards (word by word) in the text until a chunk is found that fits in the given wrapLength. If you have a paragraph with 500 words, of which only 20 fit in the given width, this means that the code will first test 500 words, then 499, then 489 and so on until it reaches word 20, at which point it will draw these 20 words, and then start it all over with 480 words ! For each of these iterations, the whole paragraph dimension is calculated using the function TTF_SizeUTF8(), which will walk over each character from the start, even though it could see that it could stop after 20 words.

With a 800 word lorem-ipsum text, I measured the drawing time to be around one second !

since I am using this function as drawing text input from the user, this means that everytime the user types a character, it takes a second to appear.

usually, users will type enough returns so that the longest paragraphs stay fairly reasonable (less than 50 words) but occasionally I had users that would never type a return… they entered their input in one huge paragraph since they feared that a return would “confirm” their input and stop the dialog box.

there are several possible optimisations :

  • walk forward in each line rather than backward
  • bail out of the function TTF_SizeUTF8 when the wraplength is reached rather than calculating the size of the whole paragraph each time.

I chose to implement the 2nd option since this involves less changes to the underlying algorithm. I just pass an extra parameter called “bail_out_at_width” to TTF_SizeUTF8, and when the width exceeds this param, the function stops. I saw a 4x speed increase this way, which is good enough for my purposes

maybe the SDL_ttf algorithm for wrapped text is in need of an update though :slight_smile:

I think this is a good point, the TTF_Size is called to many times in wrap mode.

There is a start of function doing this: https://bugzilla.libsdl.org/show_bug.cgi?id=4515
It’s modified version of TTF_Size, it tells how many chars can fit into width (eg wrap length).
That would prevent calculating the width many times.

Feel free to provide a patch !
(if so, modify TTF_Size Internal to have a bail out mode, don’t just duplicate the full function).

I fixed that in https://hg.libsdl.org/SDL_ttf/rev/eb1d2358c50c
Indeed it avoids now multiples calls to TTF_Size() functions and very noticeable with large texts.
Can you give a try ?

I will try to incorporate the changes in my project, but I have made a lot of changes myself, mainly because I need text alignment (left/center/right) in TTF_RenderUTF8_Blended_Wrapped()

since my SDL_TTF fork dates from 2016, this is not simple to merge : the whole BUILD_RENDER_LINE() macro was not yet in use at that time :frowning:

I also have, next to wrapLength, a minWidth parameter : the returned surface will have at least that width, even if a given text does not wrap or wraps slightly smaller

Yes, it has changed, you probably need to to fully rewrite your patch.