codebytere

#53070: perf: trim GTK and FontConfig work off the linux startup path

Merged
Created: Aug 21, 2026, 3:56:13 AM
Merged: Aug 22, 2026, 1:04:33 AM
5 comments
Target: main

Description of Change

Linux app launch to ready drops ~35 ms and launch to first contentful paint ~55 ms (release build, X11, medians of 25-30 interleaved cold launches per side), from two independent main-thread costs during toolkit initialization. Two commits:

what launch -> app ready launch -> first contentful paint
1 skip GDK's OpenGL probe during gtk_init() 395.7 -> 366.7 ms (-29 ms, p=9e-14) 618.0 -> 573.7 ms (-44 ms)
2 start loading FontConfig before the browser thread pool runs 393.9 -> 388.1 ms (-5.8 ms, p=7e-8) 532.0 -> 520.5 ms (-11.5 ms)

(Row 2 was measured on a lower-variance base than row 1, hence the different absolute numbers; new BrowserWindow and everything after first paint are unchanged in both.)

1. GDK GL probe. When GTK initializes inside ui::GetDefaultLinuxUi(), GDK probes the display for GLX/EGL support (gdk_x11_screen_init_gl -> epoxy -> glXQueryServerString), which dlopen()s the GL driver into the browser process on the main thread. Electron only uses GTK for theme colors (cairo) and native dialogs, none of which touch GdkGLContext, so the probe is pure cost: here it was 27 of the 68 ms between "JS modules loaded" and ready, and the driver mappings also stay resident in the browser for the life of the app. GDK reads GDK_GL exactly once during gtk_init(), so ToolkitInitialized() sets GDK_GL=disable around that call when the user has not set it and removes it again immediately after, before any app code can spawn children. The same change is proposed for Chromium's GtkUi (https://crrev.com/c/8265951); this is the Electron-side form until that lands and covers Electron's own call site either way.

2. FontConfig warm-up. content already tries to initialize FontConfig off the main thread (gfx::InitializeFonts() from BrowserMainRunnerImpl::Initialize()), but that task is posted after BrowserMainLoop raises the ThreadPool execution fence, so it can never run before the toolkit's first font lookup does FcInit + config parsing on the main thread. ElectronMainDelegate::PreBrowserMain() runs after the pool is created and before it is started and fenced, so calling gfx::InitializeGlobalFontConfigAsync() there queues the work to start with the pool and overlap toolkit init; if it ever loses the race it degrades to today's behaviour, and the later content call is a no-op on the NoDestructor singleton. Upstream review of the equivalent content change asked for exactly this placement in the embedder (https://crrev.com/c/8264864).

Both are BUILDFLAG(IS_LINUX) only; macOS and Windows are untouched.

Checklist

Release Notes

Notes: Improved application startup time on Linux by skipping GDK's OpenGL probe and loading FontConfig off the main thread during toolkit initialization.

Backports

42-x-y
Pending
Waiting for a manual backport
43-x-y
Merged
PR Number
#53108
Merged At
Aug 22, 2026, 2:18:48 AM
Released In
Not yet
Release Date
Not yet
44-x-y
Merged
PR Number
#53107
Merged At
Aug 22, 2026, 2:21:00 AM
Released In
Not yet
Release Date
Not yet

Semver Impact

Major
Breaking changes
Minor
New features
Patch
Bug fixes
None
Docs, tests, etc.

Semantic Versioning helps users understand the impact of updates:

  • Major (X.y.z): Breaking changes that may require code modifications
  • Minor (x.Y.z): New features that maintain backward compatibility
  • Patch (x.y.Z): Bug fixes that don't change the API
  • None: Changes that don't affect using facing parts of Electron