PoC: introduce packed resources format#596
PoC: introduce packed resources format#596ngxson wants to merge 2 commits intocrosspoint-reader:masterfrom
Conversation
|
@Uri-Tauber I haven't tested the mentioned PR, but it should be pretty understandable why SD card can be slow. Each time you read even a small byte from SD, the program actually does:
It is common knowledge that SD card is not optimized for random read/write. My implementation rely on mmap which is backed by ESP32's MMU, it has the same performance as accessing random data inside the firmware. |
|
@ngxson if I’m not mistaken, #455 implements an LRU (Least Recently Used) cache. Since most books are written in a single language (two at most), we can reasonably assume that — for example, as in real @ruby-builds sets it to 30 — having 128 distinct characters is sufficient to render an entire book. If we assume each character is a 1-bit 16×16 pixel grid, the total cache size would be about 16 KB. On the other hand, while your implementation is more memory-efficient, it makes things harder for the average user who just wants to add their favorite fonts and doesn’t know — and doesn’t want to know — anything about manual flashing. |
I assume you haven't fully read my OP:
|
It's clearly not sufficient at least in my native language, vietnamese. I imagine it will get worse with japanese for example, where the number of grapheme is massive even when compared to chinese edit: hmm, probably a bad example because all vietnamese and japanese usually has a quite high number of repeatedly used grapheme. I guess this only affect chinese |
|
@ngxson Sorry. I missed that. |
|
I'm not very familiar with Chinese, but from a quick search, it looks like there are over 20,000 glyphs just in the CJK Unified Ideographs block of Unicode (U+4E00–U+9FFF). How would your approach handle this? Using two or three fonts could easily fill up the entire flash. |
|
The CJK block covers multiple Asian languages (and even covers obsolete one like Chu Nom). In practice, a human never use the whole CJK, so it will make more sense to separate it by language. In my experience, most memory-constraint system either support chinese+english, japanese+eng combinations, or easten-only language, I never seen one that support both chinese(simplified) and japanese at the same time. But yes this may worth considering. I haven't looked specifically into japanese but I think it can be hard to fit the whole katakana+harigana+kanji into flash, it's basically massive. That can be the only blocking point for my approach edit: in practice, katakana and harigana are pretty small, around 200 graphemes. I've done my research and concluded that ~6000 graphemes are needed to cover japanese's kanji |
|
After some more consideration, I think my approach is not good as-is. While it works on some other memory-constraint devices, it mostly because they don't have access to a sdcard. Serving fonts from sdcard has some performance issues as discussed, but I think it worth the trade-off because we don't usually render too many texts at once anyway. I'm closing this PR as I don't plan to continue it. Will focus my efforts on other parts of the project. |
Summary
Currently, some features like custom fonts cannot be implemented via SD card because the read speed will be quite slow.
This PR introduce packed resources format that is inspired by some STM32 smartwatch / smartband firmwares. One of my past (hobby) work was also based around this idea: https://github.com/ngxson/amazfit-bip-web
Instead of having a fully functional FS like spiffs or littlefs, we simply pack the resources into one big binary, then have a header table to tell where to find the resource.
Memory layout is simple:
The key benefit is that it allows using esp_partition_mmap to read the data, eliminate the need of copying it onto system RAM.
Included in this PR
ResourcesFSresources.binresources.bininto device's flash, then read a file from itThe expected user flow will be:
resources.bin)Alternatively, we can also leverage the web flasher to flash it directly to spiffs partition.
Caveats
The biggest caveat is that the ESP32's MMU only has a limited number of pages to be used for mmap'ing. There are a total of 256 pages (= 16MB), but some are data-only some are instruction-only:
basePtr + 0x1Currently, with the version on
masterbranch, we have (31 app + 31 inst) = 62 pages available (= ~3.9MB, each page is 64KB). This PR uses an addition of 28 data pages, leaving 3 pages left. This is currently hard-coded, but we can modify such that the number of pages can be control more dynamically.Additional Context
Please note that I open this PR mostly for discussion (CC @daveallie )
Demo:
test.txtpython scripts/make_resources.py -o resources.bin test.txt:FONT_REGULARresources.binto SD cardAI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? --> Only for writing python code