perf(l2): cheaper frames -- less overdraw and blending

Measured on the L2 (steady full frames): Settings page 37.7 -> 31.4 ms,
Display 41.5 -> 37.9, Contacts 34.6 -> 32.9, Home 37.3 -> 32.4.

- styleSurface() leaves boxes in the page colour unpainted; styleOpaque()
  for the screen and the status bar, which things slide under.
- group() cards clip their corners only while a row is held
  (rowPressable(), shared by the tappable rows).
- rowSlider(): the track an opaque tint (theme::mix(), also behind
  ACCENT_DIM) instead of 20 % accent blended every frame.
- Map buttons, pills, scale, nav bar and the Home minimap labels opaque.
- Screens drift in without the fading cover: its full-screen blend was in
  every entrance frame (page 39 -> 29 ms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-09-30 14:30:45 +02:00
co-authored by Claude Opus 5.5
parent f29c280c34
commit abbbdc5ae5
8 changed files with 72 additions and 57 deletions
+11 -6
View File
@@ -66,16 +66,21 @@ namespace theme {
};
static const int ACCENT_COUNT = sizeof(ACCENTS) / sizeof(ACCENTS[0]);
static int s_accent = 0;
// `fg` at `pct` % over `bg`, worked out once: an opaque fill in the colour
// a translucent one would blend to, without blending it every frame.
static uint32_t mix(uint32_t fg, uint32_t bg, uint32_t pct) {
uint32_t out = 0;
for (int sh = 0; sh <= 16; sh += 8) {
uint32_t c = (fg >> sh) & 0xFF, b = (bg >> sh) & 0xFF;
out |= ((c * pct + b * (100 - pct)) / 100) << sh;
}
return out;
}
static void setAccent(int idx) {
if (idx < 0 || idx >= ACCENT_COUNT) idx = 0;
s_accent = idx;
ACCENT = ACCENTS[idx].col;
uint32_t dim = 0;
for (int sh = 0; sh <= 16; sh += 8) {
uint32_t c = (ACCENT >> sh) & 0xFF, b = (BG >> sh) & 0xFF;
dim |= ((c * 42 + b * 58) / 100) << sh;
}
ACCENT_DIM = dim;
ACCENT_DIM = mix(ACCENT, BG, 42);
}
// Over LVGL's default theme, for every widget: a checked button is