Managing freetype and cache

Description

Hello all and @kisvegabor @embeddedt

We are using lvgl 7.11 for our Nordic MCU based E-Ink display project. So far we were using default font engine with pre converted font arrays in our code memory. We used regular ASCII range of characters for 8 different sizes. Every worked well but this was not scalable for adding new unicode characters.

Due to this we opted to use freetype library via lv_freetype to render fonts at runtime. This porting was successful but now we are trying to understand and improve performance of this project. We are also using Freetype caching via lv_freetype. Due to limited memory we cant use a bigger cache practically (currently testing with 16KB cache and 40 KB freetype heap).

But now we have hit a roadblock where the performance of the font rendering at worst case takes more than 20 seconds. . We have a custom auto-scaling feature which tries each font sizes one by one (using _lv_txt_get_size function) and then use the best fitting font size for the given text data on our display. The worst case scenario occurs if we try to switch between smallest font and largest font sizes when displaying text. If we stick to only one font size generally the performance is faster and acceptable for us(< 2secs). I think cache misses occur due to different font sizes even though font faces are still available in the cache.

Now coming to my questions,

  1. Is there a standard way to do this font fitting or auto-scaling (pardon my terminology here) than our brute force method? Either in LVGL or Freetype?
  2. Have you faced or known issue like this and how did you solve it? switching between various different font sizes and not able to utilize cache?
  3. Is freetype really best fit for our usecase? does using tinyttf improve our situation? any suggestions here? We want to support CJK and hence we need to use .ttf file for runtime font generation i guess.

Thank you very much for your support.

Regards,
djgj

Hi @djgj,

If I understand correctly, if you could find the correct font size at one try, it would be only 2 sec, which is acceptable. The problem is that sometimes you need try a lot of font sizes while finding the correct one.

Is that correct?

If so, how do you decide which is the correct font size? E.g. do you try to render a letter and get its glyph_dsc?

Hello @kisvegabor ,
Thank you for the reply.
yes, we choose the right font size by rendering text before hand using _lv_txt_get_size and get the size.y compared against screen size (max height). So for example, if we want to show a single character we use the biggest font size that fits our screen size. If we want to show a text of 10 characters then we start from biggest font size and then try smaller font sizes one by one until we find the one that fits the screen.

In the case of our freetype prototype, If the font face and size is in cache already we can usually display the text faster (< 2 secs). If i just use only one font size irrespective of text length without trying to render multiple font sizes then also response time is very fast (<2 secs). But if i initiate a worst case scenario where i try to use biggest font size followed by smallest font size (controlling the text length) then i think lot of cache misses occurs. This then leads to worst response time of more than 20 secs too.

One more information i missed to mention in my post, we use external flash to store *.ttf file. We access font glyphs/infos using lv_freetype and Little FS. However the above font fitting logic was not a problem when we used default LVGL font engine and pre-rendered font arrays in code memory.

Regards,
djgj

I see, thank you for the explanation.

If you need to know the size of a full text, it’s really complicated as you need to know the width of all characters to finally find out the number of lines.

LVGL’s file system support caching for reading, which might greatly speed up the performance of the file system. See here for STDIO. If you create a driver for LittleFS in LVGL you can easily enable the cache too. Aaand, once you create a LittleFS driver, could you contribute it back to LVGL? It seems LittleFS is quite popular so it would be great to have a built in solution for it. :blush:

I’m not a freetype expert but it seems the bitmap is calculated in freetype_get_glyph_dsc_cb. It should be a great speed up, if you could postpone the bitmap drawing to freetype_get_glyph_bitmap_cb.

Tiny_TTF also worth a try. It’s just a single file, so it should be easy to try out.

Please keep us updated on your findings.

Thanks a lot @kisvegabor.
I will check the suggestions you mentioned.
I assume all these will need me to update to latest LVGL 8.x? I did not find them in my current LVGL version 7.11.
Is there also dependency with particular zephyr version if i move to LVGL 8.x?

If your project is not in a super advanced state I recommend updating to v8. Although Tiny_TTF was added only to master (v9 development), it should be straight forward to back port it v8. If you have any issues with it I can also take a look.

Unfortunately, I don’t know. What know that recently the guys at Zephyr updated LVGL to v8.3. But I don’t know which Zephyr version is affected.