From 175e80ff47a187540f2e9170d530cff0d9c30ee2 Mon Sep 17 00:00:00 2001 From: phi hu Date: Fri, 26 Jun 2026 18:20:01 +0900 Subject: [PATCH] perf: cache FontMgr + system font enumeration thread-locally in SkiaLayerRenderer::new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SkiaLayerRenderer::new() called FontMgr::default() + collect_system_families() (enumerating every installed font family) on every page. Measured ~8.4 ms/call on macOS — ~15-21% of a page's raster time, and ~3.6 s of pure repeated enumeration on a 426-page export. The system font set is process/thread stable, so compute it once in a thread_local and clone (FontMgr = refcount bump, families = small HashSet clone, ~3 us) into each new(). Font-matching inputs are unchanged, so render output is byte-identical (verified: p13/p9 PNG md5 match baseline). new() drops 8390 us -> 3.0 us. Native-skia render path only (no wasm/NIF impact). 48 skia tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/renderer/skia/renderer.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/renderer/skia/renderer.rs b/src/renderer/skia/renderer.rs index 1b7f66819..0c3e0b3b7 100644 --- a/src/renderer/skia/renderer.rs +++ b/src/renderer/skia/renderer.rs @@ -284,13 +284,23 @@ pub struct SkiaLayerRenderer { impl SkiaLayerRenderer { pub fn new() -> Self { - let font_mgr = FontMgr::default(); - let system_families = collect_system_families(&font_mgr); - Self { - font_mgr, - custom_typefaces: HashMap::new(), - system_families, + // [perf] FontMgr::default() + collect_system_families() (시스템 폰트 family 전수 + // 열거) 는 페이지당 ~8ms 가 드는데, 프로세스(스레드) 내에서 불변이다. 매 렌더마다 + // 재열거하지 않도록 thread-local 로 1회만 계산하고, 이후 new() 는 캐시를 복제 + // (FontMgr = refcount bump, families = HashSet clone ~수십 µs) 해 재사용한다. + // 폰트 매칭 입력이 동일하므로 렌더 출력은 바이트 단위로 불변이다. + thread_local! { + static SKIA_FONT_BASE: (FontMgr, SystemFontFamilies) = { + let font_mgr = FontMgr::default(); + let system_families = collect_system_families(&font_mgr); + (font_mgr, system_families) + }; } + SKIA_FONT_BASE.with(|(font_mgr, system_families)| Self { + font_mgr: font_mgr.clone(), + custom_typefaces: HashMap::new(), + system_families: system_families.clone(), + }) } /// 사용자 지정 폰트 디렉토리 (ttfs 등) 의 폰트를 로드하여 Skia 가 직접 사용 가능하게 한다.