mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-25 00:21:46 +00:00
font: support warmup threads
The first CoreText font query in a process initializes the system font database, which takes multiple milliseconds (~7ms measured in an isolated process; 2-4ms observed inside Ghostty startup). This cost was previously paid during the first surface's font grid initialization, on the critical path to the first window. App.create can now spawn a background thread that performs the warmup.
This commit is contained in:
27
src/App.zig
27
src/App.zig
@@ -78,9 +78,36 @@ pub fn create(alloc: Allocator) CreateError!*App {
|
||||
var app = try alloc.create(App);
|
||||
errdefer alloc.destroy(app);
|
||||
try app.init(alloc);
|
||||
|
||||
// Warm up system services on background threads. These are
|
||||
// multi-millisecond one-time costs that would otherwise be paid
|
||||
// during the first surface's initialization. Doing it here overlaps
|
||||
// them with the rest of app startup (config, app runtime, window
|
||||
// creation).
|
||||
threadedWarmup();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// Warm up system services whose first use in a process is slow. Each
|
||||
/// subsystem gets its own background thread so that one slow subsystem
|
||||
/// doesn't delay the others. Only operations that are safe to run on
|
||||
/// any thread belong here.
|
||||
fn threadedWarmup() void {
|
||||
// If font discovery supports warmup, then we call it. Some font
|
||||
// mechanisms (e.g. CoreText) have a multi-millisecond one-time cost
|
||||
// on startup.
|
||||
if (comptime @hasDecl(font.Discover, "warmup")) {
|
||||
if (std.Thread.spawn(
|
||||
.{},
|
||||
font.Discover.warmup,
|
||||
.{},
|
||||
)) |thr| thr.detach() else |err| {
|
||||
log.warn("font warmup thread spawn failed err={}", .{err});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the main app instance. This creates the main window, sets
|
||||
/// up the renderer state, compiles the shaders, etc. This is the primary
|
||||
/// "startup" logic.
|
||||
|
||||
@@ -350,6 +350,22 @@ pub const CoreText = struct {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
/// Warm up the system font registry.
|
||||
///
|
||||
/// The first CoreText query in a process initializes the system font
|
||||
/// database, which takes multiple milliseconds, while subsequent
|
||||
/// queries are microseconds.
|
||||
pub fn warmup() void {
|
||||
const name = macos.foundation.String.createWithBytes(
|
||||
"AppleColorEmoji",
|
||||
.utf8,
|
||||
false,
|
||||
) catch return;
|
||||
defer name.release();
|
||||
const ct_font = macos.text.Font.createWithName(name, 12) catch return;
|
||||
ct_font.release();
|
||||
}
|
||||
|
||||
/// Discover fonts from a descriptor. This returns an iterator that can
|
||||
/// be used to build up the deferred fonts.
|
||||
pub fn discover(self: *const CoreText, alloc: Allocator, desc: Descriptor) !DiscoverIterator {
|
||||
|
||||
Reference in New Issue
Block a user