gpui: Lazy-init font DB in SvgRenderer to avoid per-test overhead (#53381)

Lukas Wirth created

Commit eaf14d028a6c changed SvgRenderer::new() to eagerly deep-clone the
system font database and enrich it with bundled fonts at construction
time. Since every #[gpui::test] creates a TestAppContext →
App::new_app() → SvgRenderer::new(), and nextest runs each test in its
own process, this added ~2-3s of overhead to every GPUI-based test (~132
minutes total across the full suite).

Move the expensive work (deep-clone + load_bundled_fonts +
fix_generic_font_families) into a OnceLock inside the font resolver
closure, so it only executes on the first actual SVG render. Tests that
never render SVGs thus do not need to load the fonts which in itself can
be fairly expensive.

This also bumps the opt-level for crane lift and some other wasmtime
crates, as only wasmtime isn't really sufficient

Release Notes:

- N/A or Added/Fixed/Improved ...

Change summary

Cargo.toml                      |  3 +++
crates/gpui/src/svg_renderer.rs | 26 ++++++++++++++++----------
2 files changed, 19 insertions(+), 10 deletions(-)

Detailed changes

Cargo.toml 🔗

@@ -902,6 +902,9 @@ proc-macro2 = { opt-level = 3 }
 taffy = { opt-level = 3 }
 resvg = { opt-level = 3 }
 wasmtime = { opt-level = 3 }
+cranelift-codegen = { opt-level = 3 }
+wasmtime-environ = { opt-level = 3 }
+wasmtime-internal-cranelift = { opt-level = 3 }
 # Build single-source-file crates with cg=1 as it helps make `cargo build` of a whole workspace a bit faster
 activity_indicator = { codegen-units = 1 }
 assets = { codegen-units = 1 }

crates/gpui/src/svg_renderer.rs 🔗

@@ -7,7 +7,7 @@ use resvg::tiny_skia::Pixmap;
 use smallvec::SmallVec;
 use std::{
     hash::Hash,
-    sync::{Arc, LazyLock},
+    sync::{Arc, LazyLock, OnceLock},
 };
 
 #[cfg(target_os = "macos")]
@@ -111,17 +111,23 @@ impl SvgRenderer {
             Arc::new(db)
         });
 
-        let fontdb = {
-            let mut db = (**SYSTEM_FONT_DB).clone();
-            load_bundled_fonts(&*asset_source, &mut db);
-            fix_generic_font_families(&mut db);
-            Arc::new(db)
-        };
+        // Build the enriched font DB lazily on first SVG render rather than
+        // eagerly at construction time. This avoids the expensive deep-clone
+        // of the system font database for code paths that never render SVGs
+        // (e.g. tests).
+        let enriched_fontdb: Arc<OnceLock<Arc<usvg::fontdb::Database>>> = Arc::new(OnceLock::new());
 
         let default_font_resolver = usvg::FontResolver::default_font_selector();
-        let font_resolver = Box::new(
+        let font_resolver = Box::new({
+            let asset_source = asset_source.clone();
             move |font: &usvg::Font, db: &mut Arc<usvg::fontdb::Database>| {
                 if db.is_empty() {
+                    let fontdb = enriched_fontdb.get_or_init(|| {
+                        let mut db = (**SYSTEM_FONT_DB).clone();
+                        load_bundled_fonts(&*asset_source, &mut db);
+                        fix_generic_font_families(&mut db);
+                        Arc::new(db)
+                    });
                     *db = fontdb.clone();
                 }
                 if let Some(id) = default_font_resolver(font, db) {
@@ -135,8 +141,8 @@ impl SvgRenderer {
                 };
                 db.query(&sans_query)
                     .or_else(|| db.faces().next().map(|f| f.id))
-            },
-        );
+            }
+        });
         let default_fallback_selection = usvg::FontResolver::default_fallback_selector();
         let fallback_selection = Box::new(
             move |ch: char, fonts: &[usvg::fontdb::ID], db: &mut Arc<usvg::fontdb::Database>| {