From e025a314d1ef5f7620e203d1a95d9bb5a11af41a Mon Sep 17 00:00:00 2001 From: DanS Date: Sat, 10 Oct 2026 09:50:03 -0500 Subject: [PATCH] perf(ui): memoize typography specs on the schema generation Every Typography text, textWrapped and textColored call rebuilt all 15 type specs to read one uppercase flag: 28 ui.toml element lookups, 13 of them copying the element with its string map. With M such labels on screen, that was 28M lookups and 13M copies per frame. The specs are now built once per UI-schema generation, which every ui.toml load, hot reload and skin or theme switch bumps. DPI, font scale and language are not inputs, so nothing else invalidates them. Co-Authored-By: Claude Opus 5.5 --- src/ui/material/typography.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ui/material/typography.cpp b/src/ui/material/typography.cpp index 6b5260b..05222fb 100644 --- a/src/ui/material/typography.cpp +++ b/src/ui/material/typography.cpp @@ -34,13 +34,21 @@ namespace material { const TypeSpec* Typography::getTypeSpecs() { - // Rebuild each call to pick up hot-reloaded values + // Memoized on the schema generation. Every input (typography.* and fonts.*) is read via + // schema::UI().drawElement, and UISchema bumps generation() on each loadFromFile / loadFromString / + // mergeOverlayFromFile (startup, hot-reload, skin/theme switch). ~0u sentinel: generation_ starts at 0, + // so the first call always builds (pre-load defaults), then the first load rebuilds. + // DPI / font scale / language are NOT inputs (kFont*() are raw schema px). UI thread only, as before. static TypeSpec specs[kNumStyles]; + static uint32_t s_builtGen = ~0u; // Helper: read typography entry from UISchema auto& S = schema::UI(); + const uint32_t gen = S.generation(); + if (gen == s_builtGen) return specs; + s_builtGen = gen; auto tspec = [&](const char* key, float defLS, float defLH, bool defUpper) -> TypeSpec { - auto e = S.drawElement("typography", key); + const auto& e = S.drawElement("typography", key); // ref into styleCache_: never let it escape this lambda float ls = e.getFloat("letter-spacing", defLS); float lh = e.getFloat("line-height", defLH); // text-transform stored as extraColors (string map)