InfiniTimeOrg / InfiniTime

Firmware for Pinetime smartwatch written in C++ and based on FreeRTOS
GNU General Public License v3.0
2.64k stars 904 forks source link

Move analog watch face background into resources #1819

Closed jackwilsdon closed 11 months ago

jackwilsdon commented 11 months ago

This decreases the size of the text section from 409,280 bytes to 394,928 bytes (-14,352 bytes). I've made this a draft PR as currently I am having issues with lv_img_conv crashing in the Docker container when using an indexed color type (specifically CF_INDEXED_2_BIT, which works fine outside of the container). I've opened the PR with the CF_TRUE_COLOR_ALPHA color type for now, but this results in a huge resource (172,804 bytes).

github-actions[bot] commented 11 months ago

Build checks have not completed. Possible reasons for this are:

  1. The checks need to be approved by a maintainer
  2. The branch has conflicts
  3. The firmware build has failed
jackwilsdon commented 11 months ago

It looks like some further optimization might be required here. Moving the background into flash has impacted performance quite considerably:

Before After
A video of swiping between quick settings and analog watch face, loading the background from internal flash A video of swiping between quick settings and analog watch face, loading the background from resources
minacode commented 11 months ago

Do you think we could draw the background with lvgl instead? It's just some lines in a circle, right?

jackwilsdon commented 11 months ago

That's probably a better option. It looks like we'd have to use Canvas for that, which is currently disabled in lv_conf.h. We'd have to see how much code enabling it adds (lv_canvas.c is pretty hefty).

lvgl does have a Line object, but we'd have to create separate instances for each minute (~50 of them), which we probably don't want to do.

jackwilsdon commented 11 months ago

Another option is to implement our own run-length encoding for images (LVGL seems to allow custom image decoders). This would work well for the current background (as it's mostly empty space), but wouldn't work too well for other images.

minacode commented 11 months ago

That's a wild solution for sure! 😄

Maybe it's worth more to have canvases than a random image if the needed space would be comparable.

Also imagine how cool it would look if the background wouldn't be drawn like right now, but instead the lines would appear one after another along the circle in clockwise direction.

JF002 commented 11 months ago

Thanks for your contribution, @jackwilsdon ! The background image for the analog watchface is indeed quite big, but, as you've already noticed, finding a solution to reduce the size or move it to the external memory is not that easy. I would be very happy if we could find one, though!

So yes, just moving the image to the external resources makes the rendering of the watch face very slow : the SPI bus is limited to 8MHz and is shared between the display and the flash memory.

I don't think using RLE is an option here : LVGL needs to be able to access the image in a random fashion to refresh only parts of the frame. With RLE, you would need to read and "uncompress" the whole picture even if only a part of it is needed.

Last time I checked, LVGL canvas was not an option either : canvas needs to allocate the memory corresponding to the size of the canvas. In this case, you would need 2402402 = 115200B in RAM memory, which is not possible on the PineTime (it only has 64KB of RAM).

But hey! Don't give up! You might be able to find a nice solution, and it would be very beneficial to InfiniTime if you manage to free a few kB in the internal flash memory!

minacode commented 11 months ago

Maybe you can build a clock from a gauge?